I'm a bit confused when it comes to the controller as
syntax as I've never worked with it before. I'd like to know the correct way to fix this. Haven't been able to find a similar problem when searching.
I have a menu and a button which toggles the menu. The menu has its own scope and the button has another, as they live in two separate files and containers.
When I click the button it only updates the nav.isActive
within the button scope. I created a service for storing the state, which I shouldn't have to do when I think about it.. Should I? Because the only way to watch if that value changes is with a watcher, which would require me to use $scope
since this
doesn't have the $watch
function, however, I'd like to avoid this as much as I can as it will affect performance which is important in this project.
What is the correct way of updating a "scope" variable from another "scope" when using the controller as
syntax?
Controller:
nav.controller('NavCtrl', ['navState', function(navState) {
var nav = this;
nav.menu = [
{icon: 'color_lens', href: ''},
{icon: 'color_lens', href: 'about'},
{icon: 'color_lens', href: 'contact'},
{icon: 'color_lens', href: 'logout'},
{icon: 'color_lens', href: 'faq'}
];
nav.toggleMenu = function() {
nav.isActive = navState.checkState();
}
}]);
The service for passing the value from one scope to the other:
nav.service('navState', [function() {
var isActive = false;
this.checkState = function() {
isActive = !isActive;
return !isActive;
}
}]);
The menu markup (menu.html):
<nav class="si-wrapper si-dark" ng-controller="NavCtrl as nav" ng-class="{active: nav.isActive}">
<ul class="si-list">
<li class="si-item" ng-repeat="item in nav.menu">
<a href="#/{{item.href}}">
<div class="si-inner-item">
<i class="material-icons md-36" ng-bind="item.icon"></i>
</div>
</a>
</li>
</ul>
<h1>{{nav.isActive}}</h1> <!-- This doesn't change -->
</nav>
The button which toggles the menu (header.html):
<div ng-controller="NavCtrl as nav">
<button ng-click="nav.toggleMenu()">Toggle</button>
<span>{{nav.isActive}}</span> <!-- This updates however -->
</div>
Your problem is that nav.isActive
is not set for one of the controllers. Basically whenever you use ng-controller
a new controller (and $scope
) is created. So for each of your controllers, $scope.isActive
needs to be set for the related view to reference it.
In your posted code, isActive
is only set when toggleMenu()
is run, which happens only in header.html.
In order to get your code to work, simply set isActive
on controller load. For example:
nav.controller('NavCtrl', ['navState', function(navState) {
// put isActive on the scope on controller load
this.activeState = navState.getState();
nav.toggleMenu = function() {
navState.toggleState();
};
}]);
You need to make your service better by separating state access and state manipulation. Also wrapping it in a container object will ensure you won't have any scope hierarchy issues.
nav.service('navState', [function() {
var state = {
isActive: false
};
this.toggleState = function() {
state.isActive = !state.isActive;
};
this.getState = function(){
return state;
};
}]);
Then you need to use `activeState.isActive' inside your view.
Now you will have a service with a shareable state, and two controllers that both reference the same service on load. Then inside your menu view, when you toggle the state, both controllers scopes are updated.