1

I have this piece of code:

....
<article class="collapse navbar-collapse">
    <ul ng-if="isLogged()" class="nav navbar-nav">
        <li ng-class="{'active': activeUrl === 'projects'}">
            <a href="#/projects" ng-click="activeUrl='projects'">Projects</a>
        </li>
        <li ng-if="isAdmin()" ng-class="{'active': activeUrl === 'admin'}">
            <a href="#/admin" ng-click="activeUrl='admin'">Administration</a>
        </li>
    </ul>
</article>

And it should add active class when link is clicked. It worked very well until I added ng-if expressions, which mock user authentication. Now when it adds active class once, it doesn't remove this class when another navigation link is clicked - it looks like 2 pages are opened in the same time. There is applicationController which has mock functions:

applicationController= function($scope, Restangular, userService){
    $scope.activeUrl = "admin";
    $scope.data = {
        user: {
        email: undefined,
        password: undefined
        }
    };

    $scope.login = function(user){
        //login mock
    };

    $scope.isLogged = function(){
        return userService.isLogged();
    };

     $scope.isAdmin = function(){
        return userService.isAdmin();
    };
};

And userService has logic which determine if user is authenticated and if is administrator. I don't think that ng-if with ng-class in one HTML element is something unusual, that's why I think I must made some simple mistake which I can't see. Is scope recreated after any click? I would be very happy if anybody helps me - thank you in advance! Update: solution with @ptwo help, I need $parent and with Administration $parent.$parent:

<article class="collapse navbar-collapse">
    <ul ng-if="isLogged()" class="nav navbar-nav">
        <li ng-class="{'active': $parent.activeUrl === 'projects'}">
           <a href="#/projects" ng-click="$parent.activeUrl='projects'">Projects</a>
        </li>
        <li ng-if="isAdmin()" ng-class="{'active': $parent.$parent.activeUrl === 'admin'}">
           <a href="#/admin" ng-click="$parent.$parent.activeUrl='admin'">Administration</a>
        </li>
      </ul>
</article>

Update 2 with solution without direct accessing $parent, but with data object in applicationController which allows me to access activeUrl:

<article class="collapse navbar-collapse">
    <ul ng-if="isLogged()" class="nav navbar-nav">
        <li ng-class="{'active': data.activeUrl === 'projects'}">
            <a href="#/projects" ng-click="data.activeUrl='projects'">Projects</a>
        </li>
        <li ng-if="isAdmin()" ng-class="{'active': data.activeUrl === 'admin'}">
            <a href="#/admin" ng-click="data.activeUrl='admin'">Administration</a>
        </li>
    </ul>
</article>

applicationController= function($scope, Restangular, userService){
    $scope.data = {
        activeUrl: "admin",
        user: {
            email: undefined,
            password: undefined
        }
};
....
Radek Anuszewski
  • 1,812
  • 8
  • 34
  • 62
  • 1
    See [here](http://stackoverflow.com/questions/20067467/model-does-not-update-within-ng-if) but pay attention to the second answer (not the accepted one). By using `$parent` to access an outer variable you solve the problem now but you run the risk of seeing it come back in the future if you add a new scope for any other reason. – Aurelio Mar 16 '15 at 18:03
  • 1
    @Nobita You are right, I placed another working solution without `$parent` but with `data.activeUrl` – Radek Anuszewski Mar 16 '15 at 18:11

2 Answers2

2

Use a function to change the activeUrl. It's never a good practice to have expressions within the view.

<article class="collapse navbar-collapse">
<ul ng-if="isLogged()" class="nav navbar-nav">
    <li ng-class="{'active': isActiveUrl('projects')}">
        <a href="#/projects" ng-click="updateActiveUrl('projects')">Projects</a>
    </li>
    <li ng-if="isAdmin()" ng-class="{'active': isActiveUrl('admin')}">
        <a href="#/admin" ng-click="updateActiveUrl('admin')">Administration</a>
    </li>
</ul>
</article>

applicationController= function($scope, Restangular, userService){
    $scope.data = {
        activeUrl: "admin",
        user: {
            email: undefined,
            password: undefined
        } };
    $scope.isActiveUrl = isActiveUrl;
    $scope.updateActiveUrl = updateActiveUrl;

    function isActiveUrl(param){
      return $scope.data.activeUrl == param;
    }

    function updateActiveUrl(param){
      $scope.data.activeUrl = param;
    }
}

The idea is to change member variables of the parent scope from its own scope, rather than the child scope of ng-if.

  • 1
    This does not provide an answer to the question. Once you have sufficient [reputation](http://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](http://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](http://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/low-quality-posts/13243316) – Michael Parker Aug 06 '16 at 04:17
  • Thanks for clarification. I'll take this into consideration. I've edited the answer to provide a good answer (I hope). – Mahmood .K Samaha Aug 06 '16 at 06:43
1

When you use ng-if it adds a scope of its own hence on click the activeUrl is set on a child scope of the controller. Try using $parent.activeUrl='admin' it should work

ptwo
  • 461
  • 4
  • 13