Olivia Oddo
Olivia Oddo

Reputation: 35

Why does ng-if only work with ng-click if they are in the same element?

I am hiding and showing nav bar elements based on if the user is logged in or out.

In the main controller:

    $scope.FBlogin = function(){
    FB.login(function(response) {
        if (response.authResponse) {
         console.log('Welcome!  Fetching your information.... ');
         FB.api('/me', function(response) {
           console.log('Good to see you, ' + response.name + '.');
           $cookies.put('userObj', response);

           var accessToken = FB.getAuthResponse().accessToken;
           console.log(accessToken);
           authFact.setAccessToken(accessToken);
           console.log(response);

            $scope.out=true;
            $scope.in = false;
            $scope.feed = true;

            $location.path("/myFeed");
            $scope.$apply();

         });
        } else {
         console.log('User cancelled login or did not fully authorize.');
        }
    });


};

    $scope.FBlogout = function(){
        $scope.out = false;
        $scope.in = true;
        $scope.feed = false;
        $cookies.remove("userObj");
        $cookies.remove('accessToken');
        $location.path("/");
        $scope.$apply();

};


}]);

It works here when the login function is called from the list item. The login link disappears and the logout link shows.

Navigation directive (part of main controller)

<li ng-click="FBlogin()" ng-if="in"><a href="#login">Login</a></li>
<li ng-if="feed"><a href="#myFeed">My Feed</a></li>
<li id="logout" ng-click="FBlogout()" ng-if="out"><a>Logout</a></li>

angular.module('dsnApp')
.directive('navApp', function(){
  return{
    templateUrl: 'templates/nav.html',
    controller:'mainController',
    replace: 'true'
  }
});

However when this button calls the login function the login button does not disappear and the logout does not show.

Login directive (part of main controller)

<div class="fbLogin" ng-controller="mainController">
    <h1 style="display: inline-block">Login with <span id="facebook">facebook</span></h1><br>
    <button ng-click="FBlogin()">Login</button>
</div>

    app.config(function($routeProvider) {
$routeProvider

    // route for the home page
    .when('/', {
        templateUrl : 'templates/home.html',
        controller  : 'mainController'
    })
    // route for the about page
    .when('/explore', {
        templateUrl : 'templates/explore.html',
        controller  : 'exploreController'
    })

    // route for the service page
    .when('/login', {
        templateUrl : 'templates/login.html',
        controller  : 'mainController'
    })

     // route for the about page
    .when('/myFeed', {
        templateUrl : 'templates/myFeed.html',
        controller  : 'feedController',
        authenticated : true
    })

    .otherwise('/', {
        templateUrl : 'templates/home.html',
        controller  : 'mainController'
    });

});

Does this have to do with scope at all?

Upvotes: 2

Views: 331

Answers (2)

georgeawg
georgeawg

Reputation: 48968

Does this have to do with scope at all?

Yes, it very much has to do with scope.

<body ng-controller="mainController">
  <div>
      <ul class="nav">
       <li id="home"><h1><a href="#/">Do Something Nice</a></h1></li>
       <li><a href="#explore">Explore</a></li>
       <li><a href="#login">Login</a></li>
       <li><a href="#myFeed">My Feed</a></li>
       <li id="logout" ng-click="FBlogout()">   <a>Logout</a></li>
    </ul>
  </div>
   <!-- this is where content will be injected -->
   <div id="main">

<!-- angular templating -->
<!-- this is where content will be injected -->
<div ng-view></div>

The body of the app has an ng-controller directive which creates a child scope and injects the mainController.

The ng-view directive is creating another child scope and the route is instantiating another mainController on that scope.

In addition, the ng-if directive is creating yet another child scope.

To make things worse, the custom dsn-app directive is instantiating yet another mainController.

To learn about scopes, I recommend reading:

Upvotes: 0

DennyHiu
DennyHiu

Reputation: 6060

It clearly have something to do with your scope. The $scope.in must have the same scope with both $scope.FBLogin() and $scope.FBlogout().

Since you said that you're using Navigation directive, I'm guessing that you have:

  1. a directive for navigation list, hence why your link inside this list works
  2. another directive for login,
  3. and a controller(mainController)

Although they're all have the same $scope as their dependency injector, their content aren't the same.

To achieve what do you want to do, you must share a variable that controls the navbar's visibility across your app (controllers and directives). Below is how you can do it, with a working example below that

 // angular app.js
 var app = angular.module('app', []);

 // main controller
 app.controller('MainController', function($scope, navbarState) {
     $scope.hide = function(){
        navbarState.hideNavbar(); // executes this when logout
     }
 });

 // navbar directive which use navbarState service
 // to show navbar, we use `ng-if` (see template)
 app.directive('navbarDirective', function(){
   return {
    restrict: 'EA',
    template: "<div ng-if=\"navbarState.currentState == 'show'\"></div>",
    controller: function ($scope, navbarState) {
      $scope.navbarState = navbarState;
    }
   }
 });

 // navbarState is a service that is shared across 
 // directives and controllers in your app.
 // this service holds a value (currentState) which indicates
 // navbar when to show or hide
 app.service('navbarState', function($window) {
    this.currentState = "show";
    this.showNavbar = function(){
       this.currentState = "show";
    }
    this.hideNavbar = function(){
       this.currentState = "hide";
    }
 });

Please see this plunkr example for detailed answer: https://plnkr.co/edit/LCS4NxJwcbfeVAXgLKJ8?p=preview

Upvotes: 2

Related Questions