Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to dynamically update directive once user is logged in?

I have an app with a navbar directive and basic sign up/log in functionality. I want to change some of the words on the nav bar (from 'signup/login' to 'sign out') once the user is logged in, but I can't figure out the best (or even one) way to do this. I've tried setting the value of the variable/binding I want to change to a factory that gets updated when the user logs in, but this doesn't work, and the directive doesn't update with its new value.

My code is attached below, specific solutions are appreciated but not really necessary, if anyone can just point me in the right direction with how to do this that would be very helpful.

Solutions I've tried:

  • Factories
    1. setting binding variables equal to factory variables that are updated
    2. setting binding variables equal to the output of getter statements for those variables
  • Cookies (would prefer to avoid unless someone convinces me it's a good way of solving this)
    1. setting binding variables equal to values in cookies

Unfortunately none of these cause the directive variable to dynamically update as well. I feel like the solution is very simple but I can't think of what I should be doing.

Potential Solutions:

  • using routing, e.g. changing the view from one navbar to another when the user is logged in, although this seems really clunky
  • $rootScope (not entirely sure how to use this and I'm guessing it's the wrong use for this anyway)

navbar.html

<nav class="navbar navbar-static-top navbar-inverse">
  <div class="container-fluid">
    <div class="navbar-header">
      <a class="navbar-brand" href="#/">
        <span class="glyphicon glyphicon-star"></span> Home
      </a>
    </div>

    <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-6">
      <ul class="nav navbar-nav">
        <li><a ui-sref="message">Message</a></li>
        <li><a ui-sref="list">User List</a></li>
        <li><a ui-sref="schedule">Schedule</a></li>
      </ul>

      <ul class="nav navbar-nav navbar-right">
        <li><a ng-href="{{ vm.accountStatusLink }}">{{ vm.accountStatus }}</a></li>
      </ul>
    </div>
  </div>
</nav>

navbar.directive.js

(function() {
  'use strict';

  angular
    .module('app')
    .directive('mainNavbar', mainNavbar);

  mainNavbar.$inject = ['userFactory'];

  function mainNavbar(userFactory) {
    var directive = {
      restrict: 'E',
      templateUrl: 'app/components/navbar/navbar.html',
      scope: {
          creationDate: '='
      },
      controller: NavbarController,
      controllerAs: 'vm',
      bindToController: true
    };

    return directive;


    function NavbarController() {
      var vm = this;
      // solution 1 (doesn't work)
      vm.accountStatus = userFactory.userStatus;
      vm.accountStatusLink = userFactory.userStatusLink;
      // solution 2 (doesn't work)
      //vm.accountStatus = userFactory.getUserStatus();
      //vm.accountStatusLink = userFactory.getUserStatusLink();
    }
  }

})();

user.factory.js

(function() {
  'use strict'

  angular
    .module('app')
    .factory('userFactory', userFactory);

  userFactory.$inject = ['$http', '$cookies'];

  function userFactory($http, $cookies) {
    var userStatusLink = '#/user/';
    var userStatus = 'Sign Up / Log In';
    var service = {
      verifyUser: verifyUser,
      storeUser: storeUser,
      userStatusLink: userStatusLink,
      userStatus: userStatus
    };
    return service;

    /* verifyUser() snip */

    function storeUser(user) {
      $cookies.putObject('user', user); // stores user obj in cookies
      userStatusLink = '#/signout/';
      userStatus = 'Sign Out';
    }

    /* solution 2 getters

    function getUserStatus() {
        return userStatus;
    }

    function getUserStatusLink() {
        return userStatusLink;
    }

    */

  }

})();

Update:

userFactory.storeUser(user) is happening asynchronously inside of a .success callback:

$http.post('someurl').success(function(user) {
    userFactory.storeUser(user);
});
like image 590
turner Avatar asked Oct 31 '22 23:10

turner


1 Answers

Have you tried making a getUserStatusLink and a getUserStatus method, and binding your view to those methods instead?

function userFactory($http, $cookies) {
  ...
  var service = {
    ...
    getUserStatusLink: function() {
      return userStatusLink;
    },
    getUserStatus:  function() {
      return userStatus;
    }
  };
  ...
}

And then in your NavBar controller:

function NavbarController() {
  ...
  vm.accountStatusLink = userFactory.getUserStatusLink();
  vm.accountStatus = userFactory.getUserStatus();
}

This should do what you are looking for it to do when userStatusLink and userStatus are updated in your userFactory.

Update:

Since your storeUser() method is being called asynchronously, it is not triggering another digest cycle to happen when your new values are set. So you should force Angular to perform a digest cycle using the $timeout service:

userFactory.$inject = [ ..., '$timeout'];

function userFactory( ..., $timeout) {
  ...
  function storeUser(user) {
    ...
    // forces Angular to perform a digest cycle, thus refreshing your view
    $timeout(function() {
      userStatusLink = '#/signout/';
      userStatus = 'Sign Out';
    });
  }
  ...
}

Update 2:

Working jsFiddle with this implementation. I included two methods so you can see the difference in using $timeout and not using $timeout: http://jsfiddle.net/HB7LU/15366/

I steered you wrong in one place, update your controller variables to access the method directly like so:

function NavbarController() {
  ...
  // remove the parens at the end of userFactory.getUserStatusLink();
  vm.accountStatusLink = userFactory.getUserStatusLink;
  // remove the parens at the end of userFactory.getUserStatus();
  vm.accountStatus = userFactory.getUserStatus;
}

And then update your view to actually call the methods:

<!-- add parens to view to make it actually call the methods -->
<li><a ng-href="{{ vm.accountStatusLink() }}">{{ vm.accountStatus() }}</a></li>

Final Update:

Turns out $timeout was unnecessary, since Angular performs a digest cycle in the success callback of the $http service. Simply updating the view to access the method directly was enough to fix it.

like image 170
kanzelm3 Avatar answered Nov 09 '22 23:11

kanzelm3