3
votes

I have two controller which injected one service and one factory. As per my knowledge if we change in Service data, It should reflected in whole application but this should not with factory.

My Requirements

For Service:

Service is singleton so if I made changes in Service object that should reflect through out application.

For Factory:

Factory is just function which return something, if I made changes in factory object that it should reflect only current instance not to whole application

I have create an application where I have used two different controller which injected with same service and factory which have two properties.

When I am changing the service property, it is not going to update in other controller.

Following is the code on Plunker.

Can anyone help on this and provide the code where service will reflect the data but factory not. thanks

(function() {
  'use strict';

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

  app.factory('MyFactory', function() {
    var myFactory = {};

    myFactory.myProperty = { myText: 'Hello' };
    myFactory.setProperty = function(value) {
      this.myProperty.myText = value;
    };
    return myFactory;
  });

  app.service('MyService', function() {
    this.myProperty = { myText: 'Test'} ;
    this.setProperty = function(value) {
      this.myProperty.myText = value;
    }
  });

  app.controller('DummyController', DummyController);
  DummyController.$Inject = ['$scope', 'MyFactory', 'MyService'];

  app.controller('Dummy1Controller', Dummy1Controller);
  Dummy1Controller.$Inject = ['$scope', 'MyFactory', 'MyService'];



  function DummyController($scope, MyFactory, MyService) {
    $scope.property = MyFactory.myProperty;
    $scope.property1 = MyService.myProperty;

  }

  function Dummy1Controller($scope, MyFactory, MyService) {
    MyFactory.setProperty('World1144');
    $scope.property = MyFactory.myProperty;

    MyService.setProperty('World1144');
    $scope.property1 = MyService.myProperty;
  }
})();

and relevant part of HTML

<div class="panel-body">
  <div ng-controller='DummyController' class='col-md-6'>
    <form class="form-inline" role="form">
      DummyController
      <div>
        Current Factory Value :
        <input type='text' ng-model='property.myText'>
        <br> Current Service Value :
        <input type='text' ng-model='property1.myText'>

      </div>
    </form>
  </div>
  <hr>
  <div ng-controller='Dummy1Controller' class='col-md-6'>
    <form class="form-inline" role="form">
      Dummy1Controller
      <div>
        Current Factory Value :
        <input type='text' ng-model='property.myText'>
        <br> Current Service Value :
        <input type='text' ng-model='property1.myText'>
      </div>
    </form>
  </div>
</div>
2
Plunkers are always helpful for reproducing the issue, but the core code that demonstrates the problem must still be added to the question directly. In addition, please do not work around the external code link filter. - David L

2 Answers

2
votes

The problem is that you're binding against plain strings, and in javascript these assignments (the ones you made in the controllers) are made by value, not by reference. To fix your problem, use an object in your service instead.

See this forked plunkr which work as you were expecting.

The changes are

In Javascript

I defined your factory and service to use an object. Then you can bind this object in your controllers, just like before.

app.factory('MyFactory', function() {
    var myFactory = {};

    myFactory.myProperty = { myText: 'Hello' };
    myFactory.setProperty = function(value) {
      this.myProperty.myText = value;
    };
    return myFactory;
  });

  app.service('MyService', function() {
    this.myProperty = { myText: 'Test'} ;
    this.setProperty = function(value) {
      this.myProperty.myText = value;
    }
  });

See that now, you expose an object, rather than a plain string. Probably now the setter is useless, since you can update the object directly. You can leave it if you want to add some extra logic or validation.

In HTML

I updated the ng-model binds

<div>
  Current Factory Value :
  <input type='text' ng-model='property.myText'>
  <br> Current Service Value :
  <input type='text' ng-model='property1.myText'>
</div>
1
votes

if we change in Service data, It should reflected in whole application but this should not with factory.

the factory part is not correct.

factory in angular is more powerful than a service but most of the time what you do with a factory is already covered by a service.

this is the main difference.

a service is a singleton, the function that you pass to the service is treated as a constructor, Angular instanciate the object then cached and return it, every time you request that service angular inject the SAME instance.

a factory it's a function, the first time it's injected angular invoke that function and cache the result. as a function you could made it return an instance or a function itself. if you return an instance you will have the same exact pattern as a service, while if you return a function (constructor) you can construct multiple instance.

Back to your plnkr, and the incriminate part.

here:

app.service('MyService', function() {
  this.myProperty = 'Test';
  this.setProperty = function(value) {
    this.myProperty = value;
  }
});

function DummyController($scope, MyFactory, MyService) {
    $scope.property = MyFactory.myProperty;
    $scope.property1 = MyService.myProperty;

  }

myProperty is a string and as all the primitive types it will be copied in the first assignment, it's not a reference, that means thare's no binding with the original value, a solutions would be wrap it inside an object. Same for the factory.

Working plnkr: http://plnkr.co/edit/rQvzjfB0YO4peulimivc?p=preview