Communication between controllers, angular method

I am trying to figure out a “preferred” or “angular -way” for sharing properties or states between controllers / directives. There are several ways to implement this, but I want to stick to best practices. Below are some commonplace examples of how this can be implemented:


1. Using $ scope. $ Watch

// The parent controller/scope
angular.module('myModule').controller('parentController', ['$scope', function($scope) {
    $scope.state = {
        myProperty: 'someState'; // Default value to be changed by some DOM element
    };
}]);

// The child controller/scope.
angular.module('myModule').controller('childController', ['$scope', function($scope) {
    $scope.$watch('state.myProperty', function (newVal) {
        // Do some action here on state change
    });
}]);

Edit: Based on the answers below, this is bad practice and should be avoided. It is not tested and places an unwanted DOM dependency.


2. Using $ broadcast

// The parent controller
angular.module('myModule').controller('parentController', ['$scope', function($scope) {
    var myProperty = 'someState';
    $scope.setState = function (state) {
        myProperty = state; // Set by some other controller action or DOM interaction.
        $scope.$broadcast('stateChanged', state); // Communicate changes to child controller
    }
}]);

// The child controller.
angular.module('myModule').controller('childController', ['$scope', function($scope) {
    $scope.$on('stateChanged', function (evt, state) {
        // Do some action here
    }
}]);

Edit: Bad practice, since you need to know the location of the controllers in the DOM in order to determine the weather for using $ broadcast (down the DOM) or $ emit (up the DOM).


3. Use of the service

angular.module('myModule').factory('stateContainer', [function () {
    var state = {
            myProperty: 'defaultState'
        },
        listeners = [];

    return {
        setState: function (newState) {
            state.myProperty = newState;
            angular.forEach(listeners, function (listener) {
                listener(newState);
            });
        },
        addListener: function (listener) {
            listeners.push(listener);
        }
    }
}]);

// The parent controller
angular.module('myModule').controller('parentController', ['$scope', 'stateContainer', function($scope, stateContainer) {
    $scope.setState = function (state) {
        stateContainer.setState(state);
    };
}]);

// The child controller.
angular.module('myModule').controller('childController', ['$scope', 'stateContainer', function($scope, stateContainer) {
    stateContainer.addListener(function (newState) {
        // Do some action here
    });
}]);

, , , . . , № 3 . Java jQuery, .

: . / , require. . , , ​​Angular.

+4
2

, , - AFAIK.

, ? Angular ( ), ? .

app.factory('stateService',function() {
  return {
     myState: "foo"
  }
})
.controller('one',function($scope,stateService) {
    $scope.changeState = function() {
      stateService.myState = $scope.state;
    };
})
.controller('two',function($scope,stateService) {
    $scope.svc = stateService;
})

():

<div ng-controller="one">
  <input name="state" ng-model="state"></input>
  <button type="submit" ng-click="changeState()">Submit</button>
</div>
<div ng-controller="two">{{svc.myState}}</div>

, , . ng-model , :

<div ng-controller="one">
  <input name="state" ng-model="svc.myState"></input>
</div>
<div ng-controller="two">{{svc.myState}}</div>

jsfiddle http://jsfiddle.net/cwt9L6vn/1/

+5

AngularJS , . , . , API .

DOM, . . , $broadcast $emit .

$broadcast , , , . , $rootScope.$broadcast(..), .

, , - , require .

var app = angular.modeul('myApp',[]);
// use a directive to define a parent controller
app.directive('parentDir',function() {
     return {
         controller: function($scope) {
             this.myFoo = function() {
                alert("Hello World");
             }
         }
     });
// use a directive to enforce parent-child relationship
app.directive('childDir',function() {
     return {
          require: '^parentDir',
          link: function($scope, $el, $attr, parentCtrl) {
             // call the parent controller
             parentCtrl.myFoo();
          }
     });

require .

  • Angular , .
  • .

$broadcast $emit.

, , API.

// this directive uses an API
app.directive('myDir',function() {
     return {
          scope: { 
            'foo': '&'
          },
          link: function($scope, $el, $attr) {
             // when needed, call the API
             $scope.foo();
          }
     });

 // in the template
 <div ng-controller="parentController">
     <div my-dir foo="parentController.callMyMethod();"></div>
 </div>
+2

All Articles