1
votes

I've got a directive that shares data with its controller, which I'm doing with an isolate scope.

However, when I update the data from inside the directive, neither the directive nor the controller sees the data change using $watch.

Here's an example of what I'm trying to do:

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

app.controller('myAppCtrl', function($scope) {
  $scope.buttonSettings = {
    val: 0
  }

  $scope.$watch('buttonSettings.val', function(val) {
    console.log('watchInController')
    console.log(val)
  });
});

app.directive('buttonTest', function() {
  return {
    restrict: 'E',
    scope: {
      buttonSettings: '='
    },
    template: '<button>{{buttonSettings.val}}</button>',
    link: function(scope) {
      var button = $('button');

      console.log(scope.buttonSettings)

      scope.$watch('buttonSettings.val', function(val) {
        console.log('watchInDirective')
        console.log(val)
      });

      button.bind('mouseover', function() {
        scope.buttonSettings.val++;
        console.log('mouseover')
        console.log(scope.buttonSettings.val)
      })
    }
  }
});

And here's the full example in plunkr: http://plnkr.co/edit/lnztoMhtU03Qzl0BaMpk?p=preview

What am I doing wrong?

2

2 Answers

1
votes

First of all, you should not use jQuery that way. Instead of selecting button with jQuery, you can just inject it to your directive using element parameter.

Second, you need to use $scope.$apply to trigger watches in your directive and controller.

app.directive('buttonTest', function() {
  return {
    scope: {
      buttonSettings: '='
    },
    link: function(scope, element) {
      element.bind('mouseover', function() {
        scope.$apply(function() {
          scope.buttonSettings.val++;
        });
      })
    }
  }
});

Check out this working plunker.

1
votes

halilb is correct that you should not be using jQuery to select element, but instead use the element that Angular provides to your directive, and that $scope.$apply is needed in order to register events that occur outside of Angular's context. However, you don't at all need to make a new directive to solve your problem here. Just use Angular's ngMouseover directive. You can bind a function to it or just add your logic directly in. Here's a very minimal, simple example.

<div ng-init="foo = 1">Value: {{foo}}</div>
<button ng-mouseover="foo = foo+1">Mouse over this: {{foo}}</button>

Here's how the same code looks with the logic moved to the controller:

<div>Value: {{foo}}</div>
<button ng-mouseover="incrementFoo()">Mouse over this: {{foo}}</button>

controller:

$scope.foo = 1;
$scope.incrementFoo = function() {
  ++$scope.foo;
};

Live demo