3

View {{user.email}} not getting updated after the component variable 'user' in SidebarComponent is updated. It works after manual page refresh. I have split the material design into separate components. The side bar component is as follows

SidebarComponent.ts

import {Component} from 'angular2/core';
import {Router, RouteConfig, ROUTER_DIRECTIVES,CanActivate} from 'angular2/router';
import {HomeComponent} from '../home/HomeComponent'
import {DashboardComponent} from './DashboardComponent'

@Component({
    selector: 'app-sidebar',
    template: `
      <header class="demo-drawer-header">
          <img src="../app/assets/images/user.jpg" class="demo-avatar">
          <div class="demo-avatar-dropdown">
            <span>{{user.email}}</span>
            <div class="mdl-layout-spacer"></div>
            <button id="accbtn" class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon">
              <i class="material-icons" role="presentation">arrow_drop_down</i>
              <span class="visuallyhidden">Accounts</span>
            </button>
            <ul class="mdl-menu mdl-menu--bottom-right mdl-js-menu mdl-js-ripple-effect" for="accbtn">
              <li class="mdl-menu__item">[email protected]</li>
              <li class="mdl-menu__item">[email protected]</li>
              <li class="mdl-menu__item"><i class="material-icons">add</i>Add another account...</li>
            </ul>
          </div>
        </header>
        <nav class="demo-navigation mdl-navigation mdl-color--blue-grey-800">

          <a class="mdl-navigation__link" [routerLink]="['./Dashboard']"><i class="mdl-color-text--blue- grey-400    material-icons" role="presentation">dashboard</i>Dashboard</a>


          <a class="mdl-navigation__link" [routerLink]="['./Home']"><i class="mdl-color-text--blue-grey-400     material-icons" role="presentation">assignment</i>Tasks</a>

          <a class="mdl-navigation__link" href=""><i class="mdl-color-text--blue-grey-400 material-icons"     role="presentation">delete</i>Trash</a>
        </nav>
    `, 

    directives: [ROUTER_DIRECTIVES,DashboardComponent]
})

export class SidebarComponent { 

  user = JSON.parse(localStorage.getItem('profile'));  

  constructor() {}

}

I have a custom router-outlet to check user authentication which is as follows

import {Directive, DynamicComponentLoader, ElementRef} from "angular2/core";
import {AuthService} from '../../services/AuthService'
import {Router, RouterOutlet, ComponentInstruction} from "angular2/router";

@Directive({
    selector: 'auth-router-outlet'
})
export class AuthRouterOutlet extends RouterOutlet {
    private _protectedRoutes = {
        'app/**': true,
        'app/home': true,
        'app/dashboard': true,
        'app/about': true
    };

    constructor(_elementRef: ElementRef, _loader: DynamicComponentLoader, private _router: Router, nameAttr:     string, private _authService: AuthService) {
        super(_elementRef, _loader, _router, nameAttr);
    }

    activate(nextInstruction: ComponentInstruction): Promise<any> {
        if (this._protectedRoutes[nextInstruction.urlPath]) {        
            if (!this._authService.loggedIn()) {
                this._router.navigate(['Login']);
            }
        }

        return super.activate(nextInstruction);
    }
}

The aboue outlet uses the following Authservice.ts which sets the Profile object in Localstorage

import {Injectable} from 'angular2/core';
import {ROUTER_DIRECTIVES, Router} from "angular2/router";
import {tokenNotExpired} from 'angular2-jwt';


declare var Auth0Lock: any;

@Injectable()
export class AuthService {

constructor(private router: Router) {}

  private useremail;

  lock = new Auth0Lock('KEY','URL');

  login() {
   this.lock.show((error: string, profile: Object, id_token: string) => {
     if (error) {
       console.log(error);
       return false;
     }

     localStorage.setItem('profile', JSON.stringify(profile));
     localStorage.setItem('id_token', id_token);

     /*var profiletemp = JSON.parse(localStorage.getItem('profile'));
     this.setUserEmail(profiletemp.email);*/

     this.router.navigate(['Dashboard']);

    });
 }

 logout() {
   localStorage.removeItem('profile');
   localStorage.removeItem('id_token');
 }

 loggedIn() {
    return tokenNotExpired();
  }

/* setUserEmail(val) {         -- not required as profile object is in localstorage
        this.useremail = val;
  } 

 getUserEmail() {
        return this.useremail;
  } */ 
}

index.html

