3

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>
Mukesh Kumar
  • 2,354
  • 4
  • 26
  • 37
  • 1
    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 Apr 24 '17 at 15:38

2 Answers2

2

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>
Gonzalo.-
  • 12,512
  • 5
  • 50
  • 82
  • For service, it looks good but factory does not share their instance so how it is updating in second controller, it should not change in second controller data when I change in first controller. – Mukesh Kumar Apr 25 '17 at 05:38
  • all services in angular js are functions. Since you return a value in your factory, it provides you the same functionality that a service - it is the same instance. You can look at the plunkr how it is the same object in both controllers. You can also place a debugger inside the factory function - only once is executed. If you want. Check this answer http://stackoverflow.com/a/15666049/1437934 to understand the differences – Gonzalo.- Apr 25 '17 at 12:24
1

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

Karim
  • 8,454
  • 3
  • 25
  • 33