how to get json encode from render function in symfony2 - php

I'm trying to work with ajax in symfony but is some hard for me. I have a form in twig where I get a value that I'm using for search a product in my database:
This is the form in twig:
<form id="myForm" method="post" action="{{ path('my_app_greeting') }}">
<div class="input-group">
<input id="name_id" name="name" type="text" class="form-control" placeholder="Buscar repuesto..." required />
<span class="input-group-btn">
<button id="search-button" class="btn btn-default" type="button">Buscar</button>
</span>
</div><!-- /input-group --></br>
</form>
This is my code using jquery in the same twig template for send the data with ajax:
$(document).ready(function(){
$("#myForm").submit(function(){
var value = $("#name_id").val();
$.ajax({
type: "POST",
data: { productValue: value },
url: "/ventas/test/ajax/"
})
.done(function(response){
template = response;
$('#output').html(template.content);
})
.fail(function(jqXHR, textStatus, errorThrown){
alert('Error : ' + errorThrown);
});
return false;
});
});
Later I read about how symfony works with ajax and I thought the best solution for my "problem" is create a new twig template called "ajaxContent.html.twig" for example and do this with the controller:
public function testAction()
{
$request = $this->get('request');
$name = $request->request->get('productValue');
$template = $this->renderView('AcmeDemoTwoBundle:Ventas:ajaxContent.html.twig', array('value' => $name));
$json = json_encode($template);
$response = new Response($json, 200);
$response->headers->set('Content-Type', 'application/json');
return new Response($response);
}
Of this way later I want to put all the html content inside my original template but I have a problem with json encode. I don't understand very well how it works and how is the better way for receive the data and show it in the twig template. How can I do this? ( I tried to show the data using $('#output').html(template.content); but doesn't work).
Thanks for your help!

Your code in controller seems to be not good.
I mean if you want to return json then what for do you render html (not json) twig template? That's the first.
Then you can get json response by using JsonResponse instead of setting header for standard response.
I don't know what's happening in ajaxContent.html.twig, but I would do something like this:
public function testAction(Request $request)
{
$name = $request->get('productValue');
$response = $this->get('my_response_sercive')->giveMeResponseForTestAction($name);
return new JsonResponse($response);
}
If you are waiting for html response in you javascript you have to set option dataType: 'html' for your ajax request.
Then in testAction you don't have to set 'application/json' header and don't have to json_encode $template variable - but just render your template as you are doing it now.
So in this case you could do something like this:
public function testAction(Request $request)
{
$name = $request->get('productValue');
return $this->renderView('AcmeDemoTwoBundle:Ventas:ajaxContent.html.twig', array('value' => $name));
}
After that you can put html into your #output block directly:
$('#output').html(response);

You should use form array first for your problem try this
$template['content']

Related

Pass parameters to a controller from the View by using ajax and controller pass the new eloquent to the view

This is how my Controller and View work
Controller
class DayhomeController extend Controller{
public function index(){
$Dataset = Modal::all();
return view('DayHome')->with('DataSet',$DataSet)
}
View
<div class="container" id="container1">
<input type="date" id="datepicker" name="datepicker" value="<?php echo date('Y-m-d'); ?>"
</div>
#for ($i = 0; $i < count($DataSet); $i++)
<div class="container" id="container2">
<div> {{$DataSet[$i]->name}} </div>
<div> {{$DataSet[$i]->number}} </div>
</div>
#endfor
<script type="text/javascript">
$('#datepicker').on('change', function() {
var datepicker = $('#datepicker').val();
alert(datepicker);
$.ajax({
url: '/orderdata',
data: datepicker,
type: "get",
cache: false,
success: function () {
$('#something').empty();
$('#something').append();
},
error: function () {
;}});});
</script>
Route
Route::get('/orderdata', 'DayhomeController#OrderDataorIndex');
1.I would like to ask if I use ajax to pass the datepicker value to the controller, should I pass it to the index or create another public function OrderData($Request $datepickerVal){} ? because I need to use the value of the datepicker as a condition to retrieve the modal update Dataset[i] again.
2.The data enters function index or function OrderData, and finally returns a new dataset[], will this help me refresh the page, or should I do something like $('#something').empty $('#something').append() in ajax success:function to update my object and its {{$DataSet[$i]->name}} {{$DataSet[$i]->number}} number?
You have 3 ways to accomplish this
Page reload
Reload the page and send query string in the url eg: "/yourpath?date=" + $date, then in your controller:
window.location.href = 'https://your.url/path?date=' + $('#datepicker').val();
class DayhomeController extend Controller{
public function index(){
$Dataset = Modal::all();
if(request()->get('date')){
$Dataset = $Dataset->where('date',request()->get('date'))
}
return view('DayHome')->with('DataSet',$DataSet)
}
Ajax return HTML
you could make a controller+page/view that only returns the HTML of your rendered data set.
then you can call this route/controller and just replace the html with jQuery:
$.ajax({
url: '/orderdata',
data: datepicker,
type: "get",
cache: false,
success: function (htmlReceived) {
$('#something').html(htmlReceived);
},
});})
Ajax + javascript rendiner library
you could also always get the Data set via ajax and instead create your render method locally using, react, alpineJS, svelte, vue or any other frontend rendering library or framework
*** This code does not follow best practises but tries to explain your problem