<html>
  <head>
    <title>MEAN</title>
    <base href="/"/>

    <!-- 1. Load libraries -->
    <script src="libs/angular2/bundles/angular2-polyfills.js"></script>
    <script src="libs/systemjs/dist/system.src.js"></script>


    <script src="libs/rxjs/bundles/Rx.js"></script>
    <script src="libs/angular2/bundles/angular2.dev.js"></script>
    <script src="libs/angular2/bundles/router.dev.js"></script>
    <script src="//cdn.auth0.com/js/lock-9.0.min.js"></script>
    <script src="libs/angular2/bundles/http.dev.js"></script>
    <script src="https://code.getmdl.io/1.1.3/material.min.js"></script>

    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"></    meta>

    <meta name="mobile-web-app-capable" content="yes">
    <link rel="icon" sizes="192x192" href="app/assets/images/android-desktop.png"></meta>

     <!-- Add to homescreen for Safari on iOS -->
    <meta name="apple-mobile-web-app-capable" content="yes"></meta>
    <meta name="apple-mobile-web-app-status-bar-style" content="black"></meta>
    <meta name="apple-mobile-web-app-title" content="Material Design Lite"></meta>
    <link rel="apple-touch-icon-precomposed" href="app/assets/images/ios-desktop.png">

    <!-- Tile icon for Win8 (144x144 + tile color) -->
    <meta name="msapplication-TileImage" content="app/assets/images/touch/ms-touch-icon-144x144-precomposed.png"><    /meta>
    <meta name="msapplication-TileColor" content="#3372DF"></meta>

    <link rel="shortcut icon" href="app/assets/images/favicon.png">


   <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:regular,bold,italic,thin,light,    bolditalic,black,medium&amp;lang=en">
    <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
    <link rel="stylesheet" href="https://code.getmdl.io/1.1.3/material.cyan-light_blue.min.css"> 
    <link rel="stylesheet" href="app/assets/styles.css">
    <style>
    #view-source {
      position: fixed;
      display: block;
      right: 0;
      bottom: 0;
      margin-right: 40px;
      margin-bottom: 40px;
      z-index: 900;
    }
    </style>

    <!-- 2. Configure SystemJS -->
    <script>
      System.config({
        packages: {        
          app: {
            format: 'register',
            defaultExtension: 'js'
          } 
        } ,
        map: {
          "angular2-jwt": "libs/angular2-jwt/angular2-jwt.js"
        }
      });
      System.import('app/bootstrap')
            .then(null, console.error.bind(console));
    </script>

  </head>
  <!-- 3. Display the application..All ExpressJS requests come to this index file and from here Angular routing     takes over-->
  <body>
    <my-app>Loading the application...</my-app>
  </body>

</html>    

I have the angular2-polyfills.js included in the index. The SidebarComponent view does not update after the corresponding variable in the component is changed.

Any ideas ?

2 Answers 2

4

I think that you need to notify the SidebarComponent component that the profile was updated within the local storage with the AuthService shared service. Be sure that this service is configured when bootstrapping your application.

constructor(private router: Router) {}
  private useremail;
  profileUpdated$:Suject<any> = new Subject(); // <-------

  lock = new Auth0Lock('KEY','URL');

  login() {
    this.lock.show((error: string, profile: Object, id_token: string) => {
      if (error) {
        console.log(error);
        return false;
      }

      localStorage.setItem('profile', JSON.stringify(profile));
      localStorage.setItem('id_token', id_token);
      this.profileUpdated$.next(profile); // <-------

      this.router.navigate(['Dashboard']);
    });
}

logout() {
  localStorage.removeItem('profile');
  localStorage.removeItem('id_token');
  this.profileUpdated$.next(null); // <-------
}

Within the SidebarComponent component you can subscribe on profileUpdated$ to be notified and update the corresponding template:

@Component({
  (...)
})
export class SidebarComponent { 

  user = JSON.parse(localStorage.getItem('profile'));  

  constructor(private service:AuthService) {
    this.profileUpdated$.subscribe(profile => { // <-----
      this.user = profile;
    });
  }
Sign up to request clarification or add additional context in comments.

9 Comments

Still the same behavior. I have to refresh the page manually to reload the sidebar.
Does the callback is called within the SidebarComponent component? Is the AuthService service only defined when bootstrapping the application (and not in providers attribute of components)?
i don't quite understand about the callback in SidebarComponent?? AuthService is only in the bootstrap and not in the providers of any component.
I made the following change to the sidebar constructor constructor(private service:AuthService) { this.user = this.service.profileUpdated$.subscribe(profile => { this.user = profile; }); } Now I don't have to refresh the page, but some clicks. still not perfect, but a step closer.
|
0

What is your localStorage.getItem('profile') return.

user = JSON.parse(localStorage.getItem('profile'));

You should create a user model first and then assign json result on this model. Something like this

User.ts

export class User {
   email:string;
}

Change SidebarComponent.ts class

export class SidebarComponent { 
  user:User ; 
  constructor() {
     this.user=JSON.parse(localStorage.getItem('profile'));  
  }
}

1 Comment

Even if i do that, the sidebar constructor is not called after I login. So the Sidebar is already loaded before I login. That is why when I refresh the page, it all works fine.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.