在angular中,我有负责查询参数更改的抽象类:
@Injectable()
export abstract class PageDetailsAbstract<T> implements OnInit {
object: string;
id: number;
details$: Observable<T>;
constructor(
protected entitiesSelectors: EntitiesSelectors) {
}
ngOnInit() {
this.route.params
.pipe(
map(resp => +resp.id),
)
.subscribe(resp => {
this.id = resp;
this.adopt();
});
}
protected adopt() {
if (this.id) {
this.details$ = this.entitiesSelectors.details(this.object, this.id);
}
}
}
对于详细信息页面,我也有具体的课程:
@Component({
selector: 'app-page-maile-szczegoly',
templateUrl: './page-maile-szczegoly.component.html',
styles: [],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class PageMailsDetailComponent extends PageDetailsAbstract<Mail> {
object = 'mails';
// ...
ngOnInit() {
super.ngOnInit();
this.details$
.subscribe(data => {
// do something with it
// it's triggered only once
});
}
}
问题是subscribe
中的ngOnInit
仅被触发一次。这是因为父类中有this.details$ = this.entitiesSelectors.details(this.object, this.id);
。 this.detials$
的实例及其subscribe
函数被销毁。
如何总是拥有this.details$
的相同实例,却总是用this.entitiesSelectors.details(this.object, this.id)
来纠正一个实例?
答案 0 :(得分:1)
您可以使用Subject
(http://reactivex.io/rxjs/class/es6/Subject.js~Subject.html)
我创建了一个非常简化的stackblitz以显示其工作原理 https://stackblitz.com/edit/angular-zyvkpu?file=src%2Fapp%2Fapp.component.ts
查看控制台输出以进行验证。
这是相关的代码部分(适应您的情况,而不是stackblitz的1:1)
@Injectable()
export abstract class PageDetailsAbstract<T> implements OnInit {
object: string;
id: number;
details$: Subject<T> = new Subject<T>();
constructor(
protected entitiesSelectors: EntitiesSelectors) {
}
ngOnInit() {
this.route.params
.pipe(
map(resp => +resp.id),
)
.subscribe(resp => {
this.id = resp;
this.adopt();
});
}
protected adopt() {
if (this.id) {
this.entitiesSelectors.details(this.object, this.id).subscribe((detail: T) => {
this.details$.next(detail);
});
}
}
我个人将对代码进行一些重组。
这是一个更清洁的选择,因为您不会嵌套对subscribe
的多次调用,而且您不会(至少不会那么依赖)存在于rxjs流之外的this.id
。
到
@Injectable()
export abstract class PageDetailsAbstract<T> implements OnInit {
object: string;
id: number;
details$: Subject<T> = new Subject<T>();
constructor(
protected entitiesSelectors: EntitiesSelectors) {
}
ngOnInit() {
this.route.params
.pipe(
mergeMap((resp: any) => {
return this.adopt(+resp.id);
}))
.subscribe((detail: T) => {
this.details$.next(detail);
});
}
protected adopt(id: number): Observable<T> {
if (this.id) {
return this.entitiesSelectors.details(this.object, this.id);
}
else {
return of(null); // or whatever is appropriate in your case (e.g. EMPTY or something)
}
}
您的子类将保持不变。
为什么
至于为什么您的示例不起作用:
我认为这是因为details$
实在是太冷了。 (https://blog.thoughtram.io/angular/2016/06/16/cold-vs-hot-observables.html)
当您重新分配details$
时,您将创建一个新的可观察对象,并且先前进行的订阅没有意义,因为它是用于另一个可观察对象的。您需要重新订阅。
Subject
非常热门。
也许您也可以使用publish
或share
之类的东西将您的冷观测值转换为高温观测值。