1

When I login on my app, I want the login and signup button to disappear from the nav so I am using ng-hide directive if the login was successful and a token was received from the server, which I store in the cookies.

Nav is part of the index.html file.

Because I am using angular routing, when login is successful, index.html is not loaded again instead I render the home page through ng-view directive.

The problem is I have to refresh the page for ng-hide to work. I am assuming it is because ng-hide is part of index.html page, which does not get reloaded.

Hoping there is a bette solution than refreshing the page every time someone logs in.

Here is some of my relevant code.

HTML

<!-- Navigation -->
<nav class="navbar navbar-custom navbar-fixed-top" role="navigation">
    <div class="container">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-main-collapse">
                <i class="fa fa-bars"></i>
            </button>
            <a class="navbar-brand page-scroll" href="#/">
                <i class="fa fa-play-circle"></i>  <span class="light">Webnar</span>
            </a>
        </div>

        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse navbar-right navbar-main-collapse">
            <ul class="nav navbar-nav">
                <!-- Hidden li included to remove active class from about link when scrolled up past about section -->
                <li class="hidden">
                    <a href="#page-top"></a>
                </li>
                <li>
                    <a class="page-scroll" href="#about">Webinars</a>
                </li>
                <li ng-hide="token">
                    <a class="page-scroll" href="#/login">Login</a>
                </li>
                <li ng-show="token">
                    <a class="page-scroll " href="#/create">Add a webinar</a>
                </li>
                <li ng-hide="token">
                    <a class="page-scroll btn btn-default " href="#/signup">Sign Up</a>
                </li>
                <li ng-show="token" >
                  <a class="page-scroll btn btn-default" ng-click="logOut()">Logout</a>
                </li>

            </ul>
        </div>
        <!-- /.navbar-collapse -->
    </div>
    <!-- /.container -->
</nav>

App.js

var webinarApp = angular.module('webinarApp', ['ngCookies', 'ngRoute']);

webinarApp.config(function($routeProvider){

    $routeProvider

    .when('/', {
      templateUrl: './home.html',
      controller: 'mainController'
    })
    .when('/signup', {
      templateUrl: './signup.html',
      controller: 'mainController'
    })
    .when('/login', {
      templateUrl: './login.html',
      controller: 'mainController'
    })
    .when('/create', {
      templateUrl: './create.html',
      controller: 'mainController'
    })
});

