shreyansh
shreyansh

Reputation: 1687

Component communication using service/broadcasting : Angular2

Hi all I am beginner in angular2. I am creating a small demo application for learning purpose.

app.component.ts

template: `
    <header-content></header-content>
    <main-content></main-content>
    <footer-content></footer-content>
  `

In my header I have a navigation section like home, login etc.

Main-content-template structure

<div class="container main">
        <div class="row">
          <router-outlet></router-outlet>
        </div>
 </div> 

As you can see I have placed the router-outlet for the header and footer section links inside main-content.

enter image description here

By defalut I am at Login page /login.

I have a separate component for every links.

What I want is when user clicks on submit button on login page I am redirecting him to some other xyz page.But along with that I want my Login link to get hide from the header nav and display a user name.

   <li *ngIf='!isUserLoggedIn'><a routerLink="/login">Login</a></li>
   <li *ngIf='isUserLoggedIn'><a>Welcome {{user}}</a></li>

HeaderComponent.ts

@Component({
  moduleId : module.id,
  selector : 'header-content',
  templateUrl: 'Header.html',
  providers: [LoginService]
})

export class HeaderComponent implements OnInit {
  isUserLoggedIn = false;
  user : string;

  constructor(private loginService: LoginService) { }

  getUserName() :void {
      this.user = this.loginService.getUserName(); // reading data from localstorage on page refresh
      if(this.user) {
        this.isUserLoggedIn = true;
      }
  }

  ngOnInit(): void {
     this.getUserName();
     // Will fire everytime other component use the setter this.loginService.setLogged()
     this.loginService.getLogged().subscribe((logged) => {
         console.log('Welcome===>', logged);
     });
  }
}

Login-Service.ts

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';
import { Observable } from 'rxjs/Observable';

@Injectable()

export class LoginService {
    username : string;

        private logged: boolean;
        private subject: Subject<boolean> = new Subject<boolean>();

        setLogged(logged: boolean): void {
            this.logged = logged;
            this.subject.next(logged);
        }

        getLogged() {
            return this.subject.asObservable();
        }


    constructor() {
        if(localStorage.getItem('userName')){
            this.username = localStorage.getItem('userName');
        }
    }

    getUserName():string {
        if(this.username) 
         return this.username;
    }
}

I have read a lot of other question and answers blog on stackoverflow , and I tried to use observable as you can see in the code. But when I click on submit button , the line of code inside ngOnInit() ( this.loginService.getLogged().subscribe((logged) => { ) is not getting called in order to update the value of isUserLoggedIn .

How can I broadcast or trigger some mechanism and what are the ways and the best way of doing it.

I don't know what mistake I am doing.

My other question is how can the methods in header-content can communicate with its siblings main-content or footer-content and also with the parent my-app component section.As in many questions answer is there for parent child components but not for the siblings.

Any help is appreciated !!!

Thanks

Upvotes: 0

Views: 477

Answers (2)

shreyansh
shreyansh

Reputation: 1687

After doing too much of experiment I found the mistake which I was doing, instead of creating a separate Login service, I made it as shared service and I removed the statement providers:[LoginService] from every component and placed this line of code inside app.module.ts file .

HeaderComponent.ts

 ngOnInit(): void {
     this.getUserName();
     // Will fire everytime other component use the setter this.sharedService.setLogged()
      this.sharedService.getLogged().subscribe((logged) => {
        console.log("logged==", logged);
        this.isUserLoggedIn = logged;
        this.user = this.sharedService.getUserName();
      });
  }

Upvotes: 0

Vassilis Pits
Vassilis Pits

Reputation: 3848

In your login-service you call the method that returns the username. That means that there you have a promise.

So back in your headerComponent change the get function to this:

getUserName() :void {
      this.user = this.loginService
                      .getUserName()
                      .success(data => {
                             this.isUserLoggedIn = true;
                      }
  }

I believe this will fix your problem based on what I see here. I would suggest to create a working snippet though ;)

UPDATE Based on your comments I suggest you to use BehaviorSubject which makes life easy to broadcast from service to component anything you want (from booleans to objects etc).

Here's an example based in your case:

In your login service (I'm attaching only the code that will make this happen):

import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Injectable } from '@angular/core';

@Injectable()

export class LoginService {

    userUpdated: any;

    constructor() {
        this.userUpdated = new BehaviorSubject<any>(false);
    }

    getUserName() :void {
        this.user = this.loginService
                        .getUserName()
                        .success(data => {
                            this.userUpdated.next(true);
                            return data;
                        }
    }

}

Next you go to you headerComponent code and edit it like this to subscribe to this:

@Component({
  moduleId : module.id,
  selector : 'header-content',
  templateUrl: 'Header.html',
  providers: [LoginService]
})

export class HeaderComponent implements OnInit, OnDestroy {
  isUserLoggedIn = false;
  user : string;
  sub: any;

  constructor(private loginService: LoginService) { }

  ngOnInit(): void {
    this.sub = this.loginService.userUpdated.subscribe(
      data => {
        if(data.username) {
          this.isUserLoggedIn = true;
      }
    );

  }

  ngOnDestroy() {
    this.sub.unsubscribe();
  }
}

Upvotes: 1

Related Questions