[EXTENSION] Javascript form Validation

Ahhhh, tricky you are ;).

Thank you very much.

Hi all,

a new version of the jformvalidate extension has been released today. Here is the changelog :




version 1.0.7

    - fixed : js validation rules are not correctly applied when scenario is used (thanks to Jaime)

    - fixed : EHtml::setScenario() and EJFValiudate->setScenario() now forward new scenario

      to CHtml::scenario (thanks to mindeh)



download it from the Extension section

(any feedback is welcome ;) )

8)

What a nice extension. Thanks a lot. It should be incorporated into the core.

I have a feature requests.

Could you implement the match validation (matching against a regular expression)? That should be quite easy if you know how the extension is structured. I know that the regular expressions of PHP and JavaScript might differ in details, but it would be succifient to test telephone or date patterns.

BTW: The "join discussion" link at http://www.yiiframework.com/extension/jformvalidate/ needs an update.

Hi mh469,

and thanks for your comment (I’ve updated the ‘join discussion’ link ;) )

As you say, the main problem in implementing a match rule, is thatregular expression syntax differs between PHP and JS … and converting one into the other is something I’m not sure I want to spend time in. However, if you need a simple telephone or date pattern, why not add it by yourself ? (Date and telephone format strongly varies from a country to another).

Have you check sample12 from the demo ? This sample illustrate how to add your own custom validation rule. Moreover, the extension comes with a set of JS validation rules already implemented, and not (yet) used … if one of them suits your needs (there is a date and a dateITA validators waiting for you !) just write the PHP part and you’re done. Of course I’ll provide you any help I can, and that could be intresting to have some feedback on how easy (or not) it is to write a new validator for this extension.

ciao

8)

I don’t think one has to do that. (And I don’t think that that is possible, one of the two implementations might be more powerful.) In the basics, both implementations correspond and I think that should fit 99% of their usage, if not more. Of course, I could write my own custom validation rule. But to have a validation rule like ‘^\d\d\d\d-\d\d-\d\d$’ or ‘^0\d±\d+$’ specified only in one place is much more convenient (DRY). Furthermore, custom validators would make updates of the extension much more difficult.

BTW, at the moment I’m using CMaskedTextField and a simple server side pattern for my date fields.

Maybe you want to also have a look at PRADO’s TRegularExpressionValidator for inspiration. We’ve added a ClientSidePatternModifiers property there as the modifiers are one of the main differences between server/clientside regex.

Ok then, if you think that this 99% of compatibility is enough, a match validator maybe useful … I will implement it asap and add to next release.

(and I’ll also take a look to this TRegularExpressionValidator class ;) )

8)

IPBoard starts to really annoy me. Even links are altered so they don’t work anymore. So here’s the link again:

http://www.pradosoft…nValidator.html

Edit:

No way of pasting this link without error. Grml…???

For mh469 and others, here is a new release of the [color="#0000ff"]jformvalidate [/color]extension !

[size="3"]version 1.0.8rc1[/size]

changelog :

  • add : support the match rule (see form15 from the sample)

Limitation is that the exact same pattern passed as argument of the match rule, is used both for client and server side validation, so it is processed by Javascript and PHP. Regular expression modificator are not supported, except for /i (case insensitive). Due to a short delay, this release could not be extensively tested, so don’t hesitate to submit any bug !

8)

Wow, that was fast. And it works splendid! You are my hero!

;D

Glad to see it suits your needs … As I wrote, I didn’t perform extensive test, and I can’t garantee you that some complex regular expressions are going to be correctly interpreted by PHP and JS. I guess that as long as RE are simple, you should have no problem.

I’ll release this new version in the extension section soon.

ciao

B)

Hi all,

the 1.0.8rc1 version that was published in the forum, has now turned into an official 1.0.8 release, in the Extension section. No big improvments, but some may be useful.

[size="3"]version 1.0.8[/size]

changelog :

  • add : support the match rule (see form15 from the sample)

