SMH*_*SMH 4 javascript rxjs angular
我有一个包含三个组件的页面:1.产品列表组件,该组件获取一些产品作为输入并显示它们。2.过滤器组件,它显示一些过滤器列表,例如(尺寸,颜色,...),并显示添加的过滤器。3.主要成分是根成分
假设某个用户添加了一个过滤器,该过滤器会触发一个http请求以获取新的过滤产品,而在请求未决时,他删除添加的过滤器,该过滤器将触发另一个http请求以获取所有产品如何取消第一个请求,因此我们不显示过滤后的产品?这是我的代码:
class FiltersService {
private _filters: any[];
get filters() {
return this._filters;
}
addFilter(filter) {
this._filters.push(filter);
}
removeFilter(filter) {
// Remove filter logic ...
}
}
class DataService_ {
constructor(private http: HttpClient) {
}
getProducts(filters) {
return this.http.post<any[]>('api/get-products', filters)
}
}
@Component({
selector: 'app-main',
template: `
<div>
<app-filters [filtersChanged]="onFiltersChange()"></app-filters>
<app-products-list [products]="products"> </app-products-list>
</div>
`
})
class MainComponent {
products: any[];
constructor(private dataService: DataService_, private filtersService: FiltersService) {
}
ngOnInit() {
this.setProducts()
}
setProducts() {
let filters = this.filtersService.filters;
this.dataService.getProducts(filters)
.subscribe(products => this.products = products)
}
onFiltersChange() {
this.setProducts();
}
}
@Component({
selector: 'app-filters',
template: `
<div>
Filters :
<ul>
<li *ngFor="let filter of filters" (click)="addFilter(filter)"> {{ filter.name }}</li>
</ul>
<hr>
Added Filters:
<ul>
<li *ngFor="let filter of filtersService.filters"> {{ filter.name }} <button (click)="removeFilter(filter)"> Remove</button></li>
</ul>
</div>
`
})
class FiltersComponent {
filters = [{ name: 'L', tag: 'size' }, { name: 'M', tag: 'size' }, { name: 'White', tag: 'colour' }, { name: 'Black', tag: 'colour' }]
@Output() filtersChanged = new EventEmitter()
constructor(public filtersService: FiltersService) {
}
addFilter(filter) {
const isAdded = this.filtersService.filters.find(x => x.name === filter.name);
if (isAdded) return;
this.filtersService.addFilter(filter);
this.filtersChanged.emit()
}
removeFilter(filter) {
this.filtersService.remove(filter);
this.filtersChanged.emit()
}
}
@Component({
selector: 'app-products-list',
template: `
<div>
<h1>Products</h1>
<ul *ngIf="products.length">
<li *ngFor="let product of products">
{{product.name }}
</li>
</ul>
</div>
`
})
class ProductsListComponent {
@Input() products
constructor() {
}
}
Run Code Online (Sandbox Code Playgroud)
长话短说:
处理这种情况的最简单方法是使用switchMap运算符。这样做是在发生新事件后立即取消内部订阅。
一种实现是:
class MainComponent {
products: any[];
private _filters$ = new Subject();
constructor(private dataService: DataService_, private filtersService: FiltersService) {
}
ngOnInit() {
this.setProducts()
}
setProducts() {
this._filters$
.switchMap((filters)=> this.dataService.getProducts(filters)) // or .let(switchMap...) if you are using rxjs >5.5
.subscribe(products => this.products = products);
}
onFiltersChange() {
this._filters$.next(this.filtersService.filters);
}
}
Run Code Online (Sandbox Code Playgroud)
很长的故事:
这里发生的是:当您更改过滤器时,会触发onFilterChange。然后,您通过_filters $主题(主题几乎与EventEmitter相同)发出最新的过滤器(在this.filtersService.filters内部)。
在组件初始化过程中,ngOnInit方法可以追溯到过去,它调用了setProducts,该方法已订阅_filters $主题以进行将来的事件(此时尚未发生)。当事件到达_filters $时,我们将触发dataservice的getProducts方法,并将事件中包含的过滤器传递给它。我们将在这条线上等待,直到http调用完成。一旦完成,http调用的结果将分配给该组件的产品。
如果在等待http响应返回时,再次触发onFiltersChange,则新事件将到达switchMap,并且它将取消先前的http请求,以便它可以处理新事件。
这是一种非常强大的方法,因为更改单个运算符可以轻松更改应用程序的行为。例如,将switchMap更改为concatMap将使请求等待上一个请求完成(将串行发生)。将其更改为flatMap将具有与您发布的原始代码相同的行为(HTTP请求将在过滤器发生更改时立即发生,而不会影响以前的请求,响应的顺序将不可预测)等等。
| 归档时间: |
|
| 查看次数: |
1779 次 |
| 最近记录: |