[EXTENSION] Javascript form Validation

ok, I see now.

In order to know which button is clicked by the user (with or without Js Validation), you could for instance add an hidden field to your form. Then, on the ‘onClick’ event, set the value for this hidden field.

This is how it could look like :




<?php echo EHtml::hiddenField('buttonClickedByUser','JsValidation',array('id'=> 'buttonClickedByUser')); ?>


<?php echo EHtml::submitButton('Submit'); ?>

<?php echo EHtml::submitButton('Submit (skip JS Validation)',array(

	'class'   => 'cancel',

	'onclick' => '$(\'#buttonClickedByUser\').val(\'skipJsValidation\')',

)); ?>



If the user clicks on the non-Js-validation submit button, the onclick handler sets the hidden field value to ‘skipJsValidation’, so on the server side, you can use the hidden field value.

On Submit, the POST array would contain :




buttonClickedByUser = 'skipJsValidation' or 'JsValidation'



Hope this helps

ciao

B)

Perfect!!!

Thank you!

GREAT WORK ON THE EXTENSION

Here is how i made this compatible with Yii-1.1 form.css

EJFValidate.php


	private $_jqueryPluginFile 		= 'jquery.validate.js';//'jquery.validate.min.js';

/config/main.php


		'jformvalidate'=>array (

			'class'=>'ext.jformvalidate.EJFValidate',

			'enable'=>true,

			'pluginOptions'=>array(

				'errorClass'=>'errorMessage',

				'errorElement'=>'div',

				'inputErrorClass'=>'error',

			),

		),

jquery.validate.js patch:


201d200

< 		inputErrorClass: "error",

213c212

< 				this.settings.unhighlight && this.settings.unhighlight.call( this, element, this.settings.inputErrorClass/*errorClass*/ );

---

> 				this.settings.unhighlight && this.settings.unhighlight.call( this, element, this.settings.errorClass );

376c375

< 			this.elements().removeClass( this.settings.inputErrorClass/*errorClass*/ );

---

> 			this.elements().removeClass( this.settings.errorClass );

584c583

< 				this.settings.highlight && this.settings.highlight.call( this, error.element, this.settings.inputErrorClass/*errorClass*/ );

---

> 				this.settings.highlight && this.settings.highlight.call( this, error.element, this.settings.errorClass );

597c596

< 					this.settings.unhighlight.call( this, elements[i], this.settings.inputErrorClass/*errorClass*/ );

---

> 					this.settings.unhighlight.call( this, elements[i], this.settings.errorClass );

Thank you.

thanks phpdevmd,

and you did a good job to by providing this patch … I will include it in a future release !

Thanks

B)

Hi Raoul,

This is great extension for Yii, I’m using this in all my project. But I have the little confuse.

  • In Yii 1.1.1, when call EHtml::setScenario(‘scenario’) in views, Yii error with message “scenario already set”, in old version Yii, it works fine. I find I can set scenario by $model->scenario = ‘scenario’, so EHtml::setScenario() can use in what case?

  • When I need to create a form with two models has individual rules, JFVFormValidate send error message "scenario already set", can plz help me

Thanks much

Hi giz,

since 1.1 you should always set the scenario at the model level, using (like you did) $model->scenario = ‘myScenario’.

You’re right, the method EHtml::setScenario() is useless and it has no other purpose than to preserve backward compatibility with older version of the extension.

Remember that you can’t change scenario between a beginForm() and a endForm() … and that’s what may cause your second error. I don’t know how you’ve contructed your form with mixed models, but the [color="#0000FF"]JFormValidate[/color] extension is not supposed to work if you mix models inside the same form : you’ll have to create 2 forms.

Now tell me, did you notice it used to work with older extension version ? or is it the first time you mix models ?

If you post the code of your view, maybe I could help better …

ciao

B)

ps: please note that I’ll be away since next Monday …so be patient for next reply ;)

[size="4"][color="#0000FF"]about CActiveForm and jformvalidate extension[/color][/size]

Rangel Reale has released a new extension that adds client-side validation features to the CActiveForm Widget instead of using jformvalidate, because as he said, jformvalidate is not compatible with CActiveForm. That’s true !

So I did some tests :

  • copy CActiveForm from the framework to the myWebApp/extensions/jformvalidate folder

  • rename it EJFActiveForm

  • replace all calls to CHtml:: with EHtml::

  • update configuration

  • call beginWidget(‘extensions.jformvalidate.EJFActiveForm’)

With some adjustments to set jformvalidate options, everything seemed to work fine ‘out of the box’ on simple forms (I’ve used the Contact form).

