Updating $scope between two controllers

angularjs, angularjs-scope, javascript

Solution

There are multiple ways available. The best should be chosen according to the relations between the scopes, if them are in different templates or modules, etc.

First of the ways is to create a mediator service which could store the necessary value. This mediator service could be injected anywhere it is needed - controllers, other services, directives.

Template 1 in module 1

<div ng-controller="Ctrl1">
  <input type="text" ng-model="val">{{ val }}
</div>

Controller 1 in module 1

app.controller('Ctrl1', ['$scope', 'ValMediator', function($scope, ValMediator) {
 $scope.val = '';

 $scope.$watch(
   function(){
     return ValMediator.getVal();
   },
   function(newVal){
     $scope.val = newVal;
   }
 );

 $scope.$watch('val',
   function(newVal){
     ValMediator.setVal(newVal);
   }
 );

}]);

Template 2 in module 2

<div ng-controller="Ctrl2">
  <input type="text" ng-model="val">{{ val }}
</div>  

Controller 2 in module 2

app.controller('Ctrl2', ['$scope', 'ValMediator',function($scope, ValMediator) {
  $scope.val = '';

  $scope.$watch(
    function(){
      return ValMediator.getVal();
    },
    function(newVal){
      $scope.val = newVal;
    }
  );

  $scope.$watch('val',
    function(newVal){
      ValMediator.setVal(newVal);
  }
 );

 }]);

Mediator service

app.factory('ValMediator', function() {
  var val = '';
  return {
    setVal: function(newVal){
      val = newVal;
    },
    getVal: function(){
      return val;
    }
  };
});

Please refer to this first jsBin example `ValMediator` is an example of such a service which stores the `val` variable inside and exposes getter and setter as a public interface. Other controllers could inject it and use. By using `$scope.$watch` on the service getter all the external changes are put into a local `$scope`. Watching the local `val` is used to publish local changes to other consumers via the mediator service.

=====================

Another way to it is to emit events through the `$rootScope`. I don't think this method should be used because it litters the `rootScope` with the events which aren't necessary. However it is a valid method of cross module/scope communication and should be take into account.

Please refer to second jsBin example

Here the role of the mediator is taken by the `$rootScope` service which is used just as a medium for event transportation. Templates are the same but controllers don't require nothing else then `$scope` and `$rootScope` for communication:

Controller 1 module 1

app.controller('Ctrl1', ['$scope', '$rootScope', function($scope, $rootScope) {
  $scope.val = '';

  $scope.$on('Val/update', function(e, arg){
    console.log('val update 1', arg);
    $scope.val = arg;
  });

  $scope.$watch('val',
    function(newVal, oldVal){
      if (newVal === oldVal) return;
      $rootScope.$broadcast('Val/update', newVal);
  }
);

}]);

Controller 2 module 2

app.controller('Ctrl2', ['$scope', '$rootScope',function($scope, $rootScope) {
  $scope.val = '';

  $scope.$on('Val/update', function(e, arg) {
    console.log('val update 2', arg);
    $scope.val = arg;
  });

  $scope.$watch('val',
    function(newVal, oldVal) {
      if (newVal === oldVal) return;
      $rootScope.$broadcast('Val/update', newVal);
    }
  );

}]);

That's it for the second example - just react to the change event and publish your own updates

Problem

It's very hard to explain but I will try, please keep that in mind. I'm building angularJS app and I'm having trouble getting the UI to update($scope). See layout here Has you can see there are 2 controllers and 3 different $scope at the same time. For example if I edit "Title" in the $scope3 the "Title" should change also in $scope2. What is the best way to monitor the changes, and transfer values between controllers and pass it into $scope.value or force new $resource call. I'm totally lost here.

Original source