Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trigger Yii field validation onchange of another field

I have two related fields in a Yii model. They are items_per and items_period.

items_per is an integer that reflects how many items to be processed in a given time period.

items_period is the number of seconds in that period (a dropdown with options labelled as seconds, minutes, hours). Multiply items_per by items_period and you have "items per second".

I've got a custom validation rule set up to limit items per second being above a certain amount. That all works fine and gives a sensible error message using ajax validation when you change the value in the items_per field (on blur).

I need for the validation on the items_per field to be triggered whenever the items_period field is changed (100 / second may not be allowed, but 100 / minute is).

I tried adding an onchange function to the items_per dropdown to trigger "blur" or "change" on the items_per field, but it doesn't seem to make the ajax request for validation. Submitting the form just to trigger the validation isn't an option, as it's possible it might not have any errors and simply save the record before the user is ready.

Any suggestions how I can force one field to trigger ajax validation in another?

like image 786
Hippyjim Avatar asked Jul 13 '12 11:07

Hippyjim


2 Answers

You can achieve validation client-side (with JS), through AJAX and for plain requests all together in one package if you define a custom validator extending CValidator.

For "plain" validation, set up the validator with the correct attribute names and parameters and override the validateAttribute method.

For client-side validation, additionally override the clientValidateAttribute method. If client validation is enabled for the form this will result in your custom JS automatically being called to validate the input. From within the override you will be outputting JS code that runs in this context:

function(value, messages, attribute) {
    // your code goes here
    // value: current value of attribute
    // messages: array of strings (validation errors) you should append to
    // attribute: name of the attribute
}

You can see how the built-in validators work in this framework with an example. Also see CActiveForm.clientOptions.

For AJAX validation, you can submit the form for validation. The idea is that you configure validation to either include a special parameter (e.g. ajax=something) or exclude one (e.g. to not include the value of your submit button). In fact, Yii already does this by automatically including an ajax=formId parameter in all AJAX validation requests!

This way you can easily write controller code that always validates but only saves when it should. There's an example for this too in the Yii reference for CActiveForm (search for "To respond to the AJAX validation requests, we need the following class code: ").

Finally, you can programmatically set the validation status for any attribute with Javascript by calling $.fn.yiiactiveform.updateInput. If you do this it would be a good idea to keep imitating Yii by calling $.fn.yiiactiveform.updateSummary as well.

like image 74
Jon Avatar answered Nov 12 '22 18:11

Jon


I created the following javascript function, which I manually call when changing specific fields. It performs ajax validation on all form elements.

/**
 * @author marcovtwout
 * Force performing full ajax validation on given form.
 * @param Object $form jQuery form object
 */
performFullAjaxValidation = function($form){
    var settings = $form.data("settings");
    $.each(settings.attributes, function () {
        this.status = 2; // force ajax validation
    });
    $form.data("settings", settings);

    // trigger ajax validation
    $.fn.yiiactiveform.validate($form, function (data) {
        $.each(settings.attributes, function () {
            $.fn.yiiactiveform.updateInput(this, data, $form);
        });
        $.fn.yiiactiveform.updateSummary($form, data);
    });
}
like image 5
marcovtwout Avatar answered Nov 12 '22 18:11

marcovtwout