Ok, so next step would be to make some more tests and to release a new version of the jformvalidate extension. So why am I not doing it right now instead of posting endless messages on the forum ? hum … good question !

The thing is, I don’t really see why ! I mean, which scenario could justify to mix pure client-side validation, ajax validation and pure server-side validation ? Moreover, jformvalidate does support ajax validation rules (as shown in this example) so if some attributes need to be validated on the server side, that’s easy to achieve be defining an apropriate rule on the model.

If you need 3 form validation methods (client-side, ajax, pure server-side) you have 2 options :

  • go with jformvalidate and a ‘remote’ validation rule

  • use extension wvActiveForm

Consequently, and unless I really see strong positive points in doing so, I will not provide the EJFActiveForm class in a next release of jformvalidate.

ciao

B)

Just one thing, I never used CActiveForm’s AJAX validation, so I don’t even know how it works, or even if it is compatible at all with my extension :rolleyes:

So if someone wants to do all 3 type of validations, he will need to test the AJAX one!

I think it should be easy to convert your extension to CActiveForm, as it is mainly only forwarding class to CHtml.

Only reason I could see the use of adding the client side js validation is for high traffic sites, it would reduce server load.

Hi Raoul,

I’ve been trying to get the following dropdownlist to work with a form that uses the validation extension but it seems that the extension prevents the dropdownlist from working.

Here is the dropdownlist code:




<?php

echo CHtml::dropDownList(

  CHtml::activeId($customContentAR,'id').'_ddl', 

  $customContentAR['id'],

  $customContentDDL['data'],

  array(

    'ajax'=>array( 

      // ajaxOptions

      'type' => 'POST',

      'url' => CController::createUrl('home/getCustomContentAjax'),

      'beforeSend' => '

        function(request)

        {

          return dropDownListBeforeSend(request);

        }// function()

      ',

      'dataType'=>'json',

      'success'=>'

        function(data)

        {

          dropDownListSuccess(data);

        }// function()

      ',

      'data' => array(

        'customContentId' => "js:jQuery('#".CHtml::activeId($customContentAR,'id').'_ddl'."').val()",

      ),

    )

  )

);

?>



When this is used by itself in a view it works as expected, the ajax code submits the selection to the controller. But if I add a form validated with the extension it stops working, that is changing the selected value of the dropdownlist does not cause the ajax code to be submit the change to the controller. In fact, just adding the following causes the problem.




echo EHtml::beginForm(

  '',

  'post',

  array(

    'class'=>'customContentForm',

  )

); 

EHtml::setOptions(

  array(

    'errorContainer' => 'div.errorSummary',

    'wrapper' => 'li',

    'errorLabelContainer' => 'div.errorSummary ul',

    'errorClass' => 'invalid',

    'onkeyup' => false,

    'onfocusout' => false

  )

);    

echo EHtml::endForm();

?>




What am I doing wrong?

Thanks for you help!

Hi zilchman,

you’re doing nothing wrong and I could reproduce the issue easily … now how to fix it is not so easy.

After some research I found that the Validate JQuery plugin that is used by the jformvalidate extension, overloads the Delegate method and this seems to prevent your own handler to be called when the dropDownList selection is changed by the user.

…so no ajax call is made.

This is what is found at the end of js/jquery.validate.js :




.....	

$.extend($.fn, {

		delegate: function(type, delegate, handler) {

			return this.bind(type, function(event) {

				var target = $(event.target);

				if (target.is(delegate)) {

					return handler.apply(target, arguments);

				}

			});

		},

		// ....

	});

})(jQuery); 

Now if you comment this delegate overloads, the ajax call is correctly done when selection changes. However this has some bad effects on other features : for instance validation does not occur anymore when a control lost the focus (but as you are using onfocusout = false this should not impact you).

Commenting a piece of code to solve a problem is not a good idea, but right now let’s say that it’s an acceptable workaround. I’ll try to find a better way to fix that, but it may take some times because I’m not a js expert.

Hope it helped anyway …

Thanks for the quick reply. At least I know what is going on now. I’ll Try your suggestion.

I have a few suggestions for the code.

  1. In the latest version of Yii, forms are generated by a form widget (CActiveForm) which requires you to make a lot of typing changes to switch over to using EHtml:: from $form->textField since some stuff has get labeled with active first and some doesn’t. So I made a copy of the Yii CActiveForm widget and renamed it ActiveForm. Since it is already just a mapping to the CHtml class, changing it to map to EHtml was trivial with find and replace. However, I’m not sure if this becomes rather inefficient since we are now mapping a widget to EHtml to CHtml. The only other change I made was to disable to ability to have AJAX form validation in the ActiveForm widget. See my attached code. 1124

