5

From this stackoverflow question, my understanding is that I should be using services to pass data between controllers.

However, as seen in my example JSFiddle, I am having trouble listening to changes to my service when it is modified across controllers.

angular.module('myApp', [])
    .controller('Ctrl1', function ($scope, App) {
        $scope.status = App.data.status;
        $scope.$watch('App.data.status', function() {
            $scope.status = App.data.status;
        });
})
    .controller('Ctrl2', function ($scope, App) {
        $scope.status = App.data.status;
        $scope.$watch('status', function() {
            App.data.status = $scope.status;
        });
})
    .service('App', function () {
        this.data = {};
        this.data.status = 'Good';
});

In my example, I am trying to subscribe to App.data.status in Ctrl1, and I am trying to publish data from Ctrl1 to App. However, if you try to change the input box in the div associated with Ctrl2, the text does not change across the controller boundary across to Ctrl1.

Community
  • 1
  • 1
user1027169
  • 2,627
  • 3
  • 27
  • 50

2 Answers2

10

http://jsfiddle.net/VP4d5/2/

Here's an updated fiddle. Basically if you're going to share the same data object between two controllers from a service you just need to use an object of some sort aside from a string or javascript primitive. In this case I'm just using a regular Object {} to share the data between the two controllers.

The JS

angular.module('myApp', [])
    .controller('Ctrl1', function ($scope, App) {
        $scope.localData1 = App.data;
})
    .controller('Ctrl2', function ($scope, App) {
        $scope.localData2 = App.data;
})
    .service('App', function () {
        this.data = {status:'Good'};
});

The HTML

<div ng-controller="Ctrl1">
    <div> Ctrl1 Status is: {{status}}
    </div>
    <div>
        <input type="text" ng-model="localData1.status" />
    </div>
<div ng-controller="Ctrl2">Ctrl2 Status is: {{status}}
    <div>
        <input type="text" ng-model="localData2.status" />
    </div>
</div>

Nothing wrong with using a service here but if the only purpose is to have a shared object across the app then I think using .value makes a bit more sense. If this service will have functions for interacting with endpoints and the data be sure to use angular.copy to update the object properties instead of using = which will replace the service's local reference but won't be reflected in the controllers.

http://jsfiddle.net/VP4d5/3/

The modified JS using .value

angular.module('myApp', [])
    .controller('Ctrl1', function ($scope, sharedObject) {
        $scope.localData1 = sharedObject;
})
    .controller('Ctrl2', function ($scope, sharedObject) {
        $scope.localData2 = sharedObject;
})
.value("sharedObject", {status:'Awesome'});
shaunhusain
  • 19,630
  • 4
  • 38
  • 51
  • Thanks! This is helpful... however, I am still having the issue where if the service variable is updated, the controller doesn't know about it. See this updated fiddle: http://jsfiddle.net/VP4d5/4/. After a timeout, the service variable is updated, the controllers won't know to update until I click on the div (I added an ng-click). – user1027169 Dec 10 '13 at 21:17
  • If you are using something async outside of angular you need to call $apply to cause angular to run the digest cycle, if you really just want a timeout you can use $timeout service which will do the call to $apply for you, alternatively I have an example here where I injected the $rootScope, and it seems calling $apply() on that is good enough http://jsfiddle.net/VP4d5/5/ Basically $http $timeout and other angular services automatically do this for you but in some cases you need to integrate third party stuff then calling $apply yourself is necessary to trigger an update. – shaunhusain Dec 11 '13 at 00:07
  • Thanks for angular.copy – maxbeaudoin Jul 19 '17 at 14:54
6

I agree with @shaunhusain, but I think that you would be better off using a factory instead of a service:

angular.module('myApp', [])
    .controller('Ctrl1', function ($scope, App) {
        $scope.localData1 = App.data;
    })
    .controller('Ctrl2', function ($scope, App) {
        $scope.localData2 = App.data;
    })
    .factory('App', function () {
        var sharedObj = {
            data : {
                status: 'Good'
            }
        };

        return sharedObj;
    });

Here are some information that might help you understand the differences between a factory and a service: When creating service method what's the difference between module.service and module.factory

Community
  • 1
  • 1
gion_13
  • 41,171
  • 10
  • 96
  • 108