Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I've got an AngularJS attribute directive, and I would like to take an action any time its parent input's value changes. Right now I'm doing it with jQuery:

angular.module("myDirective", [])
.directive("myDirective", function()
{
    return {
        restrict: "A",
        scope:
        {
            myDirective: "=myDirective"
        },
        link: function(scope, element, attrs)
        {
            element.keypress(function()
            {
                // do stuff
            });
        }
    };
});

Is there a way to do this without jQuery? I'm finding the keyPress event isn't doing exactly what I want it to, and while I'm sure I'll come up with a solution, I get a little nervous when I resort to using jQuery in an Angular project.

So what's the Angular way to do this?

share|improve this question

2 Answers 2

up vote 27 down vote accepted

There's a great example in the AngularJS docs here:

http://docs.angularjs.org/api/ng.directive:ngModel.NgModelController

It's very well commented and should get you pointed in the right direction.

A simple example, maybe more so what you're looking for is below:

http://jsfiddle.net/mb98y/

HTML

<div ng-app="myDirective" ng-controller="x">
    <input type="text" ng-model="test" my-directive>
</div>

JavaScript

angular.module('myDirective', [])
    .directive('myDirective', function () {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            scope.$watch(attrs.ngModel, function (v) {
                console.log('value changed, new value is: ' + v);
            });
        }
    };
});

function x($scope) {
    $scope.test = 'value here';
}

Edit Same thing, doesn't require ngModel (http://jsfiddle.net/mb98y/1/):

JavaScript:

angular.module('myDirective', [])
    .directive('myDirective', function () {
    return {
        restrict: 'A',
        scope: {
            myDirective: '='
        },
        link: function (scope, element, attrs) {
            // set the initial value of the textbox
            element.val(scope.myDirective);
            element.data('old-value', scope.myDirective);

            // detect outside changes and update our input
            scope.$watch('myDirective', function (val) {
                element.val(scope.myDirective);
            });

            // on blur, update the value in scope
            element.bind('propertychange keyup paste', function (blurEvent) {
                if (element.data('old-value') != element.val()) {
                    console.log('value changed, new value is: ' + element.val());
                    scope.$apply(function () {
                        scope.myDirective = element.val();
                        element.data('old-value', element.val());
                    });
                }
            });
        }
    };
});

function x($scope) {
    $scope.test = 'value here';
}
share|improve this answer
    
That could work. Any idea how to do it without requiring a model? I'd like to only add the directive. –  Mike Pateras Apr 30 '13 at 20:37
2  
If you want the directive to serve as ngModel, you can use isolate scope w/ a two-way binding, shown here: jsfiddle.net/langdonx/djtQR –  Langdon Apr 30 '13 at 20:40
    
I'm already using the directive, I'm afraid, but great suggestion. –  Mike Pateras Apr 30 '13 at 20:44
    
What you have there is great. If I could do that without requiring the model, it would be perfect. It's not a deal-breaker, but I'd love to not require the model, since I'm not actually using it for anything. Marking this as the answer, since it's pretty much what I want, but if you have any ideas on how I can drop the model, I'd be interested. Thank you very much for your help. –  Mike Pateras Apr 30 '13 at 20:51
    
What do mean already using the directive? I was suggesting that you modify your myDirective to act like the ngModelBlur directive in my example, which that doesn't require ngModel. –  Langdon Apr 30 '13 at 20:52

Since this must have an input element as a parent, you could just use

<input type="text" ng-model="foo" ng-change="myOnChangeFunction()">

Alternatively, you could use the ngModelController and add a function to $formatters, which executes functions on input change. See http://docs.angularjs.org/api/ng.directive:ngModel.NgModelController

.directive("myDirective", function() {
  return {
    restrict: 'A',
    require: 'ngModel',
    link: function(scope, element, attr, ngModel) {
      ngModel.$formatters.push(function(value) {
        // Do stuff here, and return the formatted value.
      });
  };
};
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.