I have 2 unrelated components, a search bar and a table. I have a service that shares data between them. The problem is that I have multiple instances of the search + table components depending on the search. Whenever I search, it updates all tables. Is there a way for me to bind one service between 2 components?
I know I can combine both the search and table component into 1 component, but with how my project is set up, it would make things more complicated than it already is.
Without giving out too much, this is what I have.
// Data sharing service
import { Injectable } from "@angular/core";
import { BehaviorSubject } from "rxjs";
@Injectable({
providedIn: 'root'
})
export class DataSharingService {
private data = new BehaviorSubject<any>(null);
currData = this.data.asObservable();
constructor(){}
updateSearchRes(newData: any){
this.data.next(newData);
}
}
// search component
onClick(e: any){
// get search data
this.searchResults = this.getSearchResults(e);
// send data to service
this.searchResults.forEach(element => {
this.dataSharingService.updateSearchRes(element);
});
}
// table component
ngOnInit(){
...
// listen for data
this.dataSharingService.currData.subscribe(newSearchRes => {
this.addDataToTable(data);
});
...
}
You need to use a simple if condition to scope the emits to a single component structure.
The HTML for the component will look like.
...
<app-search searchKey="home"/>
...
<app-table searchKey="home"/>
...
First we convert the service emit method, to emit an object with an event name, instead of just the data.
// Data sharing service
import { Injectable } from "@angular/core";
import { BehaviorSubject } from "rxjs";
@Injectable({
providedIn: 'root'
})
export class DataSharingService {
private data = new BehaviorSubject<any>(null);
currData = this.data.asObservable();
constructor(){}
updateSearchRes(eventName: string, newData: any){
this.data.next({eventName, data: newData });
}
}
Now When you click on search, you take an @Input() searchKey = ''
, this searchKey, can be used to filter the emits received by the table.
// search component
...
@Input() searchKey = ''
...
...
onClick(e: any){
// get search data
this.searchResults = this.getSearchResults(e);
// send data to service
this.dataSharingService.updateSearchRes(this.searchKey, this.searchResults);
}
Then use this same approach, to filter on the table.
// search component
...
@Input() searchKey = '';
private sub: Subscription = new Subscription();
...
...
// table component
ngOnInit(){
...
// listen for data
this.sub.add(
this.dataSharingService.currData.subscribe((event: any) => {
if(event.eventName === this.searchKey) {
this.addDataToTable(event.data);
}
})
);
...
}
ngOnDestroy() {
this.sub.unsubscribe();
}