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 中的做法。一旦它开始向您显示结果,然后尝试逐一分析失误。

希望您能通过这种方式找到问题所在。