Search code examples
angularjsangularjs-directiveangularjs-service

AngularJS - view not updated when directive changes data in service


I'm using a directive to interact with a service and am encountering some trouble with the view showing the latest data.

I setup the following example. You can see that when a controller interacts with the Service, the view will update with the latest data. If you click the directive link, you can see in the console the data was changed but the view is not updated with that data.

http://jsfiddle.net/kisonay/pv8towqc/

What am I missing?

JavaScript:

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

app.factory('Service', function() {
  var Service = {};
  Service.data = {};
  Service.data.active = false;
  Service.data.one = {};
  Service.data.many = [];
  Service.changeActive = function(state) {
    state = state || false;
    Service.data.active = state;
  };
  Service.setOne = function(one) {
    Service.data.one = one;
  };
  Service.setMany = function(many) {
    Service.data.many = many;
  };
  return Service;
});

app.directive('launcher', function(Service) {
  return {
    restrict: "A",
    link: function(scope, elem, attrs) {
      elem.bind('click', function(event) {
        if (Service.data.active) {
          Service.changeActive(false);
        } else {
          Service.changeActive(true);
        }
        console.log(Service.data); // shows data changed
      });
    }
  };
});

function Ctrl1($scope, Service) {
  $scope.ServiceData = Service.data;
}

function Ctrl2($scope, Service) {
  $scope.active = function() {
    Service.changeActive(true);
  };
  $scope.inactive = function() {
    Service.changeActive(false);
  };
}

HTML

<div ng-controller="Ctrl1">
  {{ServiceData}}
</div>

<hr />

<div ng-controller="Ctrl2">
  Directive: <a href="#" launcher>Change</a>
  <hr /> Controller:

  <button ng-click="active()">
    Active
    </button>
  <button ng-click="inactive()">
    Inactive
    </button>
</div>

Solution

  • Your event listener executes but Angular doesn't know anything about it, so it doesn't know it has to detect changes.

    Add scope.$apply(); at the evn of the click listener, and it will work as expected.