Limitation is that the exact same pattern passed as argument of the match rule, is used both for client and server side validation, so it is processed by Javascript and PHP. Regular expression modificator are not supported, except for /i (case insensitive).

  • update : original jquery.validate.js file was modified in order to make it compliante with JS compressors. In particular, opening and closing braces were added to single ‘if’ statement (thanks to scythah).

  • update : EJFValidate.getCurrentFormId() is now public

Please note that currently, this extension does not support (yet) the 1.1 branch of the Yii framework.

Enjoy !

8)

Hi all,

the 1.0.8rc1 version that was published in the forum, has now turned into an official 1.0.8 release, in the Extension section. No big improvments, but some may be useful.

[size="3"]version 1.0.8[/size]

changelog :

  • add : support the match rule (see form15 from the sample)

Limitation is that the exact same pattern passed as argument of the match rule, is used both for client and server side validation, so it is processed by Javascript and PHP. Regular expression modificator are not supported, except for /i (case insensitive).

  • update : original jquery.validate.js file was modified in order to make it compliante with JS compressors. In particular, opening and closing braces were added to single ‘if’ statement (thanks to scythah).

  • update : EJFValidate.getCurrentFormId() is now public

Please note that currently, this extension does not support (yet) the 1.1 branch of the Yii framework.

Enjoy !

8)

[size="3"]Bugreport: unticked ActiveCheckBox broken[/size]

Example:

[spoiler]controllers\TestController.php


<?php

class TestController extends BaseController

{

	public function actionIndex()

	{

		$form = new TestForm;

		if(isset($_POST['TestForm']))

			$form->attributes = $_POST['TestForm'];

		$this->render('test', array('form'=>$form));

	}

}

?>

models\TestForm.php


<?php

class TestForm extends CFormModel {

	public $check = true;

	public function rules() {

		return array( array('check', 'safe') );

	}

	public function safeAttributes() {

		return array( 'check', );

	}

}

?>

views\test\test.php


<?php

var_dump($form->check);

echo CHtml::beginForm();

echo CHtml::ActiveCheckBox($form, 'check');

echo CHtml::submitButton('Submit');

echo CHtml::endForm();

?>

[/spoiler]

Play around with this example. An unticked checkbox is recognized as “0”. Now, in the view, change CHtml:: into EHtml:: (i.e. use jformvalidate). Then, an unticked checkbox is recognized as “true”. That shouldn’t be the case.

hi mh469,

I’ll take a look at this bug, but before that, I noticed that you are using the ‘safe’ rule which has been added to 1.1x version of Yii. Please note that jformvalidate extension does not support Yii 1.1x … this is in the ‘todo’ list, but not before the final Yii 1.1 is released.

Now back to this checkbox …

8)

ok, here is a new version of EJFValidate extesion, that should fix this problem.

For those who are intrested, here is what happened : when a check box is created by Yii, no one but 2 input fields are created with different values and types, like shown below.

[html]

<input id="ytTestForm_approvePolicy" type="hidden" name="TestForm[check]" value="0"/>

<input id="TestForm_approvePolicy" type="checkbox" name="TestForm[check]" value="1" />

[/html]

There is the actual checkbox and before it, an hidden field with the same name than the checkbox. This way, if the checkbox is not checked by the user, the POST contains TestForm[‘check’] = 0 … without it, TestForm[‘check’] would simply not be set (NULL).

This is ok, but 2 inputs with the exact same name is not supported by the underlying JS validate plugin and so, the extension adds a js call to a function in charge of normalizing names, to make them unique. Just before the form is submitted, the extension must restore those names and this is done in the js onSubmitHandler.

The problem reported by mh469 occured when no js rule is defined for the checkbox control, and consequently, the onSubmitHandler is not called : names are not restored and the POST array is wrong.

In this new version, the function that normalize names is called only when a JS rule is actually added (which garantee that names will be restored before submit).

I made some tests and it seems to work fine, but please let me know if the problem persists.

Thanks

B)

Thanks. That does fix my example, but did not work with my complex form. I spent quite a long time searching. I found the following minimal example to reproduce the problem

