Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 - Transfer data outside router-outlet to another component

Tags:

angular

Am new to Angular2 but I have already made 30+ component and services and used Input, Output, ChangeDetectorRef, Pipes. So pretty much know about Angular2 by now. My app.component.ts looks like this

import { Component } from '@angular/core';
@Component({
    selector: 'soc',
    template: `
        <header-block></header-block>
        <router-outlet></router-outlet>
    `,
})
export class AppComponent { }

As I need my header-block in every page so I added it outside router-block so I don't have to add it everywhere. Now the problem I am having is changing the value of variable in the header-block after doing an action in view inside router-outlet.

For example I have menu which will be visible to the user only after they login.

{{ user_is_logged }}
<ul class="nav navbar-nav navbar-right" *ngIf="user_is_logged == '1'">
    <li><a href="#" (click)="logout($event)">Logout</a></li>
</ul>

user_is_logged is a variable whose value am getting from localStorage in header.block.component.ts

user_is_logged:string = localStorage.getItem("logged");

When the user is not logged in i.e. user_is_logged is undefined for home.component.ts ( where login logic is written ), I ask the user to login and after successful login am updating the value of user_is_logged variable and also updating the localStorage value of the variable and then triggering detect changes by using the ChangeDetectionRef(cdr) and then routing to user profile

this.user_is_logged = "1";
localStorage.setItem('logged', '1');
this.cdr.detectChanges();
this.router.navigate(['u/'+user_id']); //user_id is from login response from server

The problem is when I reach the user profile after successful login the value of {{ user_is_logged }} never updates even when am using the variable itself or using the value from localStorage or even calling for detection.

Is it possible to do it this way or do I have to add header-block to every page separately? Please ask for more information if I missed something.


EDIT ============>

So after going through Subject, BehaviourSubject, AsyncSubject, ReplaySubject, Observables and what not I just couldn't get this to work. This is the last code I have written :

home.page.component.ts (where login happens and has to emit the event)

import { HomeService } from '../services/home.service';
// No observable or subject imported here.

login() {
    // Sending status 1 to HomeService
    this.HomeService.changeStatus("1");
}

home.service.ts (which is imported by both component)

import { BehaviorSubject } from 'rxjs/BehaviorSubject';
// I imported Subject, BehaviourSubject, Observables but cant get it to work

export class HomeService {

    // This looked more reliable than Subject so used this; init with value "0"
    public subjectStream = new BehaviorSubject<string>('0');


    constructor(
    ){
        this.subjectStream.subscribe(value => {
            // Successfully logs value "1" sent by changeStatus below
            console.log(value);
        });
    }


    changeStatus(value: any){

        // Gives value "1" when called by home.page.component.ts
        console.log(value);

        // Looks correct because it successfully sent value to construct
        this.subjectStream.next(value);

    }

}

header.block.component.ts

import { HomeService } from '../services/home.service';
// No observable or subject imported here also.


constructor(
){
    this.HomeService.subjectStream.subscribe(value => {
        // Logs value "0" at beginning but never logs value "1"
        console.log(value);
    });
}

My Log

// logged by constructor when imported by header.block.component
home.service.ts:31                  0

// logged by constructor of header.block.component itself
header.block.component.ts:25        0

// logged by constructor when imported by home.page.component (I think)
home.service.ts:31                  0

// ===================
// Login called here
// ===================

// logged by changeStatus after login after called by home.component
home.service.ts:36                  1 

// logged by constructor after getting event from changeStatus
home.service.ts:31                  1

What am I missing in header.block.component.ts? As the value is successfully updated within the home.service.ts but never goes to header.

like image 578
Akash Joshi Avatar asked Jan 28 '17 14:01

Akash Joshi


1 Answers

If you provide HomeService in homepage and header, you get 2 instances of HomeService. If you want to share a service, then provide it only once on the parent component. If you want to share a single instance with your whole application, provide it only at @NgModule() of AppModule

like image 129
Günter Zöchbauer Avatar answered Nov 15 '22 06:11

Günter Zöchbauer