ActiveForm.php

  1. I upgraded the validate plugin to the latest version (1.7) with no issues.

  2. I added a bit of code to warn people on leaving the page.

The changes for that were:

In: EJFValidate.php

Add:


                $options['submitHandler'] = "function(form) {

                        changed=false;

                        return true;

                   }";

Below:


	protected function prepareOptions(){


		$options = array_merge($this->pluginOptions, $this->_pluginOptions);

Add:


$js = 'var changed=false;

                                    function goodbye(e) {

                                        if (changed) {

                                            if(!e) e = window.event;

                                            //e.cancelBubble is supported by IE - this will kill the bubbling process.

                                            e.cancelBubble = true;

                                            e.returnValue = \'You will lose changes if you leave this page, please press Cancel to stay on this page and save your changes.\';

                                            //This is displayed on the dialog


                                            //e.stopPropagation works in Firefox.

                                            if (e.stopPropagation) {

                                              e.stopPropagation();

                                              e.preventDefault();

                                            }

                                       }

                                    }

                                   window.onbeforeunload=goodbye;';

                                Yii::app()->clientScript->registerScript('JValidatechanged', $js, CClientScript::POS_END);

                                $js = '                                    $("#'.$this->_formId . ' :input").change(function() {

                                      changed=true;

                                    });';

                                Yii::app()->clientScript->registerScript($this->_formId.'changed', $js, CClientScript::POS_END);

Below:


Yii::app()->clientScript->registerScript($this->_formId, $this->prepareOptions());

In: Jquery.validate.js

Change:


					if ( validator.settings.submitHandler ) {

						if (validator.submitButton) {

							// insert a hidden input as a replacement for the missing submit button

							var hidden = $("<input type='hidden'/>").attr("name", validator.submitButton.name).val(validator.submitButton.value).appendTo(validator.currentForm);

						}

						validator.settings.submitHandler.call( validator, validator.currentForm );

						if (validator.submitButton) {

							// and clean up afterwards; thanks to no-block-scope, hidden can be referenced

							hidden.remove();

						}

						return false;

					}

					return true;



to:


					if ( validator.settings.submitHandler ) {

						if (validator.submitButton) {

							// insert a hidden input as a replacement for the missing submit button

							var hidden = $("<input type='hidden'/>").attr("name", validator.submitButton.name).val(validator.submitButton.value).appendTo(validator.currentForm);

						}

						submitReturn = validator.settings.submitHandler.call( validator, validator.currentForm );

						if (validator.submitButton) {

							// and clean up afterwards; thanks to no-block-scope, hidden can be referenced

							hidden.remove();

						}

                                                if (submitReturn === true) {

                                                    return true;

                                                } else {

                                                    return false;

                                                }

					}

					return true;

I know a few of these changes are not the best for all since the first change will prevent people from using AJAX submit scripts, and it requires changing the jquery validate code. (Though I think using a bit of magic it should be possible to just add changed=false into a user specified function or code which is all my code needs to prevent a warning on submit.) I will submit a request to the validate plugin for a change similar to what I made to the JS. I did not prepend anything to my changed variable since that is one time code for the page and will register a change in any form. If you change two forms and submit one, the code will let that happen and you will lose your changes in the other form.

I’m happy to provide explanations for things if you have any questions.

Hi Loren,

and thanks for posting.

You’re right, about using CactiveForm to generate forms, and in fact I’ve already made some test in the direction you’re pointing … and it seems to work fine, with minimal adaptation effort (basically use something like JVFActiveForm instead of CActiveForm). Actually i had posted about that topic (see above) and the class you have attached is exactly what I planned to release … cool

Now regarding the ‘leaving page…’ feature it’s indeed very intresting but as you mentioned, having to modify the Validate JS plugin is a problem (hopefully, authors will include your changes).

Anyway, good job and thanks again for your clear explanation. I’ll release a new version that includes the ActiveForm class as soon as I have sometime …

bye

ps: if you’re using the extension on a website, I would be intresting to see it in action…

I assume you are wanting to see the page leave warning part live?

If that is what you are looking for, I will need to put a copy of our sandbox software live online somewhere which I’ve been meaning to do for a while so just let me know on that part.

I missed part of the documentation about jquery validate.

It works fine if you use:


            	$options['submitHandler'] = "function(form) {

                    	changed=false;

                    	form.submit();

               	}";

I had used this.submit() when I tried it the first time which creates an infinite loop instead of the correct form.submit()

