0

I have used jQuery Validate's handy addClassRules function to apply a rule to all elements of a given class rather than relying on the elements' name attribute values. In using the Angular wrapper of jQuery Validate, I've found that the addClassRules function is not supported out of the box. I tried modifying angular-validate.js to bring in this functionality, but no luck. The file is small, so I'll paste the whole thing, with my modification, below. Skip to the TL;DR at the end if you prefer.

angular-validate.js (with one modification)

(function (angular, $) {
    angular.module('ngValidate', [])

        .directive('ngValidate', function () {
            return {
                require: 'form',
                restrict: 'A',
                scope: {
                    ngValidate: '='
                },
                link: function (scope, element, attrs, form) {
                    var validator = element.validate(scope.ngValidate);
                    form.validate = function (options) {
                        var oldSettings = validator.settings;
                        validator.settings = $.extend(true, {}, validator.settings, options);
                        var valid = validator.form();
                        validator.settings = oldSettings; // Reset to old settings
                        return valid;
                    };
                    form.numberOfInvalids = function () {
                        return validator.numberOfInvalids();
                    };
                }
            };
        })

    .provider('$validator', function () {
        $.validator.setDefaults({
            onsubmit: false // to prevent validating twice
        });

        return {
            setDefaults: $.validator.setDefaults,
            addMethod: $.validator.addMethod,
            addClassRules: $.validator.addClassRules, /*<< this is the line I added >>*/
            setDefaultMessages: function (messages) {
                angular.extend($.validator.messages, messages);
            },
            format: $.validator.format,
            $get: function () {
                return {};
            }
        };
    });
}(angular, jQuery));

I only get an error if I actually try to invoke the addClassRules function in code. For example:

angular.module("PageModule", ['ngValidate'])
    .config(function($validatorProvider) {
        $validatorProvider.setDefaults({
            errorClass: "error custom-error-class" // this works fine
        })
        $validatorProvider.addMethod("customValidationMethod", function (value) {
                var isValid = false;
                // do stuff
                return isValid;
            }, "Bleh"
        ); // this works fine too
        $validatorProvider.addClassRules("emailField", {
            email: true
        }); // this crashes :(
    });

And the error is as follows:

Angular Validate error in Chrome JS console

Is there a way for me to use jQuery Validate's addClassRules function within its Angular implementation? What modification might I need to make? Or, is there a better way to apply validation rules to multiple elements on something other than the name attribute?

Sparky
  • 98,165
  • 25
  • 199
  • 285
Jacob Stamm
  • 1,660
  • 1
  • 29
  • 53

1 Answers1

1

I have used jQuery Validate's handy addClassRules function to apply a rule to all elements of a given class ...

That's not the issue the .addClassRules() method was meant to solve. It's used for combining multiple standard rules into a single "compound" rule that can be applied using one class name.


Or, is there a better way to apply validation rules to multiple elements on something other than the name attribute?

If you simply want to apply individual rules using class names, the plugin is smart enough to pick those up and no special techniques or methods are needed.

<input type="text" class="required email" name="foo" ...

By simply using the required and email classes, you have automatically applied the required and email rules to this field.

DEMO: jsfiddle.net/70g6brcf/


Alternatively, you can use HTML5 attributes and the plugin will apply rules accordingly.

<input type="email" required="required" name="foo" ...

DEMO: jsfiddle.net/70g6brcf/1/


NOTE: These are only alternative ways to apply rules. These methods do not negate the requirement to have a name attribute, which is mandatory when using jQuery Validate.

Sparky
  • 98,165
  • 25
  • 199
  • 285
  • Thanks for the info, you've given me a bit to look into. As for having to have a `name` attribute, why do you say that? In my case, I have dozens of `input` elements in the same form that need the same validation. I have no need of `name` attributes, and I certainly don't want to duplicate names. Besides, I'm posting the form using `$scope` model properties, not traditional posting. I've had no problem omitting `name` attributes in the past, even with jQuery Validate. As for applying individual rules using class names, I'll give that a go, but I don't like how invasive that is of the CSS. – Jacob Stamm Jan 18 '17 at 23:50
  • 1
    @JacobStamm, I don't recall saying it was ok to duplicate a `name` attribute. However, if you think you can use jQuery Validate without `name` attributes, try it: http://jsfiddle.net/zxhu17ja/ ~ Or just read the documentation: [*"Mandated: A 'name' attribute is required for all input elements needing validation, and the plugin will **not** work without this."*](https://jqueryvalidation.org/reference/#link-markup-recommendations) – Sparky Jan 19 '17 at 00:27
  • I know that I've gotten jQuery Validate to work fine without `name` attributes before, but you're right, the documentation is clear. I probably just got lucky in my implementation :) . About the resolution: I know the CSS classes would work fine, but I don't want accidental styles to get applied at some point, so I'm going with the `data-` attributes. I also got rid of my `addClassRules` stuff and am using my custom method, named "hours", directly, by putting `data-rule-hours="true"` on the elements. I also filled in some bs `name` values that are unique. Everything's working great :) – Jacob Stamm Jan 19 '17 at 00:49
  • @JacobStamm, you're welcome and I'm glad everything is resolved for now. However, lucky or not, it's impossible that you got this plugin working without `name` attributes. There are over 6000 SO questions tagged with jQuery Validate and [I've personally answered 25% of them](http://stackoverflow.com/search?q=user:594235%20[jquery-validate]%20is:answer)... the issue has been beaten to death. Otherwise, myself and others would be very interested in how you accomplished this. – Sparky Jan 19 '17 at 01:01
  • I'll take your word on that one. For all I know, my server-side HTML preprocessing was adding `name` attributes without me noticing on the client-side. – Jacob Stamm Jan 19 '17 at 01:06