angular 7 中的搜索栏即服务
Search bar as a service in angular 7
在问这个问题之前,我在这里做了一些研究,只发现有人问关于将搜索值传递给 rest API 并取回结果。
我的问题完全不同。我有两个组件和一个服务:
- 一个搜索栏组件(负责在每次按键时获取用户输入)
- 一个应用列表组件(显示所有应用/仅过滤的应用)
- 一个应用服务,负责一次从后端获取所有用户应用,然后从搜索栏组件获取搜索输入并更新 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);
}
}
这是我当前应用服务的实现。
我的 objective 是让 applist 组件订阅 appList,每当 searchbar 组件要求服务查找一个值时,applist 组件就会从 observable 中获取一个新的应用程序数组。
现在,由于管道函数 returns 是一个可观察对象,我无法将结果添加为行为主题的下一个值。
我还想听听您对这个特定实现的看法。谢谢!
我认为您的设计使问题看起来比实际更复杂。
数据流是一种方式:
HeaderComponent
-- searchTerm
--> AppService
-- apps
--> AppListComponent
我认为您只需要 AppService
中的 Subject
作为代理。 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()" />
应用-list.component.ts
constructor(private appService: AppService) {
}
apps$: Observable<Application[]> = this.appService.getSearchResults();
应用-list.component.html
<div *ngFor="let app of apps$ | async">
{{app.name}}
</div>
在问这个问题之前,我在这里做了一些研究,只发现有人问关于将搜索值传递给 rest API 并取回结果。
我的问题完全不同。我有两个组件和一个服务:
- 一个搜索栏组件(负责在每次按键时获取用户输入)
- 一个应用列表组件(显示所有应用/仅过滤的应用)
- 一个应用服务,负责一次从后端获取所有用户应用,然后从搜索栏组件获取搜索输入并更新 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);
}
}
这是我当前应用服务的实现。
我的 objective 是让 applist 组件订阅 appList,每当 searchbar 组件要求服务查找一个值时,applist 组件就会从 observable 中获取一个新的应用程序数组。
现在,由于管道函数 returns 是一个可观察对象,我无法将结果添加为行为主题的下一个值。
我还想听听您对这个特定实现的看法。谢谢!
我认为您的设计使问题看起来比实际更复杂。
数据流是一种方式:
HeaderComponent
-- searchTerm
--> AppService
-- apps
--> AppListComponent
我认为您只需要 AppService
中的 Subject
作为代理。 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()" />
应用-list.component.ts
constructor(private appService: AppService) {
}
apps$: Observable<Application[]> = this.appService.getSearchResults();
应用-list.component.html
<div *ngFor="let app of apps$ | async">
{{app.name}}
</div>