Search code examples
angularjsservicebindingcontrollers

How to properly share and update data between Controllers in AngularJS?


So I am trying to code with AngularJS the best practice way without using $scope or $rootScope, but named controllers.

http://codepen.io/anon/pen/LpxOwx

Here's the Angular part:

.controller('demoController', function(Fac){
  var vm = this;
  vm.theme = Fac.theme;
  vm.changeTheme = function(theme) {
    Fac.changeTheme(theme);
    vm.theme = Fac.theme;
  };
 })

.controller('secondController', function(Fac){
  var vm = this;
  vm.changeTheme = function(theme) {
    Fac.changeTheme(theme);
  };
 })

 .factory('Fac', function() {
  var fac = {
  theme: '',
  changeTheme: function(theme) {
    fac.theme = theme === 'indigo' ? 'lime' : 'indigo'; 
  }
}
return fac;
});

I have forked a codepen to illustrate my problem. The demoController works as intended and updates the view. But it doesn't "work" when using the same Factory in the secondController. I assume that it works, but just doesn't update in the demoController.

The way I understood Angular data binding is, that all I need to do is use the Factory to share data between Controllers which bind to them and update accordingly on change.

I am sure, it's a very stupid mistake I'm doing here. What am I doing wrong?

UPDATE:

Thanks for the answers! I've encountered a new (related?) problem though:

http://plnkr.co/edit/cRa2FTkpbIsJ9TLzu5bD?p=preview

Can you tell me how I bind the user between LoginCtrl and ToolbarCtrl so that ng-show and ng-hide can update upon login and logout? When I login the Toolbar doesn't update accordingly. I have to refresh the whole page instead to make the login visible. When I logout it works because I explicitly set vm.user= {}; in the ToobarCtrl.


Solution

  • Here is a working version of your codepen

    I simply used a subvar to bind into view. Binding primitive var from factory to controller often lead to this king of trouble.

    The factory look like this :

    .factory('Fac', function() {
        var fac = {
          theme: {value:'indigo'},
          changeTheme: function(theme) {
            console.log(theme);
            fac.theme.value = theme === 'indigo' ? 'lime' : 'indigo'; 
          }
        }
    

    both controllers look like this :

    .controller('secondController', function(Fac){
          var vm = this;
          vm.theme = Fac.theme;
          vm.changeTheme = Fac.changeTheme;
      })
    

    and i used it like this in the view :

    <md-button href="#" class="md-primary md-raised" ng-click=vm.changeTheme(vm.theme.value)>
      Change theme
    </md-button>
    

    Hope it helped,

    EDIT : Here is an answer where i explain why this actually don't work with a primite var