2

I have service methods,

 var selectedType = 0;
 .........
 .........
 return {
            updateType: function (type) {
                return selectedType = type;
            },

            getType: function () {
                return selectedType;
            }
        }

I want to share this selectedType variable across 2 controllers. So calling the updateType method from one controller and opening a new popup page where I am calling the getType method.

Issue is, the getType method always returning 0 in popup page, but the value assigned from main page is 2 (by calling updateType method).

Main page,

angular.module('Controller1Module', [])
.controller('myController1', ['$scope', 'myService',
 function ($scope, myService) {
  myService.updateType(1);
 $scope.$watch(myService.getType , function(newValue, oldValue){                
            $scope.selectedType = myService.getType();                
        });
}

Popup Controller,

angular.module('Controller2Module', [])
.controller('myController', ['$scope', 'myService',
 function ($scope, myService) {

   $scope.$watch(myService.getType , function(newValue, oldValue){                
            $scope.selectedType = myService.getType();                
        });
}

My Service,

angular.module('serviceModule', [])
 .service('myService', ['$rootScope',
  function($rootScope){
     var selectedType = 0;

       return {
               updateType: function (type) {
                return selectedType = type;
            },

            getType: function () {
                return selectedType;
            }
    ]);
5
  • Are you sure that updateType is called before getType? Commented May 8, 2015 at 9:10
  • 1
    Your code should work. I used like this many a times. Please replace ` var selectedType = 0;` with ` var selectedType;'. Please put ur code in fiddle & post please ` Commented May 8, 2015 at 9:43
  • 1
    Will it be a problem if my controllers are in different modules?
    – Nic
    Commented May 8, 2015 at 10:00
  • @VeeraBhadra I have updated my code, can you please check and provide your input?
    – Nic
    Commented May 11, 2015 at 8:42
  • @Nic Yes Nic. Please use a module. If you wanna use different modules inject & use. Commented May 14, 2015 at 5:53

2 Answers 2

1

Here's an example using $scope.$watch to see changes in myService.getType(). This particular implementation uses watches because the value returned by myService.getType() is a string (which is a value), instead of an object (which returns a reference) - any change in the service's selectedType property will not automatically be noticed by the scope in your controllers, since they've only received a value of what was in the service at the time getType() was called.

(function() {
  angular.module('myApp', [])
    .controller('Controller1', ['$scope', 'myService', Controller1])
    .controller('Controller2', ['$scope', 'myService', Controller2])
    .service('myService', ['$log', myService]);

  function Controller1($scope, myService) {
    $scope.$watch(
      myService.getType,
      function(newValue, oldValue) {
        $scope.selectedType = myService.getType();
      }
    );
    $scope.updateType = myService.updateType;
  }

  function Controller2($scope, myService) {
    $scope.$watch(
      myService.getType, //watch the service get function for changes in return value, then update local scope
      function(newValue, oldValue) {
        $scope.selectedType = myService.getType();
      }
    );
  }

  function myService($log) {
    var _selectedType = 0;

    function _updateType(type) {
      $log.log("updateType: " + type);
      return _selectedType = type;
    }

    function _getType() {
      $log.log("getType: " + _selectedType);
      return _selectedType;
    }

    return {
      updateType: _updateType,
      getType: _getType
    }
  }
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.28/angular.min.js"></script>
<div ng-app="myApp">
  <div ng-controller="Controller1">
    <div>
      <input ng-model="newType" />
      <button ng-click="updateType(newType)">Update type</button>
    </div>
    Selected type in Controller 1: {{selectedType}}
  </div>
  <div ng-controller="Controller2">
    Selected type in Controller 2: {{selectedType}}
  </div>
</div>

Alternatively, consider the following (I've also demonstrated multiple modules sharing, as I noticed this possible requirement in a comment of yours):

(function() {
  "use strict";
  
  // define a services module that can be listed as a dependency of other modules
  angular.module('myApp.services', [])
    .service('myService', ['$log', myService]);

  //here we show the module containing our controller depends on the module with the service
  angular.module('module1', ['myApp.services']) 
    .controller('Controller1', ['$scope', 'myService', Controller1]);

  angular.module('module2', ['myApp.services'])
    .controller('Controller2', ['$scope', 'myService', Controller2]);

  // this is the module being used by ng-app='myApp' to tie it all together
  // note that since the controller modules already specify their dependence on the services module,
  // we don't need to list it again here.
  angular.module('myApp', ['module1', 'module2']);

  function Controller1($scope, myService) {
    $scope.data = myService.getData(); // we pass the whole object, and scope binding expressions have a '.' in them: {{data.selectedType}}
    $scope.updateType = myService.updateType;
  }

  function Controller2($scope, myService) {
    $scope.data = myService.getData();
  }

  function myService($log) {
    var _data = {
      selectedType: 0
    };

    function _updateType(type) {
      $log.log("updateType: " + type);

      _data.selectedType = type;
    }

    function _getData() {
      $log.log("getData called:");
      $log.log(_data);

      return _data;
    }

    return {
      updateType: _updateType,
      getData: _getData
    }
  }
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.28/angular.min.js"></script>
<div ng-app="myApp">
  <div ng-controller="Controller1">
    <div>
      <input ng-model="newType" />
      <button ng-click="updateType(newType)">Update type</button>
    </div>
    Selected type in Controller 1: {{data.selectedType}}
  </div>
  <hr />
  <div ng-controller="Controller2">
    <div>
      <input ng-model="data.selectedType" /> &lt;- 2-way binding, no separate update function needed
    </div>
    Selected type in Controller 2: {{data.selectedType}}
  </div>
</div>

In the above example, we're returning an object from the service. Since objects are passed by reference, changes to its properties within the service can be seen by any controller holding a reference to it. This makes 2-way binding pretty easy.

Just remember that if you replace the object in the service instead of just updating its properties, you'll break the references the controllers have on it (well, really, the controllers will be maintaining a reference to the old object, but your service will be containing a new one). In this case, helper functions like angular.extend and/or angular.copy can make it pretty easy to update any objects in your service with data from properties of objects returned by REST API calls, without replacing the object entirely (thus avoiding breaking references).

3
  • 1
    Thanks for your answers!!! I tried with your first example which is using watch. controller1 is my main page and controller2 is popup page which will open when clicking a button in main page. am injecting the service into both controllers, from controller1 am updating the selectedType variable in service and retrieving this variable value in watch as you mentioned. but still am updating with 1 from controller1 and the value retrieved in controller2 is 0 always.
    – Nic
    Commented May 11, 2015 at 6:51
  • Happy to help! Will try and investigate further and update mine as soon as I can get the chance. I'm assuming from your comment on another answer that you're unable to modify the service, and so the second example is not an option? Often the issue is related to this: stackoverflow.com/questions/30126743/…
    – JcT
    Commented May 11, 2015 at 15:32
  • I need to watch this selectedtype value, if value of this variable changed then should pick that new value to process the further methods.
    – Nic
    Commented May 12, 2015 at 11:40
0

I recommend creating a DataRepo service which holds all the data you need across the entire page. Then you can access the same data in all your controllers by injecting this service:

myApp.factory('DataRepo', function() { 

    var defaultState = {
        selectedType: 1
    };

    return {
        state: angular.copy(defaultState)
    };
});

Fiddle

2
  • I should use this existing service.
    – Nic
    Commented May 8, 2015 at 9:33
  • well then refactor the existing service :)
    – DonJuwe
    Commented May 8, 2015 at 9:37

Not the answer you're looking for? Browse other questions tagged or ask your own question.