Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Refresh Header after Login in Angular2

So I have a header component that displays either the User's name or "Sign In" depending on whether they are logged in or not. I also have a Login component that does all of the business logic of logging in. They currently do not have a parent / child relationship.

When the User logs in, the header does not refresh or change unless a full page refresh is done in the browser. I've been doing a lot of searching and reading online about different ways to do this. ngOnChanges, NgZone, ApplicationRef, and ChangeDetectorRef seem to be the most popular. I'm trying to implement this behavior in ChangeDetectorRef as this seems to be most relevant to my situation. However, I can't seem to find actual examples of how to use this.

I've coded it up but it does not seem to do anything. Any advice would be appreciated. I'd even accept that I'm taking the wrong approach and need to use another solution besides ChangeDetectorRef.

LoginComponent

import { Component, OnInit } from '@angular/core';
import { Response } from '@angular/http';
import { Router } from '@angular/router';

import { AuthenticationService } from '../service/authentication.service';

@Component({
    selector: 'login-component',
    templateUrl: './login.component.html'
})

export class LoginComponent implements OnInit {
    constructor(private router: Router, 
                private authenticationService: AuthenticationService) { }

    ngOnInit() {
        // Resets the login service.  
        // This is one of the events that should cause the refresh.
        this.authenticationService.logout();
    }

    login() {
        /*
        Authentication code
        This is the other event that should cause the refresh.
        */
    }
}

HeaderComponent

import { ChangeDetectorRef, ChangeDetectionStrategy, Component, OnInit } from '@angular/core';

import { Instance } from '../../entity/instance';

@Component({
    selector: 'header-component',
    templateUrl: './html/header.component.html',
    changeDetection: ChangeDetectionStrategy.OnPush
})

export class HeaderComponent {

    userName: string;

    constructor(private ref: ChangeDetectorRef) {
        this.ref.markForCheck();
    }

    ngOnInit(): void {
        var currentUser = JSON.parse(localStorage.getItem('currentUser'));

        this.userName = currentUser && currentUser.full_name;

        if (!this.userName) {
            this.userName = "User Name";
        }
    }
}

AppComponent

import { ChangeDetectorRef, ChangeDetectionStrategy, Component, OnInit } from '@angular/core';

import { Instance } from './entity/instance';
import { InstanceService } from './service/instance.service';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
    changeDetection: ChangeDetectionStrategy.OnPush
})

export class AppComponent implements OnInit {

    instances: Instance[];

    constructor(private instanceService: InstanceService) { }

    ngOnInit(): void {
    }
}

app.component.html

<header-component></header-component>

<router-outlet></router-outlet>
like image 965
Pinski Avatar asked Mar 23 '17 21:03

Pinski


3 Answers

So I ended up taking some of the advice of using my service to emit the change. I read in some places on Stack Overflow that using a service this way was a bad pattern, that emits should only happen from a child component to a parent component. So I'm not sure this is the "proper" way, but it works for me because I want to have multiple components know of this event.

I already had a service that was dealing with my authentication, so all I had to do was give it an emitter, emit at the proper times, and then listen for the emit in my component.

Header Component

export class HeaderComponent {
    userName: string;

    constructor(private authenticationService: AuthenticationService) {
        authenticationService.getLoggedInName.subscribe(name => this.changeName(name));
    }

    private changeName(name: string): void {
        this.userName = name;
    }
}

Authentication Service

@Injectable()
export class AuthenticationService {
    @Output() getLoggedInName: EventEmitter<any> = new EventEmitter();

    login(email: string, password: string): Observable<boolean> {
        if (successfulLogIn(email, password)) {
            this.getLoggedInName.emit(fullName);
            return true;
        } else {
            this.getLoggedInName.emit('Sign In');
            return false;
        }
    }

    logout(): void {
        this.getLoggedInName.emit('Sign In');
    }
}
like image 143
Pinski Avatar answered Oct 13 '22 17:10

Pinski


@Pinski was good. But this can be more easy. This is an alternative method to emit and subscribe data.

Header Component

export class HeaderComponent implements OnInit {
    userName: string;

    constructor(private authenticationService: AuthenticationService) {}

   NgOnInit() {
      this.authenticationService.getLoggedInName.subscribe(name => this.userName = name);
   }

}

Authentication Service

@Injectable()
export class AuthenticationService {
    public getLoggedInName = new Subject(); //Alternate method to Emitting data across Components. Subject() is doing both Emitting data and Subscribing it in another component. So its the best way to compare with Emitting using Output.

    login(email: string, password: string): Observable<boolean> {
        if (successfulLogIn(email, password)) {
            this.getLoggedInName.next(fullName); //next() method is alternate to emit().
            return true;
        } else {
            this.getLoggedInName.next('Sign In');
            return false;
        }
    }

    logout(): void {
        this.getLoggedInName.next('Sign In');
    }
}

Give a try to Subject(). Happy coding.

like image 11
Silambarasan R.D Avatar answered Oct 13 '22 19:10

Silambarasan R.D


You can do this -->

Header Component -->

 ngOnInit() {
this.subscription = this.emitterService.getEmitter('userDetails').subscribe((user: Object) => {
            if(user)
                this.userName = user["name"];
        });
    }
ngOnDestroy() {
        // prevent memory leak when component is destroyed
        this.subscription.unsubscribe();
    }

Login Service -->

this.emitterService.getEmitter('userDetails').emit(userDetails);

the value which you are emitting from login component will be caught in your menu component.

like image 4
RemyaJ Avatar answered Oct 13 '22 19:10

RemyaJ