bestfirstsearch
bestfirstsearch

Reputation: 131

How to share data between (multiple instances) of 2 unrelated components?

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);
  });

  ...
}

Upvotes: 1

Views: 76

Answers (1)

Naren Murali
Naren Murali

Reputation: 56054

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();
}

Upvotes: 2

Related Questions