I came across something similar in the past and looked at four possible approaches:
- Using
$broadcast - Saving
$rootScope - Observer pattern (as you are here)
- Using
$watch from the controller
Here are my thoughts on every occasion:
$ broadcast
In the AngularJS view, I saw that Mishko Hevery talked about using $broadcast (i.e. events) and use cases for this. The bottom line is that $broadcast more designed to respond to events that are not closely related to what you are working with, otherwise an alternative is most likely preferable. Also on this subject, the Best Practices guide in the angular wiki recommends:
Use only $ broadcast () ,. $ emit () and. $ on () for atomic events: Events that are applicable globally throughout the application (for example, user authentication or application closure).
Here, since you have settings that are closely related to what ng-view fills, this suggests that it is preferable to use $broadcast .
$ rootScope
This is the global state that you mention (and want to avoid). I was not / am not my personal preference to either open the settings for my entire application, despite the fact that this was often a simple option. I personally reserved $rootScope for configuration settings and soft variables such as page name, etc. I would not decide to use this option.
Observer Pattern
Registering factory callbacks is a robust approach. As for your persistent callbacks, you can listen for the $destroy event in the scope by calling the remove method on your Factory Configuration to remove the callback. This can be considered a good example of using $broadcast ; the controller refers to the event and must respond to it, but the event itself does not apply to data common to the controllers / configuration service.
$ watch
Using a common service, it can be entered into any controller that matches the settings. Right now, any change to config will trigger your callback when perhaps some views may concern only one or two configuration parameters. $watch will make it easier for you to watch changes for these attributes only. I canβt talk with the overhead and register callbacks, but for me it seems like the most βangularβ one.
Here's how to do it with $watch :
var app = angular.module("myApp",[]); app.factory("Configuration",function(){ var data = { settingOne: true, settingTwo: false }; return data; }) app.controller("SettingsCtrl",function($scope, Configuration){ // do something }) app.controller("HomeCtrl",function($scope, Configuration){ // detect any change to configuration settings $scope.$watch(function() { return Configuration; }, function(data) { // do something }, true) // alternatively only react to settingTwo changing $scope.$watch(function() { return Configuration.settingTwo }, function(data) { // do something }) })
Note that if you need a slightly more complex factory configuration, you can switch to getter / setter methods and keep the configuration settings private. Then in $watch you should watch the method call instead of the property itself.
UPDATE:
During the response, I preferred the a $watch approach in the controller. After some time, developing using the framework, I now try to completely leave $watch from the controller, instead preferring, where possible, direct access to the function at the point of changing the value or by using ng-change .
One of the reasons for this is the complexity that it adds to testing the controller, but perhaps moreover, that it is inefficient: every $digest angular cycle causes, every registered $watch will be evaluated independently, and it can respond very well to a change made into value with existing $watch .
Instead of judging the flaws and solutions from this point of view, there is a very good article in this problem: Angular JS - you probably t use $ watch in your controllers .