Я думаю, что ваш дизайн сделал проблему более сложной, чем она есть.
Поток данных является одним из способов:
HeaderComponent
- searchTerm
-> AppService
- apps
-> AppListComponent
Я думаю, вам просто нужен Subject
в AppService
, который служит прокси. HeaderComponent
передаст в него поисковые термины, а AppListComponent
получит результаты поиска.
app.service.ts
@Injectable({ providedIn: 'root' })
export class AppService {
private apps: Application[];
private filteredApps$: Subject<Application[]> =
new ReplaySubject<Application[]>(1);
getSearchResults(): Observable<Application[]> {
return this.filteredApps$.asObservable();
}
search(searchTerm: string): Observable<void> {
return this.fetchApps().pipe(
tap((apps: Application[]) => {
apps = apps.filter(app => app.name.toLowerCase().includes(searchTerm));
this.filteredApps$.next(apps);
}),
map(() => void 0)
);
}
private fetchApps(): Observable<Application[]> {
// return cached apps
if (this.apps) {
return of(this.apps);
}
// fetch and cache apps
return this.httpClient.get('http://localhost:3000/api/user/apps').pipe(
tap((apps: Application[]) => this.apps = apps)
);
}
}
Служба приложения будет кэшировать HTTP-ответ в первый раз производится поиск. Когда поисковый термин входит в службу, он выбирает приложения, фильтрует их и передает их по теме. Компонент, в котором перечислены результаты поиска, подпишется на тему.
header.component.ts
constructor(private appService: AppService) {
}
searchTerm = '';
ngOnInit() {
this.appService.search(this.searchTerm).subscribe();
}
onSearchTermChange(): void {
this.appService.search(this.searchTerm).subscribe();
}
header.component. html
<input [(ngModel)]="searchTerm" (ngModelChange)="onSearchTermChange()" />
app -list.component.ts
constructor(private appService: AppService) {
}
apps$: Observable<Application[]> = this.appService.getSearchResults();
app-list.component. html
<div *ngFor="let app of apps$ | async">
{{app.name}}
</div>
DEMO: https://stackblitz.com/edit/angular-nbdts8