Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

View not getting updated after component variable is changed in Angular2

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 ?

like image 323
user2180794 Avatar asked Mar 16 '26 19:03

user2180794


1 Answers

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;
    });
  }
like image 114
Thierry Templier Avatar answered Mar 18 '26 08:03

Thierry Templier