12

I'm missing something obvious here. In my directive I have a working two-way data binding however I can't seem to use $scope.$watch() to monitor changes which may occur on the directive's parent scope js object.

http://jsfiddle.net/Kzwu7/6/

As you can see, when I try to use $watch on attrs.dirModel the resulting value is undefined and nothing is further watched, even though I'm modifying the object after a brief delay. I've also tried using (and not using) the true flag on the $watch statement.

HTML:

<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.min.js"></script>

<div ng-app="test" ng-controller="MainCtrl">
    <dir dir-model="model"></dir>
    <p>{{model.tbdTwoWayPropA}}</p>
</div>

<script type="text/ng-template" id="template">
    <div class="test-el">{{dirModel.tbdTwoWayPropB}}</div>
</script>

JS:

var app = angular.module('test', []);

app.controller("MainCtrl", [
    "$scope", "$timeout",
    function($scope, $timeout){
        $scope.model = {
            tbdTwoWayPropA: undefined,
            tbdTwoWayPropB: undefined,
            tbdTwoWayPropC: undefined
        }

        // TBD Ajax call
        $timeout(function(){

            // alert("Model updated, but $scope.$watch isn't seeing it.");

            $scope.model.tbdTwoWayPropA = 1;
            $scope.model.tbdTwoWayPropB = 30;
            $scope.model.tbdTwoWayPropC = [{ a: 1 },{ a: 2 },{ a: 3 }];

        }, 2000)
    }
]);

app.directive('dir', [
  "$timeout",
  function($timeout) {
      return {
          restrict: "E",
          controller: function($scope){
              $scope.modifyTwoWayBindings = function(){

                  // Two-way bind works
                  $scope.dirModel.tbdTwoWayPropA = 2;
              }

              $timeout(function(){
                  $scope.modifyTwoWayBindings();
              }, 4000);
          },
          scope: {
              dirModel: '='
          },
          template: $("#template").html(),
          replace: true,
          link: function($scope, element, attrs) { 

            $scope.$watch( attrs.dirModel, handleModelUpdate, true);

              // alert(attrs.dirModel);

              function handleModelUpdate(newModel, oldModel, $scope) {
                  alert('Trying to watch mutations on the parent js object: ' + newModel);
              }
          }
      }
}]);
BradGreens
  • 1,357
  • 4
  • 15
  • 31

1 Answers1

19

Since you are using '=', you have a local directive scope property dirModel. Just $watch that:

$scope.$watch('dirModel', handleModelUpdate, true);
Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • Thank you. Do you happen to know a good resource to learn more about the "local directive scope property". Previously I have only see examples accessing the attributes argument. Final JS fiddle for users reference. http://jsfiddle.net/Kzwu7/8/ – BradGreens Mar 11 '13 at 18:15
  • @BradGreens, well, it is mentioned on the not-so-easy-to-understand [directives page](http://docs.angularjs.org/guide/directive) under the "Directive Definition Object" section. Also see http://stackoverflow.com/questions/14050195/what-is-the-difference-between-and-in-directive-scope/14063373#14063373, http://stackoverflow.com/questions/14908133/what-is-the-difference-between-vs-and-in-angularjs, and http://stackoverflow.com/questions/14049480/what-are-the-nuances-of-scope-prototypal-prototypical-inheritance-in-angularjs/14049482#14049482 (see section "directives" near the bottom). – Mark Rajcok Mar 11 '13 at 18:29
  • I've read it many times ;). I think now I'm specifically interested in learning exactly what angular methods will accept this string representation of the attribute as a parameter. i.e., $observe('attr', fct), $set('attr','val'), $watch('attr', fct) etc... The string representation is kind of magical. – BradGreens Mar 11 '13 at 18:58
  • 5
    $watch is a method defined on [Scope](http://docs.angularjs.org/api/ng.$rootScope.Scope#$watch). If the first argument to $watch is a string, is evaluated against the scope (in this case, the directive's isolate scope). $watch doesn't watch/observe attributes, it can only watch/observe scope properties (or it can be given a function to "watch"). $observe() and $set are methods on the Attributes object, so they can only watch/observe/set attribute values (using the normalized attribute names). – Mark Rajcok Mar 11 '13 at 19:14