If you need to communicate a message from one component to another using a service, one approach is to establish a global message bus or event bus (known as the publish/subscribe pattern).
To achieve this, you will require the use of the Subject (for emitting values with the .next() method) and Observable (for subscribing to messages with the .subscribe() method) from RxJS, which has become an integral part of Angular 6. In this example, I am utilizing RxJS 6 in combination with the rxjs-compat package.
In this scenario, we will send a message through the MessageService class, annotated as @Injectable for dependency injection in components. The message will be triggered by clicking a button in app.component.html, and then retrieved in message.component.ts to display it in the HTML template message.component.html. To include the selector for MessageComponent, use in app.component.html.
Below is the complete code:
message.service.ts
import { Injectable } from '@angular/core';
import { Observable,Subject} from 'rxjs';
@Injectable()
export class MessageService {
private subject = new Subject<any>();
sendMessage(message: string) {
this.subject.next({ text: message });
}
clearMessage() {
this.subject.next();
}
getMessage(): Observable<any> {
return this.subject.asObservable();
}
}
app.component.ts
import { Component } from '@angular/core';
import { MessageService } from './message.service';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular 6';
constructor(private service:MessageService){}
sendMessage(): void {
// send message to subscribers via observable subject
this.service.sendMessage('Message from app Component to message Component!');
}
clearMessage():void{
this.service.clearMessage();
}
}
app.component.html
<button (click)="sendMessage()">Click here to test message</button> <br><br>
<app-messagecomponent></app-messagecomponent>
message.component.ts
import { Component, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';
import { MessageService } from './message.service';
@Component({
selector: 'app-messagecomponent',
templateUrl: 'message.component.html'
})
export class MessageComponent implements OnDestroy {
message: any = {};
subscription: Subscription;
constructor(private messageService: MessageService) {
// subscribe to app component messages
this.subscription = this.messageService.getMessage().subscribe(message => { this.message = message; });
}
ngOnDestroy() {
// unsubscribe to ensure no memory leaks
this.subscription.unsubscribe();
}
}
message.component.html
<p>The incoming message : </p> <br>
{{message?.text }}
The Elvis operator is utilized here in case the message is undefined.
Here is a working demo: https://stackblitz.com/edit/rxjs-snaghl
Feel free to reach out if you are interested in implementing a similar solution.