webinarApp.controller('mainController', ['$scope', '$http', '$cookies', '$location', function($scope, $http, $cookies, $location){

  $scope.welcomeMessage = '';
  $scope.users = [];
  $scope.searchQuery = "";
  $scope.orderByField = 'name';
  $scope.newUser = {};
  $scope.logInUser = {};
  $scope.webinars = [];
  $scope.newWebinar = {};
  $scope.isDisabled = false;


  // ============== Users ================

  $scope.getUsers = function(){
    $http.get('/api/users').then(function(response){
      $scope.users = response.data;
    });
  };
  $scope.getUsers();

  $scope.createUser = function(){
    $http.post('/api/users', $scope.newUser).then(function(response){
      console.log(response.data)
      $scope.users.push(response.data);
      $scope.newUser = {};
      $location.path('/login');
    });
  };

  $scope.obtainToken = function(){
    $http.post("/api/users/authentication_token", $scope.logInUser).then(function(reponse){
      $scope.token = reponse.data.token;
      console.log($scope.token);
      $cookies.put('token', $scope.token);
      $location.path('/')
    });
  };
isherwood
  • 58,414
  • 16
  • 114
  • 157
manutdfan
  • 285
  • 4
  • 18

5 Answers5

2

It's because you put the navbar on the index page. It's not a template that is loaded by the route module. So it's not related to any route and controller that are bind with it. Controller declared in routes only applies for template that are loaded by the route module.

To bind a controller whatever the route is use ng-controller directive. Put it on your <nav> element

Note if you use the "as controller" syntax you must do in controller : this.isDisabled instead of $scope.isDisabled

Documentation : https://docs.angularjs.org/#!/api/ng/directive/ngController

If you need to update datas to that controller with the rest of the application. Use $rootScope. If you use 'ctrl as' syntax, the easier is to do : this.$rootScope=$rootScope;

If you don't like this use $watch to watch for changes and rebind the currentValue to the controller :

$rootScope.watch('myParameter', function(new){
     this.myParameter = new;
});

AND DON'T FORGET TO INITIALIZE THE VARIABLE IN $ROOTSCOPE. Or the variable will end up in a child scope that won't be visible for your navbar's controller.

Mr Lister
  • 45,515
  • 15
  • 108
  • 150
Walfrat
  • 5,363
  • 1
  • 16
  • 35
  • How about making of index.html as ??? – Pratap A.K Jan 28 '16 at 15:25
  • bad idea, you have the ng-route that is doing his stuff with a child of body. Better to keep the navbar controller separated from the ones used by the route. If you only have one controller as the demo code showed here you can, but i absolutely don't recommand it for a true application, i don't even know if this will work. – Walfrat Jan 28 '16 at 15:29
  • Thanks!! Even I am not sure whether it will work or not..but it just a thought. – Pratap A.K Jan 28 '16 at 15:33
  • I already have the body element binded to ng-controller="mainController" and that doesnt work. So I am going to try this solution by @walfrat – manutdfan Jan 28 '16 at 15:59
  • f you have multiple time the same controller called, the $scope object will be unique for each of them. It will be two distinct $scope object that may have no relationship parent-child between them. So if you stick to mainController on your body. Use $rootScope to share the values. Otherwise they just have their own scope and do their own business without interacting with each other – Walfrat Jan 28 '16 at 16:03
  • 1
    So the above worked. I used mainController on the body element tag which contains the navbar. Instead of storing token in $scope, I stored it in $rootscope. @walrat - My question is how was it working when I refreshed the page? – manutdfan Jan 28 '16 at 17:28
  • Can you please edit the first sentence of the second paragraph of your answer? Where it says "To bind a controller whatever the route is use ng-controller directive". I feel like this may be missing a comma or a word such as 'to', which makes it confusing to try to understand :) – Kyle Vassella Dec 18 '16 at 01:09
0

You should declare $scope.token with your other variable declarations. It does not exist in the scope when you are initially setting your ng-hide.

$scope.isDisabled = false; 
$scope.token;
Phobos
  • 1,568
  • 10
  • 18
0

Have you tried using $scope.$apply() ???

  $scope.$apply(function() {
    $scope.token = <whatever value>;
  })
Nijeesh
  • 848
  • 7
  • 11
  • I did but it says digest loop is already in progress. Which is right because I never went out of Angular context. Thanks though – manutdfan Jan 28 '16 at 15:17
0

Ok i think one way to do this would be to add a controller for nav say navbarController.

    <nav ng-controller="navbarController">...</nav>

Inject $rootScope into both maincontroller and navbarController.

then in mainController whenever you need to change value of token, do this

$rootScope.$emit('tokenValueChange', <value>);

then in navbarController add,

$rootScope.$on('tokenValueChange', function(newValue) {
    $scope.token = newValue;
})

I am not sure if this is a perfect method but this should work.
Nijeesh
  • 848
  • 7
  • 11
0

I had a similar problem as OP (viditsaxena), and solved it the same way he did. Like him, I had ng-hide in my nav which was located in index.html. My ng-hides worked correctly on initial page load, but when I tried to navigate to a different view, my ng-hide's would not work until I refreshed the page.

My solution: The same way @viditsaxena describes in his comments under the accepted answer (use $rootScope instead of $scope), but I thought I'd put my actual code here to show you how I made it work in my app.js file:

I went from this (ng-hide required refresh to load after I navigated away from the original view):

app.controller('routeController', ['$scope', '$location', function($scope, $location) {
    $scope.showPortfolioHeader = $location.path() === '/jcRealty';
}]);

To this (now my ng-hides don't require a refresh after I navigate away from my first view):

app.controller('routeController', ['$rootScope', '$location', function($rootScope, $location) {
    $rootScope.showPortfolioHeader = $location.path() === '/jcRealty';
}]);

The accepted answer got me part of the way there, but I had a hard time deciphering some of the grammar in his response. My own testing confirmed some of what he said. My controller above (routeController) is related to the view located at the /jcRealty path. If I put my ng-hides in my jcRealty view, they work properly (no refresh needed) using $scope. But since my ng-hide's are on index.html, outside of that controller's path, $rootScope was needed to not require a page reload.

Kyle Vassella
  • 2,296
  • 10
  • 32
  • 62