
yii - issue #2008
validateOnSubmit does not work with ajaxSubmitButton on the form, while it should work
What steps will reproduce the problem? 1. I implemented standart feedback form with CActiveForm according to documentation: <?php $form=$this->beginWidget('CActiveForm', array( 'id' => 'feedback-form', 'enableAjaxValidation' => true, 'clientOptions' => array( 'validateOnSubmit' => true, ), )); ?> <p class="note">Fields marked with <span class="required">*</span> are required.</p>
<?php echo $form->errorSummary($model); ?>
<div class="row">
<?php echo $form->labelEx($model,'email'); ?>
<?php echo $form->textField($model,'email',array('size'=>60,'maxlength'=>254)); ?>
<?php echo $form->error($model,'email'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'name'); ?>
<?php echo $form->textField($model,'name',array('size'=>60,'maxlength'=>254)); ?>
<?php echo $form->error($model,'name'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'message'); ?>
<?php echo $form->textArea($model,'message',array('rows'=>6, 'cols'=>50)); ?>
<?php echo $form->error($model,'message'); ?>
</div>
<div class="row buttons">
<?php echo CHtml::ajaxSubmitButton('Send', '', array('type' => 'POST')?>
</div>
<?php $this->endWidget(); ?>
2. I presse Submit button. And what I get is described below
What is the expected output? What do you see instead? When I click submit in this case I expect ajax validation call first and then, if no errors call ajax submit. Instead ajax submit happens with no ajax validation before that (according to documentation this shouldn't act like that. Documentation says "validateOnSubmit: boolean, whether to perform AJAX validation when the form is being submitted. If there are any validation errors, the form submission will be stopped.")
What version of the product are you using? On what operating system? I am using yii 1.1.6 on windows
Please provide any additional information below. I figured out the reason of the problem, but unfortunately I have no time to understand how to fix it and proved a patch. See my investigation below.
- If I replace CHtml::ajaxSubmitButton('Send', '', array('type' => 'POST')?> with CHtml::submitButton('Send', '', array('type' => 'POST')?> then I get correct ajax validation before submitting and only if no errors the submit occurs (but in this case the submit is not via ajax, thus it is not suitable for me)
- I tried to figure out the reasion and here it is. ajaxSubmitButton delegates onclick event to the button. And this event does not allow to execute form.submit event (which assigned in yiiactiveform.js in validateOnSubmit section)
Comment #1
Posted on Jan 18, 2011 by Quick OxTo explain the reasons of the problem better, here the pieces of code:
- This code is generated in the bottom of the page, when we use submitButton: jQuery(function($) { $('#feedback-form').yiiactiveform({ 'validateOnSubmit':true, 'attributes':[ {'inputID':'Feedback_email','errorID':'Feedback_email_em_','model':'Feedback','name':'email'}, {'inputID':'Feedback_name','errorID':'Feedback_name_em_','model':'Feedback','name':'name'}, {'inputID':'Feedback_message','errorID':'Feedback_message_em_','model':'Feedback','name':'message'}],'summaryID':'feedback-form_es_' }); });
And this is generated by ajaxSubmitButton: jQuery(function($) { jQuery('body').delegate('#yt0','click',function(){ jQuery.ajax( {'type':'POST','success':feedbackSuccess,'url':'/company/feedback','cache':false,'data':jQuery(this).parents("form").serialize()} ); return false; }); $('#feedback-form').yiiactiveform({ 'validateOnSubmit':true, 'attributes':[ {'inputID':'Feedback_email','errorID':'Feedback_email_em_','model':'Feedback','name':'email'}, {'inputID':'Feedback_name','errorID':'Feedback_name_em_','model':'Feedback','name':'name'}, {'inputID':'Feedback_message','errorID':'Feedback_message_em_','model':'Feedback','name':'message'}],'summaryID':'feedback-form_es_' }); });
So, jQuery('body').delegate('#yt0','click',function(){...}); is called before form.submit and suppresses it, so the fields are not validated. Ajax validation is implemented in yiiactiveform.js at the following piece of code: if (settings.validateOnSubmit) { $form.find(':submit').live('mouseup keyup',function(){ $form.data('submitObject',$(this)); }); var validated = false; $form.submit(function(){...});
So, I suppose ajaxSubmitButton should be re-designed somehow to make on-submit validation for the ActiveForm work fine.
Comment #2
Posted on Jan 18, 2011 by Quick OxI made some studing for this problem. To solve it we can do the following: 1. In jQuery('body').delegate('#yt0','click',function(){...}); do the check whether yiiactiveform exists or not and whether the button clicked is inside this activeform 2. Add validation like that: var $form = $('#feedback-form'); window.jQuery.fn.yiiactiveform.validate($form, function(data){ var hasError = false; $.each($.fn.yiiactiveform.getSettings($form).attributes, function(i, attribute){ hasError = $.fn.yiiactiveform.updateInput(attribute, data, $form) || hasError; }); $.fn.yiiactiveform.updateSummary($form, data); if($.fn.yiiactiveform.getSettings($form).afterValidate==undefined || $.fn.yiiactiveform.getSettings($form).afterValidate($form, data, hasError)) { if(!hasError) { var $button = $form.data('submitObject') || $form.find(':submit:first'); // TODO: if the submission is caused by "change" event, it will not work if ($button.length) $button.click(); else // no submit button in the form $form.submit(); return false; } } }); 3. Only if we have no errors, than call the following ajax method: jQuery.ajax( {'type':'POST','success':feedbackSuccess,'url':'/company/feedback','cache':false,'data':jQuery(this).parents("form").serialize()} );
PS this is very raw algorithm, just the most obvious solution of the problem.
Comment #3
Posted on Jan 19, 2011 by Helpful CamelDo not use ajaxSubmitButton in this case because it will mess up with the active form js, as you have experienced.
You may consider setting beforeValidate and afterValidate if you want to do some extra work when submit is clicked.
Comment #4
Posted on Jan 20, 2011 by Quick OxI want to have both ajax validation and ajax form submission (I want to make fadein effect after form is submitted and give a message to the user). But, unfortunately, in the current situation it is impossible, unless I will do it manually.
Still, if you say, that we cannot use ajaxSubmitButton with CActiveForm, then I guess this should be highlighted in the documentation (I have not found any word about it and spent several hours to understand why it is not working)
Nevertheless, I think the better way is to make some checks in ajaxSubmitButton and if it is used with CActiveForm, then ajaxSubmitButton should integrate into it correctly.
I should also note, that I'm not the only one who struggled with this issue. I found topic thread about the same problem (but it's in Russian) http://yiiframework.ru/forum/viewtopic.php?f=3&t=821 So, I think, people would like to use ajaxSubmitButton with CActiveForm.
Comment #5
Posted on Jan 20, 2011 by Helpful CamelIt's fine to do both ajax validation and submission. You just need to configure afterValidate().
We cannot check if ajaxSubmitButton is within CActiveForm because it introduces unnecessary coupling between them. If in future we develop another widget similar to CActiveForm.
I agree we need to improve the doc. Things like this are better explained in a special topic, perhaps in terms of a wiki article. Perhaps you may help with this after you overcome this problem (so that your hours are no longer wasted)? Thanks!
Comment #6
Posted on Jul 15, 2011 by Swift WombatIt's fine to do both ajax validation and submission. You just need to configure afterValidate()
I think it will be nice to have response data from the server in afterValidate() method.
Now we have only this params: form - form object; data - validation error list in JSON; hasError - boolean validation result.
Of course, we can to make fadeIn effect and to display message, but how can we display custom server response in DOM element by afterValidate() method?
Comment #7
Posted on Nov 2, 2011 by Helpful RabbitIt took me a minute to figure out how to do this, but I got it working with the afterValidate callback, like so:
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; } }
If there is no error, it submits the form via ajax, and returns "false" so the default form submit does not finish.
Comment #8
Posted on Nov 2, 2011 by Helpful RabbitEdit: jQuery(this).parents("form").serialize() needs to be jQuery('#formID').serialize()
Comment #9
Posted on Oct 30, 2012 by Swift GiraffeHi guys I had same problem. I used aftervalidate, beforevalidate etc.. nothing worked out for me :( SO I made it myself and have posted in the forum. Take a look @ my post here: http://www.yiiframework.com/forum/index.php/topic/37075-form-validation-with-ajaxsubmitbutton/
Comment #10
Posted on Dec 20, 2012 by Swift CatI've also put together a solution, as Qiang Xue suggested previously, implemented as an extension of CActiveForm, CActiveAjaxForm.
This keeps things encapsulated, utilizes the framework provided ajax validation (without reimplementation of existing code) gracefully, and requires no additional implementation code, except for an optional "afterSave" method for a callback handler on the successful save.
It's available with docs here -https://github.com/beezee/yii_cactiveajaxform
Comment #11
Posted on Feb 5, 2013 by Happy RhinoWe can merge the validation code and ajax submit code. try this, http://www.yiiframework.com/extension/eactiveajaxform/
Status: Invalid
Labels:
Priority-Medium
Milestone-1.1.7