angular - 搜索栏作为 Angular 7 中的服务
问题描述
在问这个问题之前,我在这里做了一些研究,只发现有人询问将搜索值传递给一个 REST API 并返回结果。
我的问题完全不同。我有两个组件和一个服务:
- 一个搜索栏组件(负责在每个按键上获取用户输入)
- 一个 applist 组件(显示所有应用程序/仅过滤的应用程序)
- 一个应用服务,负责一次从后端获取所有用户应用,然后从搜索栏组件获取搜索输入并更新 behaviorSubject。
在任何时候,我都需要保留原始应用列表的副本来过滤它。
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { map, distinctUntilChanged, filter } from 'rxjs/operators';
import { Observable, BehaviorSubject } from 'rxjs';
import { Application } from '../models/apps.model';
@Injectable({
providedIn: 'root'
})
export class AppsService {
private appListSubject: BehaviorSubject<Application[]>;
private filteredAppListSubject: BehaviorSubject<Application[]>;
private appList: Observable<Application[]>;
constructor(private httpClient: HttpClient) {
this.appListSubject = new BehaviorSubject<Application[]>({} as Application[]);
this.filteredAppListSubject = new BehaviorSubject<Application[]>({} as Application[]);
this.appList = this.filteredAppListSubject.asObservable().pipe(distinctUntilChanged());
}
getApps(): Observable<Application[]> {
return this.httpClient.get('http://localhost:3000/api/user/apps').pipe(map(
(res: any) => {
this.setAppList = res;
return res;
}
));
}
public get getCurrentAppList() {
return this.appList;
}
public set setAppList(apps: Application[]) {
this.appListSubject.next(apps);
this.filteredAppListSubject.next(apps);
}
public searchApp(searchTerm: string) {
const filteredApps = this.appListSubject.pipe(filter(
(app: any) => {
if (app.name.includes(searchTerm)) {
return app;
}
}
));
this.filteredAppListSubject.next(filteredApps);
}
}
这是我当前的应用服务实现。
我的目标是让 applist 组件订阅 appList,每当搜索栏组件要求服务查找值时,applist 组件就会从可观察到的应用程序中获取一个新数组。
现在,由于管道函数返回一个 observable,我无法将结果添加为行为主题的下一个值。
我也想听听你对这个特定实现的看法。谢谢!
解决方案
我认为您的设计使问题看起来比实际更复杂。
数据流是一种方式:
HeaderComponent
-- searchTerm
--> AppService
-- apps
-->AppListComponent
我认为您只需要一个Subject
inAppService
作为代理。将向其中HeaderComponent
传递搜索词,然后AppListComponent
将接收搜索结果。
应用服务.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()" />
应用程序列表.component.ts
constructor(private appService: AppService) {
}
apps$: Observable<Application[]> = this.appService.getSearchResults();
应用程序列表.component.html
<div *ngFor="let app of apps$ | async">
{{app.name}}
</div>
推荐阅读
- oracle - ORA-01652: 无法在表空间 TEMP 中将临时段扩展 128,但有 500GB 可用
- python-3.x - 如何从小部件调用的函数更新散景下载按钮的源
- postgresql - json_array_elements:整数的无效输入语法
- google-cloud-firestore - 如何知道请求的数量
- flowtype - 您如何在 Flow 中阅读此内容?
- android - android命令行构建出现错误:找不到com.android.tools.build:gradle
- node.js - 出现奇怪的错误 Error TypeError: app.use() requires a middleware function
- ruby-on-rails - FullCalendar 未知选项 'dateClick'
- android - 无法上传 targetSdkVersion 为 30 的签名 apk
- java - 在 Edittext 上获取空对象引用