0

I want to update the filter of an ng-repeat in my view and for that reason I am using a $scope variable to change in my controller. For example here is a json array of my objects that I'll iterate in my view:

[{
    "address" : "#/",
    "title" : "Home",
    "name" : "Home",
    "category": "loggedIn loggedOut"
}, {
    "address" : "#/logout",
    "title" : "Logout",
    "name" : "Logout",
    "category": "loggedIn"
}, {
    "address" : "#/register",
    "title" : "Register",
    "name" : "Register",
    "category": "loggedOut"
}, {
    "address" : "#/login",
    "title" : "Login",
    "name" : "Login",
    "category": "loggedOut"
}]

Which is assigned to $scope.menuLinks. I also hava a $scope.menuFilter = "loggedIn"; for the filtration.

Here is my view that I want to update: menu.html

<div ng-controller="MenuController as menuCtrl">
    <ul id="menu">
        <li ng-repeat="link in menuLinks | filter:menuFilter"><a
            href="{{link.address}}" title="{{link.title}}">{{link.name}}</a>    </li>
    </ul>
</div>

And here is my controller which changes the $scope.menuFilter:

 function LogoutController($scope, $http, $location) {
    var sessionkey = localStorage.getItem("sessionkey");

    $http({
        method : 'PUT',
        url : url + "/user/logout",
        headers : {
            'sessionkey' : sessionkey
        }
    }).success(function(data) {
        sessionkey = "";
        localStorage.setItem("sessionkey", sessionkey);
        $location.path('/');
        $scope.menuFilter = "loggedOut";
    });
 }

But when the LogoutController is called, the view does not change, I have to refresh the page in order to see the view changed. If I add $scope.$apply(); after $scope.menuFilter = "loggedOut"; then I get and error: [$rootScope:inprog] $digest already in progress

What am I doing wrong? How should I update the view after a $scope value is changed?

1 Answers1

0

You are modifying the scope of the controller, when instead you need to modify the scope of the ngRepeat. The easiest way to fix this is to use an object on the controller scope which will get prototypically inherited and thus when you update it, the ngRepeat will reflect the change:

$scope.filters = {
    menuFilter: "loggedIn"
}

And then in your markup:

<li ng-repeat="link in menuLinks | filter:filters.menuFilter"><a
            href="{{link.address}}" title="{{link.title}}">{{link.name}}</a></li>

Finally when you update in the controller:

$scope.filters.menuFilter = "loggedOut";

For more info on scope inheritance / javascript prototypal inheritance check out this SO question:

What are the nuances of scope prototypal / prototypical inheritance in AngularJS?

Community
  • 1
  • 1
Daniel
  • 423
  • 5
  • 11
  • I tried your suggestion but then I received another error - TypeError: Cannot set property 'menuFilter' of undefined. Maybe I didn't mention that I change the $scope.menuFilter or $scope.filters.menuFilter in another controller. I found that $rootScope is also used in some cases and tried it in my code and it finally worked. I tried and without using the prototypically inherited object - $scope.filters = {menuFilter...} and it still works. So does $scope means only the controller scope and $rootScope is a global scope? I'll have to read more about the differences and which when to use. – Simeon Nikolov May 17 '14 at 17:07
  • In general, you should stick to using the controller $scope so you don't pollute the global scope ($rootScope). If you are still having trouble, create an example at plnkr.co and I can take a look. – Daniel May 18 '14 at 19:31