Angular - 2 种数据绑定 rxjs 主题 属性,从不在 child 上发出,但在 parent 上发出
Angular - 2 way data binding rxjs subject property, never emits on the child, yet emits on the parent
我在 parent 组件的模板中有这个自定义 child 组件:
parent html:
<cb-filter-chip-list [(filter-chips$)]="$ctrl.filterChips$"
[(filter-chip-adds)]="$ctrl.filterChipAdds"
[(filter-chip-deletes)]="$ctrl.filterChipDeletes"
[(current-chip-count)]="$ctrl.currentChipCount"
(update-data-behind-filter-chips)="$ctrl.updateDataBehindFilterChips($event)">
</cb-filter-chip-list>
parent ts:
public filterChips$ = new BehaviorSubject<Array<FilterChip>>(undefined);
public filterChipAdds = new ReplaySubject<any>(10);
public filterChipDeletes = new Subject();
child ts:
export class FilterChipListComponent implements OnInit {
@Input() public filterChips$: BehaviorSubject<Array<FilterChip>>;
@Input() public filterChipAdds: BehaviorSubject<any>;
@Input() public filterChipDeletes: Subject<any>;
@Output() public updateDataBehindFilterChips = new EventEmitter<FilterChip[]>();
createChip: Observable<any>;
deleteChip: Observable<any>;
chipVariations: Observable<unknown>;
@Input() public currentChipCount: any;
constructor() { }
public ngOnInit(): void {
this.createChip = this.filterChipAdds.pipe(map(chip => ([{ ...chip, action: 'add' }])));
this.deleteChip = this.filterChipDeletes.pipe(
tap((chipId) => this.updateDataBehindFilterChips.emit(chipId)),
map(chipId => ([{ id: chipId, action: 'delete' }])));
this.chipVariations = merge(this.createChip, this.deleteChip);
this.currentChipCount = this.chipVariations.pipe(
// startWith(this.filterChips$.value),
scan((totalCurrentChips: FilterChip[], changeInChips: ChipAction) => {
if (changeInChips[0].action === 'add') {
if (totalCurrentChips.some(tcc => tcc.id === changeInChips[0].id)) {
totalCurrentChips.forEach(element => {
if (element.id === changeInChips[0].id) {
element.text = changeInChips[0].text;
}
});
} else {
totalCurrentChips.push(changeInChips[0]);
}
} else if (changeInChips[0].action === 'delete') {
totalCurrentChips = totalCurrentChips.filter(chip => chip.id !== changeInChips[0].id);
}
return totalCurrentChips.sort((a, b) => a.sortOrder - b.sortOrder);
})
);
// console.log(this.filterChipAdds);
this.currentChipCount.subscribe();
this.filterChipAdds.subscribe(x => console.log("fc", x));
}
}
在 parent 中,我通过这样做让它发出:
this.filterChipAdds.next({
id: "fromDate",
sortOrder: 4,
text: `From Date - ${this.datePipe.transform(this.userCacheItem.silentData.fromDate, "dd MMM yyyy")
}`
});
出于某种原因,parent 控制台上的 this.filterChipAdds.subscribe(console.log);
会记录正在发出的值,但 this.filterChipAdds.subscribe(x => console.log("fc", x));
不会记录任何内容。 child 上没有任何东西发出。即使它在技术上应该同时发出,因为它是双向数据绑定。为什么发射没有反映在 child 组件上?
我认为双向绑定没有任何问题,它应该按照您期望的方式工作,即 child 组件的订阅也应该被触发。
现在我实际上使用了你的代码并尝试 运行 如果我注释了一些行它确实有效并且这让我认为如果你从你的 parent。因为一旦 observable 发出错误,它将停止发出新的项目,除非你已经正确处理了错误,而这里不是这种情况。
这就是我累的样子
在child个分量
@Input() public filterChips$: BehaviorSubject<Array<any>>;
@Input() public filterChipAdds: BehaviorSubject<any>;
@Input() public filterChipDeletes: Subject<any>;
@Output() public updateDataBehindFilterChips = new EventEmitter<any[]>();
createChip: Observable<any>;
deleteChip: Observable<any>;
chipVariations: Observable<unknown>;
@Input() public currentChipCount: any;
constructor() { }
public ngOnInit(): void {
// this.createChip = this.filterChipAdds.pipe(map(chip => ([{ ...chip, action: 'add' }])));
// this.deleteChip = this.filterChipDeletes.pipe(
// tap((chipId) => this.updateDataBehindFilterChips.emit(chipId)),
// map(chipId => ([{ id: chipId, action: 'delete' }])));
// this.chipVariations = merge(this.createChip, this.deleteChip);
// this.currentChipCount = this.chipVariations.pipe(
// // startWith(this.filterChips$.value),
// scan((totalCurrentChips: any[], changeInChips: any) => {
// if (changeInChips[0].action === 'add') {
// if (totalCurrentChips.some(tcc => tcc.id === changeInChips[0].id)) {
// totalCurrentChips.forEach(element => {
// if (element.id === changeInChips[0].id) {
// element.text = changeInChips[0].text;
// }
// });
// } else {
// totalCurrentChips.push(changeInChips[0]);
// }
// } else if (changeInChips[0].action === 'delete') {
// totalCurrentChips = totalCurrentChips.filter(chip => chip.id !== changeInChips[0].id);
// }
// return totalCurrentChips.sort((a, b) => a.sortOrder - b.sortOrder);
// })
// );
// console.log(this.filterChipAdds);
// this.currentChipCount.subscribe();
this.filterChipAdds.subscribe(x => console.log("fc", x));
}
在parent组件
filterChipAdds = new ReplaySubject<any>(10);
click(){
console.log('clicked');
this.filterChipAdds.next('aaa');
}
并且只是为了测试它的工作是否在 parent 组件中创建了一个按钮,该按钮将调用 parent 组件的方法,然后设置 observable 的值。
<button (click)="click()">Click</button>
我的建议是首先尝试注释掉所有行,然后只关注 filterChipAdds
我在 stackblitz 中的做法。一旦它开始向您显示结果,然后尝试逐一分析失误。
希望您能通过这种方式找到问题所在。
我在 parent 组件的模板中有这个自定义 child 组件:
parent html:
<cb-filter-chip-list [(filter-chips$)]="$ctrl.filterChips$"
[(filter-chip-adds)]="$ctrl.filterChipAdds"
[(filter-chip-deletes)]="$ctrl.filterChipDeletes"
[(current-chip-count)]="$ctrl.currentChipCount"
(update-data-behind-filter-chips)="$ctrl.updateDataBehindFilterChips($event)">
</cb-filter-chip-list>
parent ts:
public filterChips$ = new BehaviorSubject<Array<FilterChip>>(undefined);
public filterChipAdds = new ReplaySubject<any>(10);
public filterChipDeletes = new Subject();
child ts:
export class FilterChipListComponent implements OnInit {
@Input() public filterChips$: BehaviorSubject<Array<FilterChip>>;
@Input() public filterChipAdds: BehaviorSubject<any>;
@Input() public filterChipDeletes: Subject<any>;
@Output() public updateDataBehindFilterChips = new EventEmitter<FilterChip[]>();
createChip: Observable<any>;
deleteChip: Observable<any>;
chipVariations: Observable<unknown>;
@Input() public currentChipCount: any;
constructor() { }
public ngOnInit(): void {
this.createChip = this.filterChipAdds.pipe(map(chip => ([{ ...chip, action: 'add' }])));
this.deleteChip = this.filterChipDeletes.pipe(
tap((chipId) => this.updateDataBehindFilterChips.emit(chipId)),
map(chipId => ([{ id: chipId, action: 'delete' }])));
this.chipVariations = merge(this.createChip, this.deleteChip);
this.currentChipCount = this.chipVariations.pipe(
// startWith(this.filterChips$.value),
scan((totalCurrentChips: FilterChip[], changeInChips: ChipAction) => {
if (changeInChips[0].action === 'add') {
if (totalCurrentChips.some(tcc => tcc.id === changeInChips[0].id)) {
totalCurrentChips.forEach(element => {
if (element.id === changeInChips[0].id) {
element.text = changeInChips[0].text;
}
});
} else {
totalCurrentChips.push(changeInChips[0]);
}
} else if (changeInChips[0].action === 'delete') {
totalCurrentChips = totalCurrentChips.filter(chip => chip.id !== changeInChips[0].id);
}
return totalCurrentChips.sort((a, b) => a.sortOrder - b.sortOrder);
})
);
// console.log(this.filterChipAdds);
this.currentChipCount.subscribe();
this.filterChipAdds.subscribe(x => console.log("fc", x));
}
}
在 parent 中,我通过这样做让它发出:
this.filterChipAdds.next({
id: "fromDate",
sortOrder: 4,
text: `From Date - ${this.datePipe.transform(this.userCacheItem.silentData.fromDate, "dd MMM yyyy")
}`
});
出于某种原因,parent 控制台上的 this.filterChipAdds.subscribe(console.log);
会记录正在发出的值,但 this.filterChipAdds.subscribe(x => console.log("fc", x));
不会记录任何内容。 child 上没有任何东西发出。即使它在技术上应该同时发出,因为它是双向数据绑定。为什么发射没有反映在 child 组件上?
我认为双向绑定没有任何问题,它应该按照您期望的方式工作,即 child 组件的订阅也应该被触发。
现在我实际上使用了你的代码并尝试 运行 如果我注释了一些行它确实有效并且这让我认为如果你从你的 parent。因为一旦 observable 发出错误,它将停止发出新的项目,除非你已经正确处理了错误,而这里不是这种情况。 这就是我累的样子 在child个分量
@Input() public filterChips$: BehaviorSubject<Array<any>>;
@Input() public filterChipAdds: BehaviorSubject<any>;
@Input() public filterChipDeletes: Subject<any>;
@Output() public updateDataBehindFilterChips = new EventEmitter<any[]>();
createChip: Observable<any>;
deleteChip: Observable<any>;
chipVariations: Observable<unknown>;
@Input() public currentChipCount: any;
constructor() { }
public ngOnInit(): void {
// this.createChip = this.filterChipAdds.pipe(map(chip => ([{ ...chip, action: 'add' }])));
// this.deleteChip = this.filterChipDeletes.pipe(
// tap((chipId) => this.updateDataBehindFilterChips.emit(chipId)),
// map(chipId => ([{ id: chipId, action: 'delete' }])));
// this.chipVariations = merge(this.createChip, this.deleteChip);
// this.currentChipCount = this.chipVariations.pipe(
// // startWith(this.filterChips$.value),
// scan((totalCurrentChips: any[], changeInChips: any) => {
// if (changeInChips[0].action === 'add') {
// if (totalCurrentChips.some(tcc => tcc.id === changeInChips[0].id)) {
// totalCurrentChips.forEach(element => {
// if (element.id === changeInChips[0].id) {
// element.text = changeInChips[0].text;
// }
// });
// } else {
// totalCurrentChips.push(changeInChips[0]);
// }
// } else if (changeInChips[0].action === 'delete') {
// totalCurrentChips = totalCurrentChips.filter(chip => chip.id !== changeInChips[0].id);
// }
// return totalCurrentChips.sort((a, b) => a.sortOrder - b.sortOrder);
// })
// );
// console.log(this.filterChipAdds);
// this.currentChipCount.subscribe();
this.filterChipAdds.subscribe(x => console.log("fc", x));
}
在parent组件
filterChipAdds = new ReplaySubject<any>(10);
click(){
console.log('clicked');
this.filterChipAdds.next('aaa');
}
并且只是为了测试它的工作是否在 parent 组件中创建了一个按钮,该按钮将调用 parent 组件的方法,然后设置 observable 的值。
<button (click)="click()">Click</button>
我的建议是首先尝试注释掉所有行,然后只关注 filterChipAdds
我在 stackblitz 中的做法。一旦它开始向您显示结果,然后尝试逐一分析失误。
希望您能通过这种方式找到问题所在。