Problem/Motivation

Currently the Field Validation (field_validation) integration is by default limited to those validations known to clientside_validation_field_validation_regular().
This is great since those validations ensure that whatever can be done on the client side is done there.
However it would be nice to be able to run more complex validations using the remote validation functionality that's shipped with jQuery.validate.
There already examples for "remote" validations e.g. drupalURL / phone / captcha. Although those validations use synchronous (blocking) ajax calls which can lead to bad user experience.

Proposed resolution

The attached patch contains:

  • Generic remote validation integration for any Field Validation rule.

    If a rule can't be re-created on the client side the validation method fieldValidationAjax is used - all Field Validation rules are collected and executed at once.
    The ajax callback is done using jQuery.validator.methods.remote(), this ensures maximum compatibility with jQuery.validator and is a non-blocking (async) approach. Further this ensures we'll have context specific error messages.
    The integration is as generic as possible, however further testing is needed to see if there are any uncovered scenarios.
  • Generic integration with High-performance JavaScript callback handler. The code does it's best to handle dependencies to be able use the JS callback.
  • Enhanced the ajax handling for the remote validation. Supports now progress (throbber) and works around some quircks with the success handler of jquery.validation
  • Integration with Drupal.states.Trigger.states, which means you can now use #states to write something like this:
    $form['email_retype'] = array(
        '#type' => 'textfield',
        '#states' => array(
          // Hide the email re-type field as long as the email field hasn't valid data.
          'invisible' => array(
           ':input[name="email"]' => array('clientside_validation' => FALSE),
          ),
        ),
      );
    

    This is globally available and independent from "Field Validation". Available states are:

    • clientside_validation (!clientside_validation): TRUE on initialization. Set once the validation is run
    • clientside_validated (!clientside_validated): FALSE on initialization. TRUE if the validation is done, reset to FALSE as soon as the value is changed.
  • Integrate with Conditional Fields - which means you can now configure the #states in the Field UI!

Remaining tasks

Reviews needed.

User interface changes

None.

API changes

If someone already uses hook_clientside_validation_rule_alter() the new implementation might duplicate or interfere with that custom validation.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

das-peter’s picture

Oh, something was very wrong with the first patch :(
However, here's the follow up.
This brings:

  • Enhanced the ajax handling for the remote validation. Supports now progress (throbber) and works around some quircks with the success handler of jquery.validation
  • The ajax enhancement allows us to properly integrate with Drupal.states.Trigger.states, which means you can now use #states to write something like this:
    $form['email_retype'] = array(
        '#type' => 'textfield',
        '#states' => array(
          // Hide the email re-type field as long as the email field hasn't valid data.
          'invisible' => array(
           ':input[name="email"]' => array('clientside_validation' => FALSE),
          ),
        ),
      );
    

    This is globally available and independent from "Field Validation"

  • Finally the above enhancements allow us to integrate with Conditional Fields - which means you can now configure the #states in the Field UI!
das-peter’s picture

Next patch with some enhancements for the JS integration.
Hope I'm able to save a bit time by doing this. Performance is a hard requirement here.

das-peter’s picture

Enhanced the configurability of the integration with the JS module. Adjusting just the dependencies might not be enough. So now modules are able to alter the whole definition.
Also added the missing clientside_validation_field_validation.api.php for the new hook.

das-peter’s picture

das-peter’s picture

Updated patch.
New stuff:

  • Enhanced ajax handling - the remote call is just executed if the value was changed. (Basically restored a broken jQuery.validate feature.)
  • Added new states:
    • clientside_validation (!clientside_validation): TRUE on initialization. Set once the validation is run
    • clientside_validated (!clientside_validated): FALSE on initialization. TRUE if the validation is done, reset to FALSE as soon as the value is changed.
das-peter’s picture

Made states integration more defensive. clientside_validation.js is loaded sometimes on pages where Drupal.states isn't available.

das-peter’s picture

Updated JS integration. Switched to JS 2.x due to security reasons. This also helped to decrease the code needed as JS 2.x brings some required alter hooks I was adding here.
All in all less code is needed to get the same functionality :)
The JS integration still is optional, so no dependency there.

  • Jelle_S committed 991bd08 on 7.x-1.x authored by das-peter
    Issue #2413877 by das-peter: Enhance Field Validation integration using...
Jelle_S’s picture

Version: 7.x-1.x-dev » 7.x-2.x-dev
Status: Needs review » Needs work

Fixed in latest dev (1.x). Thanks for the patch! Any chance you'd want to do something similar for 2.x?

das-peter’s picture

Holy freaking cow! I didn't expect that this goes in so smooth :)
Thank you so much!
Hmm, about the 2.x stuff, I'd like to - but it's unlikely that I'll find time in near future. All this work was done for a customer project, which will take at least until August and absorbs almost all of my work-time.

cravecode’s picture

Is there any way to get an example of how to use this? I'm currently trying to implement a "remote" validation rule for a custom webform component. Thanks!

mibfire’s picture

@das-peter could you privide us an exmaple? and thx your great work!

skadu’s picture

Hi there, how does this handle validation configurations that require multiple fields? I have an "emails must match" rule that was working until the latest version of this module (7.x-1.42). The ajax validation seems to only ever send one value to the server for validation, which (AFAIK) means that rules depending on multiple values will always fail.

Am I going crazy? Or is this a real issue?

Had a bit more time to look into this. Any rule that is not matched in the function clientside_validation_field_validation_regular is sent through via AJAX (instead of being ignored on the client side), as mentioned in the proposed resolution section.

If a rule can't be re-created on the client side the validation method fieldValidationAjax is used - all Field Validation rules are collected and executed at once.

The problem with this approach is that certain Field_Validation rules use groups of fields to perform their validation (Equal Values on Multiple Fields, Unique Values, etc...). In these cases, the AJAX validation kicks in and attempts to validate against nothing (since the AJAX request only sends the value of the current field being validated.

The old way this worked, is the client side validation just failed silently and then during server side processing, the validator kicked in. Currently, this AJAX validation causes any field with group based validation to fail, every single time.

I am about to be away from my computer for several days, so I can't offer a solution yet, but I would imagine there should be some sort of exclude for rules that use group based validation as a short term solution.

Jelle_S’s picture

Version: 7.x-2.x-dev » 7.x-1.x-dev