I have a jQuery dialog popup form shown within an iframe on Yii. If the form validates, it needs to save and close, otherwise it needs to show with the errors. However, while the validateOnChange is working, the validateOnSubmit doesn't - clicking on submit just returns the output of the view, instead of the errors (or an empty array). I'm not really sure where to start with fixing it.
I have these options in the beginWidget() call:
'enableAjaxValidation'=>true,
'clientOptions' => array(
'validateOnSubmit'=>true,
'validateOnChange'=>true,
'validateOnType'=>false,
),
And I am using this code to generate the button:
CHtml::ajaxSubmitButton('Submit', 'enter', array('success' => 'afterValidate()'));
I found a couple of other links talking about the problem of these two options not working together at: Yii ajaxSubmitButton() with fields validation and
http://code.google.com/p/yii/issues/detail?id=2008. However, I'm not sure what to do with the suggested fix in the last link:
function afterValidate(form, data, hasError){
if (!hasError) {
$.ajax({
url: '{$postUrl}',
type: 'POST',
dataType: 'json',
data:jQuery(this).parents("form").serialize()
})
.done(function ( response ) {
// my successhandler
})
.fail(function ( xhr, status ) {
// my error handler
});
return false;
}
}
The callback function is being called, but always fails, whether the data is valid or not.
So, how do I implement a jQuery dialog form in Yii?
Related
I have some problems with my ajax call, I have a collection group and when I click on show link it should show me the collection's tasks.The problem is when I try to create new tasks for the current collection.I made 50% of the problem, because it creates the records in database, but something strange happen.
Form is already submitted even If I do not click the create button
After ajax call, it creates the records in database, but it does not append the newly created element, it shows me this:
Ajax call response
Here is my ajax script:
$(document).ready(function() {
// store task
$('#create-task').click(function (event) {
event.preventDefault();
$.ajax({
type: 'post',
dataType: 'json',
data: $('#create-task-form').serialize(),
success: function (data) {
$('#create-task-form').trigger('reset');
$('#createTaskModal').modal('hide');
$('.collections').append('<li>' + data.name + '</li>');
}
});
});
});
I did not set the url, because when I do that it shows me something like this, and I do not know why.
Duplicate collection/collection/id
Set the url
Routes:
// Collection routes
Route::prefix('collections')->middleware('auth')->group(function() {
Route::get('/', 'CollectionController#index')->name('collections.index');
Route::post('/', 'CollectionController#store')->name('collections.store');
Route::get('/{collection}', 'CollectionController#show')->name('collections.show');
Route::get('/{collection?}/edit', 'CollectionController#edit')->name('collections.edit');
Route::patch('/{collection?}', 'CollectionController#update')->name('collections.update');
Route::delete('/{collection?}', 'CollectionController#destroy')->name('collections.destroy');
Route::post('/{collection?}', 'CollectionController#storeTask')->name('tasks.store');
});
Controller
public function storeTask(Request $request)
{
$attributes = $request->validate([
'name' => 'required|min:3',
'description' => 'nullable|min:3',
'status' => 'required',
'due' => 'nullable|date'
]);
$attributes['collection_id'] = $request->collection;
$task = Task::create($attributes);
return Response::json($task);
}
PS: I can still create records, even the validation from back-end fails!
Based on your image your routing is wrong.
You get a 404 for trying to access collections/collections twice leading to a non existing URL of course.
A solution to this would be:
url: {{ url('/collections/25') }},
I'm using Laravel 5.2. On my index page, I've got a button to add a new entry, which brings up the form in a lightbox. This form then submits via the create method.
I also have each entry listed on this page, with the ability to edit them inline, which submits via the update method.
I've setup validation via a Request. This means when someone misses something on the add, it redirects to the index method with errors. The errors only show though, when the lightbox is triggered by the user.
I know I can use $errors to see any errors, but I don't see how I can differentiate between the create and update forms for the sake of forcing the lightbox to appear on reload with create errors. Is there a way to do that?
Update:
Suggestion was made to use AJAX to bypass the reload issue, but now I'm getting a 422 return:
AJAX call:
(function(){
var submitAjaxRequest = function(e){
var form = $(this);
var method = form.find('input[name="_method"]').val() || 'POST';
$.ajax({
type: method,
url: form.prop('action'),
data: form.serialize(),
success: function(data){
console.log(data)
}
});
e.preventDefault();
}
$('form[data-remote]').on('submit', submitAjaxRequest);
})();
Request:
public function response(array $errors)
{
$response = parent::response($errors);
if ($this->ajax() || $this->wantsJson()) {
return $response;
}
return $response->with('requestMethod', $this->method());
}
I've also tested the ajax call and it works fine when the validation rules are met. It only fails if the validation comes back with something incorrect in the input.
You could override the response method so that you can flash the type of request.
In you Request class you could add
public function response(array $errors)
{
$response = parent::response($errors);
if ($this->ajax() || $this->wantsJson()) {
return $response;
}
return $response->with('requestMethod', $this->method());
}
(With ajax you wouldn't need to worry about the page reload so we can just return the original response.)
In the above I'm assuming you're using POST for your create methods and PUT or PATH for your update methods. If this is not the case you could use a way that make sense to you to differentiate between the requests.
Then in your view you could do something like:
#if(session('requestMethod') == 'POST')
https://laravel.com/docs/5.2/responses#redirecting-with-flashed-session-data
If you are going to use ajax, as I mentioned in the comment above, you will need to make sure you use the error method within the ajax call:
$.ajax({
type: method,
url: form.prop('action'),
data: form.serialize(),
success: function (data) {
console.log('success', data)
},
error: function (data) {
console.log('error', data)
}
});
Hope this helps!
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']);
}
});
I have an AJAX script that should insert data into a mysql database when users are logged in. However it is currently running the success function, even when 'success' => 'false' is returned in the console.
Her is my code
$(document).ready(function() {
$("#addfav").click(function() {
var form_data = {heading: $("#vidheading").text(), embed : $("#vidembed").text()};
jQuery.ajax({
type:"POST",
url:"http://localhost/stumble/Site/add_to_fav",
dataType: "json",
data: form_data,
success: function (data){
alert("This Video Has Been Added To Your Favourites");
console.log(data.status);
},
error: function (data){
if(data.success == false){
alert("You Must Be Logged In to Do That");
console.log(data.status);
};
}
});
})
})
here is the php, bear in mind my project is in codeigniter.
public function add_to_fav(){
header('Content-Type: application/json');
$this->load->model('model_users');
$this->model_users->add_favs();
}
and this is the actual model for adding data to db
public function add_favs(){
if($this->session->userdata('username')){
$data = array(
'username' => $this->session->userdata('username'),
'title' => $this->input->post('heading'),
'embed' => $this->input->post('embed')
);
$query = $this->db->insert('fav_videos',$data);
echo json_encode(array('success'=>'true'));
} else {
echo json_encode(array('success'=>'false'));
}
}
Thank you for any suggestions!
You aren't returning an error.
You are returning a 200 OK with the data {"success": "false"}.
You can either handle that in your jQuery success function or send a different status code (it looks like a 403 error would fit here).
You have to remember error that occurs for asynchronous requests and errors that occur for PHP backend are different. Your error occurs at PHP-level, and PHP returns valid HTML as far as the javascript frontend is concerned. You need to check if the "success" variable in the returned JSON is true.
I have a php script that takes some user form input and packs some files into a zip based on that input. The problem is that sometimes the server errors, so all the form data is lost. I was told I could use ajax instead so that the user never even has to change the page. I've never used ajax, and looking at http://api.jquery.com/jQuery.ajax/ without any experience in ajax is quite difficult.
The page says that you can accept returns from an ajax call. How do you set up returns in the PHP file for an ajax call? If the server errors with the ajax call, how will I know?
edit: Also, is there a way to send an ajax request with javascript and jquery as if it were a submitted form?
How do you set up returns in the PHP file
just echo it in ajax page that will return as response
Simple Tutorial
client.php
$.post('server.php',({parm:"1"}) function(data) {
$('.result').html(data);
});
server.php
<?php
echo $_POST['parm'];
?>
result will be 1
edit on OP comments
Is there a way to use ajax as if you were submitting a form
Yes, there is
You can use plugins like jQuery form
Using submit
If you using jquery validation plugin, you can use submit handler option
using sumit
$('#form').submit(function() {
//your ajax call
return false;
});
every ajax function has a function param to deal with server returns.and most of them has the param msg,that is the message from server.
server pages for example php pages you can just use echo something to return the infomation to the ajax funciton . below is an example
$.ajax({
url:yoururl,
type:post,
data:yourdata,
success:function(msg){
//here is the function dealing with infomation form server.
}
});
The easiest way to get information from PHP to JavaScript via AJAX is to encode any PHP data as JSON using json_encode().
Here's a brief example, assuming your server errors are catchable
<?php
try {
// process $_POST data
// zip files, etc
echo json_encode(array('status' => true));
} catch (Exception $e) {
$data = array(
'status' => false,
'message' => $e->getMessage()
);
echo json_encode($data);
}
Then, your jQuery code might look something like this
$('form').submit(function() {
var data = $(this).serialize();
$.ajax(this.action, {
data: data,
type: 'POST',
dataType: 'json',
success: function(data, textStatus, jqXHR) {
if (!data.status) {
alert(data.message);
return;
}
// otherwise, everything worked ok
},
error: error(jqXHR, textStatus, errorThrown) {
// handle HTTP errors here
}
});
return false;
});