[spoiler]TestController.php


<?php

class TestController extends BaseController

{

    public function actionIndex()

    {

        $form = new TestForm;

        if(isset($_POST['TestForm']))

            $form->attributes = $_POST['TestForm'];

        $form->validate();

        $this->render('test', array('form'=>$form));

    }

}

?>

models/TestForm.php


<?php

class TestForm extends CFormModel {

    public $check = true;

    public $check2;

    public $text = "a\nb";


    public function rules() {

        return array(

            # those two rules in combination spoil the 3rd checkbox

            array('check2', 'required'),

            array('text', 'match', 'pattern'=>'/^[^\n]*(\n[^\n]*){0,1}$/su', 'message'=>'no more than 2 lines'), # regexp invalid for JS

        );

    }

    

    public function safeAttributes() {

        return array( 'check, check2, text', );

    }

}

?>

views/test/test.php


<?php

echo EHtml::beginForm();

echo EHtml::errorSummary($form);

echo EHtml::ActiveTextArea($form, 'text');echo "

";

echo EHtml::ActiveCheckBox($form, 'check2');echo "

";

var_dump($form->check);

echo EHtml::ActiveCheckBox($form, 'check');

echo EHtml::submitButton('Submit');

echo EHtml::endForm();

?>

[/spoiler]

The problem seems as follows: The RegExp is invalid in Javascript and disturbs the validation. That would be acceptable, but submission is also affected. The unticked checkbox is not submitted properly.

The simplest solution would be to declare the match rule to be only validated on the server.

But one could go other ways as well. As my browser does not show any JS error message, I assume you use try/catch. But somehow it is too large a block, so that a bad RegExp spoils all other validations and, most important, submission. Would it be possible to use smaller try/catch blocks so that the other functions are not affected?

One other thing your last fix points me to, is the fact that you modify the form on creation on the server and fix it before submission. That means that the form won’t work correctly with Javascript turned off. The best solution would be if Javascript could somehow handle duplicate names. If that was not possible one could use <script>/<noscript> constructs to make the form work without JS. But I know that this is a lot of work.

Carry on with your good work!

Hi mh469,

the problem you’re describing here is not related to the first one (the one with checkboxes), and as you found out, it is caused by a Regular Expression that can’t be evaluated by JS (because of the /su flags I guess). This problem was going to happen sooner or later, and I have implemented what I believe to be an acceptable behaviour :

[indent]If a regular expression can’t be evaluated on the client side, the JS rule returns success, so validation can continue and the form be submitted. On the server-side then, match rule is again tested, and this time, with no error.[/indent]

You’ll find attached a new verion of the JS ‘match’ validation rule … Based on the sample you’ve posted, it solves the problem, but I let you do the test ;)

One point I was not clear about …

That’s not what happen because in fact, input element names are modified (normalized to make each one unique) only on the client-side. This happens on documentReady JQuery event, by a call to $.fn.EJFValidate.uniqueName(). Now if Javascript is disabled, nothing will be modified and the form will remain unchanged.

Ok, no more blah blah … here is the new JS file. Unzip it and copy jquery.jfvalidate.helper.js into protected/extensions/jformvalidate/js (replace existing file)

Tell me if it works.

ciao

8)

Perfect! :D

I claimed that the field names werd modified on the server-side.

Oh, sorry for the wrong accusation. :-[ You are right. I only saw your change in EJFValidate.php with regard to $this->normalize(). I assumed that this function does directly alter the name where in fact it ships out JS code to do that on page load. I could have tested it myself.

I have another bug report with regard to checkboxes. :( If I need a checkbox to be ticked, your code accomplished this with


array('check2', 'required')

However, this is not identical to the server-side behaviour. As a checkbox always has a value (‘0’ or ‘1’) that rule is always met on the server-side. (BTW if I need a checkbox to be checked, I now use “‘compare’, ‘compareValue’=>true,” or “‘required’, ‘requiredValue’=>true”.

I’ll take a look at it soon (tomorrow) ;)

8)