angularjsangularjs-serviceangularjs-factoryangularjs-provider

How to make a service object that doesn't share its values with controllers that consume it


Let's suppose I create a factory, service, or provider object like so

myApp.factory('myService', function() {
  return {
    counter: 0,
    increment: function() {
      console.log('counter: ' + (this.counter++))
    }
  };
});

And suppose I have a controller that depends on it

myApp.controller('myCtrl', function(myService) {
  $scope.incr = function() {
    myService.increment();
  };
}

And I apply this controller in different parts of the html

<div ng-controller="myCtrl">
  <button ng-click="increment()">increment</button>
</div>
...
<div ng-controller="myCtrl">
  <button ng-click="increment()">increment</button>
</div>

Right now, when I click on each button, the counter is universal and it goes 0, 1, 2, 3, ...

How can I write my factory, service, or provider so that each controller gets a different copy of the service object?


Solution

  • Since factories are singletons you will need to use a method in your factory to create your service each time. Change your service to have a create method that returns your service that does the incrementing:

    myApp.factory('myService', function() {
      return {
        create: function () {
          return { 
            counter: 0,
            increment: function() {
              console.log('counter: ' + (this.counter++));
            }
          };
        }
      };
    });
    
    myApp.controller('myCtrl', function($scope, myService) {
      var service = myService.create();
      $scope.incr = function() {
        service.increment();
      };
    });
    

    Also the controller method name doesn't match up to what is in the view:

    <div ng-controller="myCtrl">
      <button ng-click="incr()">increment</button>
    </div>
    ...
    <div ng-controller="myCtrl">
      <button ng-click="incr()">increment</button>
    </div>
    

    Plunkr