取消订阅同一组件中的可观察但具有动态参数
Unsubscribe observable in the same component but with dynamic parameters
FILTER SERVICE - 可观察到基本数据过滤
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { Filter } from '../../models/filter.model';
import { Convert } from '../../utils/converter';
@Injectable({
providedIn: 'root'
})
export class FilterService {
private currentFilter$ = new BehaviorSubject<Filter>({
page: 0,
limit: 20
});
constructor() { }
private init(name: string) {
let filterStr = localStorage.getItem(name);
if (filterStr) {
this.currentFilter$.next(Convert.fromJson<Filter>(filterStr))
} else {
localStorage.setItem(name, Convert.ToJson<Filter>(this.currentFilter$.value));
}
}
private saveFilter(name: string, filter: Filter) {
this.currentFilter$.next(filter);
localStorage.setItem(name, Convert.ToJson<Filter>(filter));
}
public getFilter(name: string) : Observable<Filter> {
this.init(name);
return this.currentFilter$;
}
public nextPage(name: string) {
let filter = this.currentFilter$.value;
filter.page = filter.page + 1;
this.saveFilter(name, filter);
}
public pageLimit(name: string, limit: number) {
let filter = this.currentFilter$.value;
filter.limit += limit;
this.saveFilter(name, filter);
}
public scroll() {
let filter = this.currentFilter$.value;
filter.limit += 20;
this.currentFilter$.next(filter);
}
public resetPage(name: string) {
let filter = this.currentFilter$.value;
filter.page = 0;
filter.limit = 20;
this.saveFilter(name, filter);
}
public search(name: string, search: string) {
let filter = this.currentFilter$.value;
filter.search = search;
filter.page = 0;
filter.limit = 20;
this.saveFilter(name, filter);
}
public sort(name: string, column: string, direction: string) {
let filter = this.currentFilter$.value;
filter.limit = 20;
filter.page = 0;
if (direction != '') {
filter.orderBy = column + ' ' + direction;
} else {
filter.orderBy = undefined;
}
this.saveFilter(name, filter);
}
}
文档路径 - 此组件具有动态参数type
:302 = 发票,306 = 送货单等
{ path: 'documents/:type', component: DocumentsComponent },
文档组件
@Component({
selector: 'app-documents',
templateUrl: './documents.component.html',
styleUrls: ['./documents.component.scss']
})
export class DocumentsComponent extends Unsubscriber implements OnInit {
displayedColumns: string[] = ['number', 'customerName', 'date', 'paymentDate', 'settledStatus', 'net', 'vat', 'gross'];
documentsDataSource: Document[] = [];
sortColumn = '';
sortDirection: SortDirection = '';
searchText = '';
title = '';
filters?: FilterItem[] = [];
type = 0;
constructor(
private documentsService: DocumentsService,
private filterService: FilterService,
private route: ActivatedRoute,
private router: Router
) {
super();
this.route.params.subscribe((params) => {
this.type = params["type"];
this.title = this.getTitle(params["type"]);
this.filterService.getFilter(`documents:${this.type}`).subscribe((filter) => {
if (filter.orderBy) {
this.sortColumn = filter.orderBy.split(" ")[0];
this.sortDirection = filter.orderBy.split(" ")[1] === "asc" ? "asc" : "desc";
}
if (filter.search) {
this.searchText = filter.search;
}
this.subscription.add(this.documentsService.getDocuments(filter, params["type"]).subscribe(result => {
this.documentsDataSource = result;
}));
});
});
}
退订
import { Injectable, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';
@Injectable()
export abstract class Unsubscriber implements OnDestroy {
subscription = new Subscription();
constructor() { }
ngOnDestroy(): void {
console.log("unsubscribe");
if (this.subscription) {
this.subscription.unsubscribe();
}
}
}
RESULT - 随着文档上下文中路由(参数)的每次更改,我都会获得对过滤器和文档的 +1 订阅,因为 Unsubscriber
永远不会叫。如果我在不同组件之间更改路线,例如 Products
或 Customers
,然后返回 Documents
,一切都很好。
我应该如何解决这个问题?
我在这里看到了一些 anti-patterns,这可能是您的问题的一部分。
您正在其他 .subscribe()
回调中创建订阅。应该始终通过将 switchMap
等其他 RxJS 运算符链接在一起来避免这种情况。
this.subscription.add(this.route.params.pipe(
switchMap((params) => {
this.type = params["type"];
this.title = this.getTitle(params["type"])
return combineLatest([this.filterService.getFilter(`documents:${this.type}`), of(params])
}),
switchMap(([filter, params]) => {
if (filter.orderBy) {
this.sortColumn = filter.orderBy.split(" ")[0];
this.sortDirection = filter.orderBy.split(" ")[1] === "asc" ? "asc" : "desc";
}
if (filter.search) {
this.searchText = filter.search;
}
return this.documentsService.getDocuments(filter, params["type"])
})
).subscribe(result => {
this.documentsDataSource = result
}))
现在您只有 1 个订阅可以添加到 this.subscription
。
FILTER SERVICE - 可观察到基本数据过滤
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { Filter } from '../../models/filter.model';
import { Convert } from '../../utils/converter';
@Injectable({
providedIn: 'root'
})
export class FilterService {
private currentFilter$ = new BehaviorSubject<Filter>({
page: 0,
limit: 20
});
constructor() { }
private init(name: string) {
let filterStr = localStorage.getItem(name);
if (filterStr) {
this.currentFilter$.next(Convert.fromJson<Filter>(filterStr))
} else {
localStorage.setItem(name, Convert.ToJson<Filter>(this.currentFilter$.value));
}
}
private saveFilter(name: string, filter: Filter) {
this.currentFilter$.next(filter);
localStorage.setItem(name, Convert.ToJson<Filter>(filter));
}
public getFilter(name: string) : Observable<Filter> {
this.init(name);
return this.currentFilter$;
}
public nextPage(name: string) {
let filter = this.currentFilter$.value;
filter.page = filter.page + 1;
this.saveFilter(name, filter);
}
public pageLimit(name: string, limit: number) {
let filter = this.currentFilter$.value;
filter.limit += limit;
this.saveFilter(name, filter);
}
public scroll() {
let filter = this.currentFilter$.value;
filter.limit += 20;
this.currentFilter$.next(filter);
}
public resetPage(name: string) {
let filter = this.currentFilter$.value;
filter.page = 0;
filter.limit = 20;
this.saveFilter(name, filter);
}
public search(name: string, search: string) {
let filter = this.currentFilter$.value;
filter.search = search;
filter.page = 0;
filter.limit = 20;
this.saveFilter(name, filter);
}
public sort(name: string, column: string, direction: string) {
let filter = this.currentFilter$.value;
filter.limit = 20;
filter.page = 0;
if (direction != '') {
filter.orderBy = column + ' ' + direction;
} else {
filter.orderBy = undefined;
}
this.saveFilter(name, filter);
}
}
文档路径 - 此组件具有动态参数type
:302 = 发票,306 = 送货单等
{ path: 'documents/:type', component: DocumentsComponent },
文档组件
@Component({
selector: 'app-documents',
templateUrl: './documents.component.html',
styleUrls: ['./documents.component.scss']
})
export class DocumentsComponent extends Unsubscriber implements OnInit {
displayedColumns: string[] = ['number', 'customerName', 'date', 'paymentDate', 'settledStatus', 'net', 'vat', 'gross'];
documentsDataSource: Document[] = [];
sortColumn = '';
sortDirection: SortDirection = '';
searchText = '';
title = '';
filters?: FilterItem[] = [];
type = 0;
constructor(
private documentsService: DocumentsService,
private filterService: FilterService,
private route: ActivatedRoute,
private router: Router
) {
super();
this.route.params.subscribe((params) => {
this.type = params["type"];
this.title = this.getTitle(params["type"]);
this.filterService.getFilter(`documents:${this.type}`).subscribe((filter) => {
if (filter.orderBy) {
this.sortColumn = filter.orderBy.split(" ")[0];
this.sortDirection = filter.orderBy.split(" ")[1] === "asc" ? "asc" : "desc";
}
if (filter.search) {
this.searchText = filter.search;
}
this.subscription.add(this.documentsService.getDocuments(filter, params["type"]).subscribe(result => {
this.documentsDataSource = result;
}));
});
});
}
退订
import { Injectable, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';
@Injectable()
export abstract class Unsubscriber implements OnDestroy {
subscription = new Subscription();
constructor() { }
ngOnDestroy(): void {
console.log("unsubscribe");
if (this.subscription) {
this.subscription.unsubscribe();
}
}
}
RESULT - 随着文档上下文中路由(参数)的每次更改,我都会获得对过滤器和文档的 +1 订阅,因为 Unsubscriber
永远不会叫。如果我在不同组件之间更改路线,例如 Products
或 Customers
,然后返回 Documents
,一切都很好。
我应该如何解决这个问题?
我在这里看到了一些 anti-patterns,这可能是您的问题的一部分。
您正在其他 .subscribe()
回调中创建订阅。应该始终通过将 switchMap
等其他 RxJS 运算符链接在一起来避免这种情况。
this.subscription.add(this.route.params.pipe(
switchMap((params) => {
this.type = params["type"];
this.title = this.getTitle(params["type"])
return combineLatest([this.filterService.getFilter(`documents:${this.type}`), of(params])
}),
switchMap(([filter, params]) => {
if (filter.orderBy) {
this.sortColumn = filter.orderBy.split(" ")[0];
this.sortDirection = filter.orderBy.split(" ")[1] === "asc" ? "asc" : "desc";
}
if (filter.search) {
this.searchText = filter.search;
}
return this.documentsService.getDocuments(filter, params["type"])
})
).subscribe(result => {
this.documentsDataSource = result
}))
现在您只有 1 个订阅可以添加到 this.subscription
。