2

I am trying to broadcast an event from authguard component to my header component.

Broadcast service

@Injectable()
 export class BroadcastService {

 public subject = new Subject<any>();

 sendMessage(message: string) {
  this.subject.next(message);
 }
}

Receiver (header component)

export class HeaderComponent {
  constructor(public broadcast: BroadcastService) {
    this.broadcast.subject.subscribe(message => {
    alert('broadcast received: ' + message);
   });
 }
}

Broadcast (authguard component -- doesn't work)

export class AuthGuard implements CanActivate {
 constructor(public broadcast: BroadcastService) {      
 }

 canActivate(): boolean {
  this.broadcast.sendMessage('Hi from AuthGuard');
  return true;
 }
}

Broadcast (dashboard component -- works)

export class DashbardComponent {
 constructor(public broadcast: BroadcastService) {      
 }

 ngOnInit() {
  this.broadcast.sendMessage('Hi from AppComponent');
 }
}

app.component.html

<headerComponent></headerComponent>
<router-outlet></router-outlet>

routing

{
 path: 'dashboard',
 component: DashboardComponent,
 canActivate: [AuthGuard]
}

The issue is that when I broadcast from my authguard component, the receiver in my header component never receives the message. I can confirm that the canActivate method in authGuard is called for every path.

But when I broadcast from a page component (eg. dashboard), the receiver in the header component does receive the message.

Does anyone know how to publish a message from the authguard to my header component?

FruitDealer
  • 91
  • 2
  • 8
  • Please use BehaviorSubject instead of Subject. May be header component is not at all active when you emit the event and no subscription for your subject – Pratap A.K Sep 19 '18 at 04:40

2 Answers2

2

You have to use BehaviorSubject

here's an example

boradcast.service.ts

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

@Injectable({
  providedIn: 'root'
})
export class BroadcastService {

  constructor() { }

  public subject = new BehaviorSubject<any>('');

  sendMessage(message: string) {
    this.subject.next(message);

  }

}

here is Stackblitz demo

Aniket Avhad
  • 4,025
  • 2
  • 23
  • 29
  • does this answer different from what I have mentioned except Stackblitz? – Pratap A.K Sep 19 '18 at 05:25
  • @FruitDealer asked you for the stackblitz and I ceated this demo befor your answer post but i was late to post here....and main thing is that when you give answer to others with the demo that will matters.. – Aniket Avhad Sep 19 '18 at 05:28
  • so Its depend on @FruitDealer whom answer useful for him. – Aniket Avhad Sep 19 '18 at 05:28
  • @AniketAvhad Header is a component in my app.component.html. Also dashboard is the path with the authguard on it. I'll update my question with the code – FruitDealer Sep 19 '18 at 05:32
  • @FruitDealer said BehaviorSubject is not working for him even though it's working for me and you. So asked him to provide fiddle to identify the problem – Pratap A.K Sep 19 '18 at 05:33
  • As per my understanding, you want when click on `dashboard link` then you wanted the message in `header.component`. – Aniket Avhad Sep 19 '18 at 05:39
  • @AniketAvhad Yes correct. When dashboard loads, it will call authguard, which will send a message to the header component. – FruitDealer Sep 19 '18 at 05:42
  • @AniketAvhad Your solution seems to work. Mine is similar and it's not working. Would me using Angular 5 be an issue? – FruitDealer Sep 19 '18 at 06:08
0

Please use BehaviorSubject instead of Subject

A BehaviorSubject holds one value. When it is subscribed it emits the value immediately. A Subject doesn't hold a value.

Please check this https://stackoverflow.com/a/43351340/2742156

let bSubject = new BehaviorSubject(null); // null or any default value
bSubject.subscribe(value => {
  console.log("Subscription got", value);
});

Subscriber always receives the last emitted value

Updated:

Guard

@Injectable()
export class AuthGuard implements CanActivate {

  constructor(private broadcastService: BroadcastService) {}

  canActivate(): boolean {
    console.log('auth guard called');
    this.broadcastService.subject.next('from guard');
    return true;
  }
}

broadcast service

@Injectable()
 export class BroadcastService {

 public subject = new BehaviorSubject<any>('hello');

 sendMessage(message: string) {
  this.subject.next(message);
 }
}

subscriber(header component)

constructor(private broadcastService: BroadcastService) {
broadcastService.subject.subscribe((res) => {
        console.log('Inside login', res);
      });
}

route config

{
    path: 'some route',
    component: SomeComponent,
    canActivate: [AuthGuard]
  }
Pratap A.K
  • 4,337
  • 11
  • 42
  • 79
  • Thanks, BehaviorSubject seems to be a better practice. But it still doesn't fix the issue of AuthGuard broadcast not getting recieved on the header. – FruitDealer Sep 19 '18 at 04:55
  • @FruitDealer you are not returning boolean from canActivate method. Please return true or false – Pratap A.K Sep 19 '18 at 05:07
  • sorry I left some code out to make it clearer for demo purposes. I've edited the post to include the return type. – FruitDealer Sep 19 '18 at 05:11
  • @FruitDealer it's working for me with BehaviorSubject. I'll update my answer with what I have tried. If it still didn't work please create a stackblitz, JsFiddle I'll correct for you – Pratap A.K Sep 19 '18 at 05:13