Watch controller model value from inside directive

36,732

Solution 1

$watch accepts the "name" of the property to watch in the scope, you're asking it to watch the value. Change it to watch attrs.ngModel which returns "bar", now you're watching scope.bar. You can get the value the same way you were or use scope[attrs.ngModel] which is like saying scope["bar"] which again, is the same as scope.bar.

scope.$watch(attrs.ngModel, function(newValue) {
    console.log("Changed to " + newValue);
});

To clarify user271996's comment: scope.$eval is used because you may pass object notation into the ng-model attribute. i.e. ng-model="someObj.someProperty" which won't work because scope["someObj.someProperty"] is not valid. scope.$eval is used to evaluate that string into an actual object so that scope["someObj.someProperty"] becomes scope.someObj.someProperty.

Solution 2

Wanted to add: in 1.2.x, with isolated scope, the above wont work. http://jsfiddle.net/TfTr5/23/

A workaround I came up with was using the fact that $watch also accepts a function, so you can access your controller using that.

scope.$watch(
    function(){return controller.$viewValue},
    function(newVal, oldVal){
        //code
    }
)

Working fiddle: http://jsfiddle.net/TfTr5/24/

If anyone has an alternative, I would gladly welcome it!

Solution 3

If you want to bind a value inside isolated scope,there are 2 ways to do it.The first way you can use even you don't have isolated scope.Here are the ways:

1) use $attrs.any_attribute and bind it (set in watch)

2) use 2 ways binding ('=') method and set it into listener

if you want more with examples here is a great article

http://www.w3docs.com/snippets/angularjs/bind-variable-inside-angularjs-directive-isolated-scope.html

Share:
36,732

Related videos on Youtube

Dustin
Author by

Dustin

Updated on March 03, 2020

Comments

  • Dustin
    Dustin over 4 years

    I am trying to have angular watch the $viewValue of a controller from inside a directive.

    fiddle: http://jsfiddle.net/dkrotts/TfTr5/5/

    function foo($scope, $timeout) {
        $scope.bar = "Lorem ipsum";
    
        $timeout(function() {
            $scope.bar = "Dolor sit amet";
        }, 2000);
    }
    
    myApp.directive('myDirective', function() {
        return {
            restrict: 'A',
            require: '?ngModel',
            link: function (scope, element, attrs, controller) {
                scope.$watch(controller.$viewValue, function() {
                    console.log("Changed to " + controller.$viewValue);
                });
            }
        } 
    });
    

    As is, the $watch function is not catching the model change done after 2 seconds from inside the controller. What am I missing?

  • Jonathan Rowny
    Jonathan Rowny over 11 years
    Working fiddle since SO no longer likes fiddles in the answer: jsfiddle.net/TfTr5/7
  • Mark Rajcok
    Mark Rajcok over 11 years
    I think as long as you include a code sample somewhere in your answer SO will allow the fiddle link.
  • honzajde
    honzajde about 11 years
    ok, except that there should be console.log("Changed to " + scope.$eval(attrs.ngModel));
  • sawe
    sawe over 10 years
    scope.$watch(attrs.ngModel, function(newValue) { console.log("Changed to " + newValue); });
  • Jonathan Rowny
    Jonathan Rowny over 10 years
    If the scope is isolated then you can't go watching things in the parent scope. This is just as hacky but I think a little clearer to understand: jsfiddle.net/TfTr5/25 basically just do the watch on the parent scope. If you require ngModel, and your scope is isolated, it should be safe. link: function (scope, element, attrs, controller) { scope.$parent.$watch(attrs.ngModel, function() { console.log("Changed to " + scope.$parent[attrs.ngModel]); }); } but in general i wouldn't isolate something that needs to watch $parent scope.
  • Jonathan Rowny
    Jonathan Rowny over 10 years
    Ha, yea that is simpler isn't it? I must have just been thinking based on the original question's example.
  • wlingke
    wlingke over 10 years
    I totally agree with you Johnathan. Your solution also works but correct me if I'm wrong, $viewValue isnt necessarily the same as the model value right? see here: jsfiddle.net/TfTr5/27 I believe if you are using angular's form validation, it doesn't update ngModel unless the $viewValue passes the validator. By the way, here's another solution that watches ngModel - but not $viewValue - that is a bit cleaner jsfiddle.net/TfTr5/26
  • Jonathan Rowny
    Jonathan Rowny over 10 years
    Yea, I forgot the original question was about the viewValue and if the scope is isolated then you can bi-diretionally bind ngModel which on the scope so your latest fiddle is good.
  • tanguy_k
    tanguy_k over 10 years
    @JonathanRowny please add an answer instead of commenting :)
  • Rafael Herscovici
    Rafael Herscovici about 5 years
    how is debounce related?