0

I have a complex control (button clicks, dropdowns, etc) that builds a string. So every button click/dropdown selection calls a scope function that in turn updates a scope variable that holds my result.

I bind this scope variable to a hidden field in the UI:

<input type="hidden" ng-model="MyComplexString" custom-validation ng-value="MyComplexString" />

However, when the controller function updates MyComplexString, custom-validation isn't triggered.

I tried changing the input type to text, and indeed MyComplexString gets updated, however, custom-validation still doesn't fire.

If I type in the textbox however, custom-validation fires as expected.

Research shows that AngularJs listens for input events fired on DOM elements, but the controller function doesn't fire those events on the inputs bound to scope variables after changing the scope variables. So I need to do this manually.

I hope this makes sense. Any ideas would be appreciated.

EDIT = Adding the implementation of the validation directive (implementation only checks whether something starts with a 'comma'.

  .directive("customValidation", function() {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function(scope, ele, attrs, ctrl) {
            ctrl.$parsers.unshift(function(value) {
                var valid = false;
                if (value) {
                    // test and set the validity after update.
                    valid = value.charAt(0) == ',';
                    ctrl.$setValidity('customValFlag', valid);
                }
                return valid ? value : undefined;
            });
        }
    };
})
Brian Tompsett - 汤莱恩
  • 5,195
  • 62
  • 50
  • 120
bigbadwolf
  • 63
  • 1
  • 5
  • 1
    My first instinct is wondering if you could use a `$watch` and do validation there instead of binding to a hidden field? If you could provide your `custom-validation` directive that could help – brettvd Apr 16 '15 at 20:08
  • I added the directive to the main question. I wouldn't mind trying something like what you say; and I know I can drive the validation in my controller by setting a flag there, it's just feel like the wrong way about it. Plus, it's not reusable, should I ever need the same validation on a different field. – bigbadwolf Apr 16 '15 at 22:13

1 Answers1

0

Something you can do is to use a $watch within your directive so it is reusable. See the answer here

Essentially, within your link function you can $watch the attrs.ngModel, which catches any changes. Your link function would change to something like this:

link: function (scope, element, attrs) {
            scope.$watch(attrs.ngModel, function (newVal) {
                //Do custom validation here
            });
        }

See working JSFiddle I forked here with two simple inputs and a hidden input using the directive that writes every change to the console

Edit: You might want to check for newVal and oldVal being equal to ignore the initialization call, which would look like this:

link: function (scope, element, attrs) {
        scope.$watch(attrs.ngModel, function (newVal, oldVal) {
            if(newVal !== oldVal) {
                //Do custom validation here
            }
        });
    }
Community
  • 1
  • 1
brettvd
  • 476
  • 2
  • 5
  • Thanks! I'm still passing the control in the link function as I need to set the validity on it, but what you have here is exactly what I needed to move on. – bigbadwolf Apr 17 '15 at 03:04