Avoiding client side validation on secondary submit buttons.

The problem is described here:

http://www.yiiframew…-cancel-button/

Server side validation is no problem since you can check [font=“Courier New”]isset($_POST[‘cancel’]);[/font] to see if cancel button was pressed, but it seems there’s no a reliable way to do this in javascript for client side validation.

My suggestion would be to add some option to the cactiveform’s [font=“Courier New”]clientOptions[/font] to indicate which controls would trigger client validation.

Ok, I wrote this quick hack patch to CActiveForm, adding an array property called avoidClientValidationOn which would contain the names of the buttons for which the client validation should be disabled, and a Javascript function for disabling the validation (notice that if you specify avoidClientValidationOn and clientOptions.beforeValidate, your beforeValidate handler will be overwritten. TODO: execute custom beforeValidate handlers and configure the name of the Javascript function.


--- CActiveForm.php 	(revisión: 367)

+++ CActiveForm.php 	(copia de trabajo)

@@ -278,6 +278,15 @@

 		*/

    	public $enableClientValidation=false;

 

+   /**

+	* Array containing the names of the buttons for which client validation is

+	* disabled.

+	*

+	* @author MetaYii

+	* @var type

+	*/

+   public $avoidClientValidationOn = array();

+

    	/**

 		* @var mixed form element to get initial input focus on page load.

 		*

@@ -361,10 +370,29 @@

            	if($this->focus!==null)

                    	$options['focus']=$this->focus;

 

+  	if (is_array($this->avoidClientValidationOn) && !empty($this->avoidClientValidationOn)) {

+ 		$options['beforeValidate'] = 'js:beforeValidate';

+ 		$buttons = CJavaScript::encode(array_fill_keys($this->avoidClientValidationOn, ''));

+ 		$js =&lt;&lt;<eop +function="" beforevalidate(form)="" {="" +="" if="" (form.data('submitobject'))="" (form.data('submitobject')[0].name="" in="" {$buttons})="" this.validateonsubmit="false;" this.beforevalidate="function" form.submit();="" };="" return="" false;="" }="" true;="" +}="" +eop;="" $cs-="">registerScript(get_class($this).'#'.$id.'#novalidation', $js);

+

            	$options=CJavaScript::encode($options);

            	$cs-&gt;registerCoreScript('yiiactiveform');

            	$id=$this-&gt;id;

            	$cs-&gt;registerScript(__CLASS__.'#'.$id,"\$('#$id').yiiactiveform($options);");

+  	}

    	}

 

    	/**



<br><br><br>But if you can improve my quick hack, be my guest.<br></eop>

Ok, as editing in the forum s*cks :angry: , I’ll repost my patch:


--- CActiveForm.php 	(revisión: 367)

+++ CActiveForm.php 	(copia de trabajo)

@@ -278,6 +278,15 @@

     	*/

    	public $enableClientValidation=false;

 

+   /**

+	* Array containing the names of the buttons for which client validation is

+	* disabled.

+	*

+	* @author MetaYii

+	* @var type

+	*/

+   public $avoidClientValidationOn = array();

+

    	/**

     	* @var mixed form element to get initial input focus on page load.

     	*

@@ -361,10 +370,29 @@

            	if($this->focus!==null)

                    	$options['focus']=$this->focus;

 

+  	if (is_array($this->avoidClientValidationOn) && !empty($this->avoidClientValidationOn)) {

+     	$options['beforeValidate'] = 'js:beforeValidate';

+     	$buttons = CJavaScript::encode(array_fill_keys($this->avoidClientValidationOn, ''));

+     	$js =<<<EOP

+function beforeValidate(form) {

+   if (form.data('submitObject')) {

+  	if (form.data('submitObject')[0].name in {$buttons}) {

+     	this.validateOnSubmit = false;

+     	this.beforeValidate = function beforeValidate(form) { form.submit(); };

+     	form.submit();

+     	return false;

+  	}

+   }

+   return true;

+}

+EOP;

+  	$cs->registerScript(get_class($this).'#'.$id.'#novalidation', $js);

+

            	$options=CJavaScript::encode($options);

            	$cs->registerCoreScript('yiiactiveform');

            	$id=$this->id;

            	$cs->registerScript(__CLASS__.'#'.$id,"\$('#$id').yiiactiveform($options);");

+  	}

    	}

 

    	/**



Opened an issue on this here:

http://code.google.com/p/yii/issues/detail?id=2772

Note, with my hack, you just need to configure the form like this:


<?php


$form = $this->beginWidget('CActiveForm', array(

	'id'=>'recovery-form',

   'enableClientValidation'=>true,

   'enableAjaxValidation'=>false,

   'focus'=>array($model, 'username'),

   'errorMessageCssClass'=>'clsErrorMessage',

   'htmlOptions'=>array('autocomplete'=>'off'),

   'avoidClientValidationOn'=>array('cancel'), // new option here *****

	'clientOptions'=>array(

		'validateOnSubmit'=>true,

  	'errorCssClass'=>'clsError',

  	'successCssClass'=>'clsSuccess',

  	'validatingCssClass'=>'clsValidating',

	),

));


?>

This is a great idea. I’m using a wizard style create form. When I click the “next” <button>, yiiactiveform validates the whole form displaying all errors. I didn’t get the patch to work. It seems it disabled validateOnSubmit regardless of the setting. Still working on it. This is what I patched:





                if($this->focus!==null)

                        $options['focus']=$this->focus;


//Patch

                if (is_array($this->avoidClientValidationOn) && !empty($this->avoidClientValidationOn)) {

                        $options['beforeValidate'] = 'js:beforeValidate';

                        $buttons = CJavaScript::encode(array_fill_keys($this->avoidClientValidationOn, ''));

                        $js = 'function beforeValidate(form) {

                                if (form.data("submitObject")) {

                                        if (form.data("submitObject")[0].name in {$buttons}) {

                                                this.validateOnSubmit = false;

                                                this.beforeValidate = function beforeValidate(form) { form.submit(); };

                                                form.submit();

                                                return false;

                                        }

                                }

                                return true;

                        }';


                $cs->registerScript(get_class($this).'#'.$id.'#novalidation', $js);

//End Patch

                $options=CJavaScript::encode($options);

                $cs->registerCoreScript('yiiactiveform');

                $id=$this->id;

                $cs->registerScript(__CLASS__.'#'.$id,"\$('#$id').yiiactiveform($options);");

//Patch

                }

//End Patch






This is a follow up the post by Ken… at the ticket in Google Code. He mentions that my hack didn’t work for his use case (a form with a wizard, where the pressing of the Next button triggers validation):

First: notice that the patch was extracted from svn diff, since I have Yii inside my subversion local copy of my project. So I’m not sure if the patch command will work with it without some manual modification. I’m sorry for not warning about this before.

On your issue, I guess it has to do with the fact of having a wizard. I’ve just tested on a normal form. Your wizard, is AJAX/JS based or postback-based?

Be careful, you’re using single quotes in this assignment:


$js = 'function beforeValidate(form) {

so I guess this won’t be interpolated:


                                 		if (form.data("submitObject")[0].name in {$buttons}) {

So I guess that if you check your page source code in the browser, you’ll get something like


                                 		if (form.data("submitObject")[0].name in {$buttons}) {

with the [font=“Courier New”]{$buttons}[/font] textually, instead of being replaced by the [font=“Courier New”]value of the $buttons[/font] variable. Please use double quotes. I also would suggest using heredoc, but that’s just my personal preference.

I assume you’re not using Firebug or MSIE with javascript debugging enabled, because I’m pretty sure a javascript error is being thrown.

Thanks for the reply so quickly! I’m using a standard form, using JQuery to slide back and forth to/from the next section. No AJAX. yiiactiveform is not loading, probably why the validation isn’t working. I’m using google devel tools to play with this some more.

Tried replacing the single quote with double quotes a few different ways. It still didn’t load yiiactiveform.

Logan

So… I played around with MetaYii’s patch for CActiveForm. I couldn’t get it working correctly. Perhaps I was doing something wrong. However, I believe I solved my problem with this. Let me know what you think. All I have to do is add the class ‘jsNoValidate’ to the button.




<?php

$js = <<< EOJ

function beforeValidate(form) {

	if (form.data('submitObject').hasClass('jsNoValidate'))

		return false;

	return true;

}

EOJ;

Yii::app()->clientScript->registerScript('beforeValidate', $js);

?>

<div id="container">

	<?php $form=$this->beginWidget('CActiveForm', array(

		'id'=>'employee-form',

		'enableAjaxValidation'=>true,

		'clientOptions'=>array(

			'validateOnSubmit'=>true,

			'beforeValidate'=>"js:beforeValidate"

		),

	)); ?>


ETC....



You really should install Firebug in either Firefox or Chrome. That would save you a few headaches with javascript erros :wink:

Also, remember that you must delete the contents of the published assets directory in order to get the changes to any of the javascript code of the framework.

Yeap, that’s another way to refer to the buttons.

Why don’t you try this ? ->

Wizard Behavior ;)

I am using it for an installer and it works perfectly.

Yup - I was deleting assets.

I haven’t seen a huge advantage in using firebug over the developer tools. Perhaps I’ll take another look.

Wizard behavior is nice. The wizard I’m using is one action, with a nice jquery slide effect. Very simple and minimalistic. It’s published here: Wizard. Except mine looks a bit different : My Form

hello, anyone got it to work on IE 8, I am getting javascript error "Out of stack space" when i click on the submit button. It seems like the code "form.submit();" is causing this error in IE. It is working fine on Google chrome.

Can you guys help please?

Thanks!