Search code examples
angularjsangularjs-scopeangularjs-service

Angularjs service variables not updating properly


I'm learning angular and trying to get an understanding on how services and scope work together. I have the following plnkr which is an off/on canvas menu (http://plnkr.co/edit/wP1Fu6vlJiopJi5AzkQt).

I've attempted to split controllers. I define boolean variables called navLeft & navRight in the service call navState. I use the left and right nav menus under one ctrl called "navCtrl" and the canvas(header&content) under "canvasCtrl". Both controllers functions take $scope and navState as inputs.

The classes are applied on the canvas and applicable navMenu based on these boolean expression to simulate a off/on canvas menu.

I have 2 questions:

Question 1: When left toggle button is pressed, navLeft is made true. This updates the navLeft in canvasCtrl but not the navCtrl. Using the angular way, how can I update the navCtrl, navLeft/navRight states when it is changed in canvasCtrl?

Question 2: In angular using services, is it possible directly from within the controller to update the service variables(navState), which would then pass down the new states to the both controllers using the service(ie canvasCtrl, navCtrl). Is this an angular way doing things??

Appreciate all comments, thank you in advance.

JS code snippet below:

var app = angular.module("plunker",[]); //include modules for animation, on/off navmenu 
app.controller('mainCtrl', function($scope){
   //Main Json Files/data to go here
});

app.service('navState',function(){
   this.navLeft= false; //default navLeft menu off
   this.navRight=false; //default navRight menu off
});

app.controller('navCtrl',function($scope,navState){
  $scope.navLeft = navState.navLeft;
  $scope.navRight = navState.navRight;
});

app.controller('canvasCtrl', function($scope,navState){
  $scope.navLeft = navState.navLeft;
  $scope.navRight = navState.navRight;
  $scope.navClick=function(){ //changes class of canvas when navRight or navLeft value change
  if ($scope.navLeft== true){
    $scope.navRight = false;
    return ("canvas-off-left");
  }
  else if ($scope.navRight== true){
    navState.navLeft = false;
    return ("canvas-off-right");
  }
  else{
    return("canvas-on"); //if both right and left menu false, use default canvas-on style ie width 100%
  }      
 };

});

Solution

  • You can use SharedService approach.

    For example in your case.

        app.service('navState',function($rootScope){
           this.navLeft=false; //default navLeft menu off
           this.navRight=false; //default navRight menu off
    
           this.changeLeftValue = function(newValue){
             this.navLeft = newValue;  
             $rootScope.$broadcast("leftValueChanged");
           }
           this.changeRightValue = function(newValue){
             this.navRight = newValue;  
             $rootScope.$broadcast("rightValueChanged");
           }
    
           return this;
        });
    
        app.controller('navCtrl',function($scope,navState){
          $scope.navLeft = navState.navLeft;
          $scope.navRight = navState.navRight;
    
          $scope.$on("rightValueChanged", function(){
            $scope.navRight = navState.navRight;
          });
          $scope.$on("leftValueChanged", function(){
            $scope.navLeft = navState.navLeft;
          });
        });
    
        app.controller('canvasCtrl', function($scope,navState){
          $scope.navLeft = navState.navLeft;
          $scope.navRight = navState.navRight;
    
          $scope.navClick=function(){
            var className = "";
            if ($scope.navLeft== true){
              $scope.navRight = false;
              className = "canvas-off-left";
            }
            else if ($scope.navRight== true){
              $scope.navLeft = false;
              className = "canvas-off-right";
            }
            else{
              className = "canvas-on";
            }   
    
            navState.changeRightValue($scope.navRight);
            navState.changeLeftValue($scope.navLeft);
    
            return className;
         };
       });
    

    In this approach you call service function (setter) in the controller, where service value was changed. This service function broadcasts event and this event will be listened from necessary controller.

    You can find more details about $broadcast and $on here.

    I've updated your Plunker.

    Hope it helps.