yep, the “page leave” part would be nice to have a look at, but if it can’t be accessed on the web, don’t bother … you probably have something more urgent to do

bye

I will get my app online sometime in the next week.

I’ve had a few people in my organization ask to be able to play with the development version so it is just a matter of my making time to get it online (and replace all the data with fake data…)

Here is one more change to implement the length is validation: (I use the rangelength validation rule to implement it.)

In EJFValidate.php:

Find:


		elseif($ruleName == 'length')

		{

			// This rule has no direct equivalent in the plugin, it must be splited

			// into 2 JS rules : min and max

			

			if( isset($ruleParams['min']) ) {

				$this->_rules[$attrActiveName]['minlength'] = $ruleParams['min'];

				$this->addValidatorMessage($attrName,$attrActiveName,'minlength',$ruleParams);

			}	

			if( isset($ruleParams['max'])) {

				$this->_rules[$attrActiveName]['maxlength'] = $ruleParams['max'];

				$this->addValidatorMessage($attrName,$attrActiveName,'maxlength',$ruleParams);

			}

Replace With:


		elseif($ruleName == 'length')

		{

			// This rule has no direct equivalent in the plugin, it must be splited

			// into 2 JS rules : min, max, and is

			

			if( isset($ruleParams['min']) ) {

				$this->_rules[$attrActiveName]['minlength'] = $ruleParams['min'];

				$this->addValidatorMessage($attrName,$attrActiveName,'minlength',$ruleParams);

			}	

			if( isset($ruleParams['max'])) {

				$this->_rules[$attrActiveName]['maxlength'] = $ruleParams['max'];

				$this->addValidatorMessage($attrName,$attrActiveName,'maxlength',$ruleParams);

			}

                    	if( isset($ruleParams['is'])) {

				$this->_rules[$attrActiveName]['rangelength'] = array($ruleParams['is'],$ruleParams['is']);

				$this->addValidatorMessage($attrName,$attrActiveName,'rangelength',$ruleParams);

                    	}

Find:


				'minlength' => Yii::t('yii','{attribute} is too small (minimum is {min}).'),

				'maxlength' => Yii::t('yii','{attribute} is too big (maximum is {max}).'),

Add Below:


                            	'rangelength' => Yii::t('yii','{attribute} is of the wrong length (should be {is} characters).'),

I used to write modifications for Invision Power Board which resulted in writing lots of manuals on how to properly edit the code so that is where my code changes style comes from.

Hi, I just started to use jformvalidate extension. After some attempts, I can display and submit the form data correctly with EHtml form elements. However I can’t get the checkboxlist retain their status after clicking the submit button. I can run the sample testForm in my workspace. One thing I noticed is the name value of the hidden field generated with the js lacking of the prefix: “EJSv_”. For example, in testForm 4, the hidden field is generated as:




<input type="hidden" name="EJSv_TestForm[favcolor]" value="" id="ytTestForm_favcolor">



but in my case, the hidden field is:




<input type="hidden" name="AddAdminForm[select_pub]" value="" id="ytAddAdminForm_select_pub">



I suspect this is the reason why the checkboxlist can’t retain the value selected before form submit. But I have tried every method which I can think of, still no idea where went wrong. I even copied the view from the sample code. I have been struggling with the problem for a few days, can anyone help me out of it? Thanks.

hi kuanfai,

if the prefix is not set for the checkbox element it is indeed a problem that can cause the extension to not work correctly. Yes, please, copy & paste the code of your form and I’ll try to reproduce this strange behavior … and possibly fix it (if its a bug ;) )

regards

8)

[center]

[/center]

[left]Hi all,[/left]

as you may already know, the latest release (1.1.7) of our favorite framework now includes client-side form validation feature. The powerful CActiveForm core widget now comes with a enableClientValidation option that enables you to benefit from this feature, with no additional effort.

You can find more information in the v1.1.7 release notes, and in the API documentation.

Consequently, as you may imagine, there is no need for another extension that would provide same features, and therefore, the jformvalidate extension has reached its end. With more than 2800 downloads, I like to think it has been useful to some of you, and the feedback I received sometime, tend to confirm that all the time I spent on this extension was not wasted.

For those who are still using it, I’ll do my best to provide support, however, in the future I don’t plan to release a new version of this extension (that would include CActiveForm support… this is now done in 1.1.7 ! ).

[size="3"]Again, thanks to all of you who participated in improving this extension by suggesting changes, pointing out and even sometimes fixing bugs…[/size]

[size=“3”][color="#0000FF"]… Let’s say bye bye to jformvalidate and a big welcome to 1.1.7 CActiveForm !![/color][/size]

ciao

8)