Is there a way to send/pass ajax response with normal variable to views?

As you can see the js and html code below are in the same page. When I press the button, ajax will return Item json. My goal is to know whether it is possible to return the json response with the $item variable at the same time in test function. This is because I wanted to use the $item variable in view blade. If so, then how to do it?
Controller
public function index()
{
$furniture = Furniture::all();
return view('index', compact('furniture'));
}
public function test(Request $request)
{
$item = Item::findOrFail($request->item_id);
return response()->json([
'data' => [
'success' => $item,
'key1' => "hello",
'key2' => "world",
]
]);
}
JS
$(document).on('click', '.edit_modal', function() {
var item_id = this.id;
$.ajax({
type: 'POST',
url: "{{ URL::route('test') }}",
headers: {'X-CSRF-TOKEN': '{{ csrf_token() }}' },
data: { "item_id" : item_id},
success: function(data){
if(data.data.success){
$('#edit_id').val(data.data.success.id); // this will output the id eg. 1
$('#edit_desc').val(data.data.success.description); // this will output the description eg. "hi there"
console.log(data.data.key1); // this will output "hello"
console.log(data.data.key2); // this will output "world"
}
}
});
View
<button type="button" class="edit_modal btn btn-primary" id="{{ $furniture->item_id }}">Button</button>
Blade views are rendered server side. The rendering has completed by the time the view is displayed on your browser.
When you run an AJAX request, there is no further rendering in the current view (by Blade or PHP). Therefore, you cannot pass additional variables through AJAX to the blade template.
If you really want this functionality, it seems strange that you are using AJAX to begin with. You should just submit the form normally and render a new view from the server side with the $item passed to that view. When using AJAX, you'll want to return a response Javascript can understand (JSON), not that PHP can understand, since Javascript will be rendering the response on the client side.
Read more about the difference between server side and client side programming here: What is the difference between client-side and server-side programming?

Link to a specific part of a page

I have a div that has lots of posts which is created dynamically from the database. The div has input for comment facility as well. I have no problems in posting the comments and I do it using a POST method. Then I redirect to the page using return redirect('/'); method. But it links to the beginning to the page which doesn't create a good impression on the user. The user might be in the middle of the page and when he/she comments he will go to the beginning of the page and will have to scroll down again. Luckily, I have the divs with class equal to the post_id. So, isn't there any method to go to the post in which the user posted using that class?
attach the id with the url like /#post-id
Inside your contorller where you are processing and saving the comments:
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\URL;
public function yourCommentSaveFunction()
{
...
//Get the Post ID and store in $postid
return Redirect::to(URL::previous() . '#' .$postid);
}
This should work fine.
But the best way would be to use AJAX to post comments.
Edit (As request by OP)
THE AJAX METHOD
Controller will be something like:
public function saveComment(Request $request)
{
//you do the saving part..
...
$comment = $request->comment;
//after saving the comment return a json response
//you can also send other varibales like username, created at etc..
return Response::json(array(
'success' => true,
'comment' => $comment,
));
}
Route:
Route::post('/save-comment', [
'as' => 'save-comment',
'uses' => 'yourController#saveComment',
]);
And your View:
<form action="{{ route('save-comment') }}" class="comment-form">
<input type="text" name="comment">
<input type="submit" name="submit">
<input type="hidden" name="_token" value="{{ csrf_token() }}"
<div class="comment"></div>
</form>
<script>
$('.comment-form').submit(function(event){
event.preventDefault();
var comment = $this.val();
var token = $('.token').val();
var $url = "{{ route('save-comment') }}";
$.ajax({
url: route,
type: 'POST',
data: {_token: token, comment: comment},
dataType: 'JSON',
success: function (data) {
$(".comment").append('<div class="new-comment">' +data.comment +'</div>');
},
error: function(data) {
console.log("Something went wrong");
}
});
});
</script>
Please note: this is just a sample code.

Why can't I get form inputs using ajax and laravel

I'm trying to parse the data that I send from my ajax form. But for some reason I cannot extract the information from the form in the php controller. Here's what I'm doing.
Here is the html:
<div style="margin-top: 100px;">
<h2>Character settings</h2>
<table class="table table-striped table-bordered table-hover">
<tr>
<th>Name</th>
<th>Map</th>
<th>Move</th>
</tr>
#foreach($chars as $char)
<tr>
<td>{{$char['name']}}</td>
<td>{{$char['map']}}</td>
<td>
{{Form::open(array('action' => 'UsersController#move', 'class' => 'mover'))}}
<input type="hidden" name="charID" class="charID" value="{{$char['id']}}" />
<button type="submit" class="btn btn-small btn-info">Move</button>
{{Form::close()}}
</td>
</tr>
#endforeach
</table>
Here is the javascript ajax processing:
$('#mover').on('submit', function(e){
e.preventDefault();
var $form = $( this ),
method = $form.attr( "method" );
$.ajax({
url: "{{action('UsersController#move')}}",
dataType: "json",
data: $form.find('.charID').val(),
type: method,
success: function (response) {
console.log(reponse['test']);
}
});
});
Here is the controller:
public function move() {
if(Auth::check()) {
Log::info(Input::get('charID')); //When I check the logs this is blank
$person = Character::where('id', '=', Input::get('charID'))->first();
$person->map = 100000000;
$person->save();
$response = array('status' => 'success', 'text' => 'Your character has been moved!');
return Response::json($response);
exit();
}
else {
return Redirect::action('PageController#showHome');
}
}
When I check the console log on submit I see the data "charID", so its being extracted by the form correctly, but I can't seem to get it in the laravel controller. Strange thing is I use the Input::get() function in other parts of my controller. So it's just this function.
Any help appreciated!
You're accessing response[test] instead of response[text].
Other things of note:
Your use of exit(); is redundant and will never be hit because you are returning above it.
Also, exit is a language construct and it can be called without parens if no status is passed. So if you are to use it without an argument, just use exit;.
Your ajax method could be optimised a bit more and it seems you also have another problem with your data, which needs to be sent as a key value pair.
You could do it as an inline string in the form of a GET request, or as an object like { "charID": $(this).find("input[name=charID]").val() },.
$("#mover").on("submit", function (e) {
e.preventDefault();
$.ajax({
"url": this.action, // <-- we can use native javascript
"dataType": "json",
"data": $(this).serialize(), // <-- collects your form data
"type": this.method,
"success": function (data) {
if (data.success !== "undefined" && data.success === 200) {
console.log(data.text);
}
}
});
});
I would recommend against using the Form helper class. It isn't very readable after-the-fact. You don't save that much time using it compared to writing out the HTML form definition anyway.
Let's optimise your controller so it's easier to understand as well:
public function move ()
{
if (Auth::check()) {
Log::info(($charID = request('charID')));
$person = Character::where('id', '=', $charID)->first();
$person->map = 100000000;
$person->save();
return response()->json([
'success' => 200, // success
'text' => 'Your character has been moved!'
]);
} else {
return response()->json([
'success' => 401 // unauthorised
]);
}
}
For a variable you're accessing more than once, I use a neat trick with parens (). If you wrap an assignment in parens e.g. ($charID = request('charID')) you can still use it's output in-line, with the added benefit that you now have access to it further into your script.
I'm opting for the helper methods like request() and redirect() instead of their class counterparts and the use of array() is a bit old hat - but that's just my opinion - I'd use square brackets [].
Your response when the user isn't authenticated is useless here assuming this controller action is only meant to handle posts from AJAX requests (if I'm not mistaken). Since it can't force your asynchronous request to redirect you. Instead we return the proper HTTP response code 401 to represent that the user was unauthorised.
You could also look up PSR-2 standards for your code structure, as that is what is used as an industry standard nowadays.
Lastly, if you are using the web middleware (with CSRF protection) on the controller here. You need to send a CSRF token with the request. You can do that by popping {{ csrf_field() }} into the form. The form helper may be doing this for you.
But another problem you would have stumbled into if you were not using $(this).serialize() in the AJAX setup is that the _token field would never have been sent along with the request.
Try
data: { 'charID': $form.find('.charID').val() },
as it is now you're only sending the value, there's no way PHP let alone Laravel will know its name
I see a few potential issues with this code.
You're initializing your form with 'class' => 'mover', but your jquery is looking for $('#mover') - So your form tag has the class 'mover' but your jquery expects an id 'mover'
You're setting the ajax method to $form.attr( "method" ); but I'm not sure if method is getting set at all in your form tag? Why not just set your ajax type/method to POST since that's the appropriate method for posting a form?
try to change as below,
$.ajax({
url: "{{action('UsersController#move')}}",
dataType: "json",
data: $form.serialize(),
type: 'post',
success: function (response) {
console.log(reponse['test']);
}
});

500 internal server error while posting data to database with laravel 5 and ajax

Hi guys? am trying to post data to the database using laravel 5 and ajax..am also applying using csrf protection by adding
<meta name="_token" content="{!! csrf_token() !!}"/>
to my layout header and adding the following code to my footer:
<script type="text/javascript">
$.ajaxSetup({
headers: { 'X-CSRF-Token' : $('meta[name=_token]').attr('content') }
});
</script>
This is my form:
<form action="{{action('QuizController#postQuiz')}}" method="POST">
<div id="name-group" class="form-group">
<label for="name">Please type your question here</label>
<input type="text" class="form-control" name="question">
</div>
<button type="submit" class="btn btn-success">Submit <span class="fa fa-arrow-right"></span></button>
</form>
This is my JS code:
var formData = {
'question' : $('input[name=question]').val(),
};
// process the form
$.ajax({
type : 'POST',
url : 'quiz',
data : formData,
dataType : 'json',
encode : true
})
// using the done promise callback
.done(function(data) {
// log data to the console to see
console.log(data);
// ALL GOOD! just show the success message!
$('form').append('<div class="alert alert-success">' + data.message + '</div>');
// stop the form from submitting the normal way and refreshing the page
event.preventDefault();
This is my route:
Route::post('create/quiz', array(
'as' => 'post-quiz',
'uses' => 'QuizController#postQuiz'
));
When my controller is like the following:
public function postQuiz()
{
if(Request::ajax()) {
$question = Request::get('question');
$data['success'] = true;
$data['message'] = $question;
echo json_encode($data);
}
the ajax call works and it returns,
Object {success: true, message: "test question"}
but when I try posting data to the database using:
public function postQuiz()
{
if(Request::ajax()) {
$question = Request::get('question');
DB::table('questions')->insert([
'question' => $question,
]);
}
I get the following from the console
POST http://localhost/leoschool-laravel5/public/create/quiz 500 (Internal Server Error)
and
Object {readyState: 4, responseText: "{"success":true,"message":"test question"}<!DOCTYPE htm…l>↵</div>↵↵ </div>↵ </body>↵</html>", status: 500, statusText: "Internal Server Error"}
What could be the problem? Thanks..
A good place to start is with Chrome Developer tools. Load your page with the tools open and fire the event that does the AJAX request.
Under the network tab of the tools, it will show you every request made and allow you to preview the response as if you were not using AJAX. This will show you the laravel stack trace. I think the problem is that you're using facades and they're not namespaced correctly.
Change your controller function to this and see if it works:
public function postQuiz()
{
if(\Request::ajax()) {
$question = \Request::get('question');
\DB::table('questions')->insert([
'question' => $question,
]);
}
With the above instruction on how to use dev tools and with the corrected code, you should be able to fix your problem. A better way to write this code would look like this though:
// assuming you have these models setup
// this uses dependency injection
public function postQuiz(Request $request, Question $question)
{
if($request->ajax()) {
$newQuestion = $request->get('question');
//add fields here to create new question with
$question->create([ /*stuff*/ ]);
}

Categories