angularrxjsobserverssubjectsubject-observer

Calling .next() on an RxJS Subject which is of array type, does not notify observer


I am building a filter, where you can filter by categories, you can select a category by clicking the checkbox next to the name of the category.

So I have a filterComponent, which contains the filter it self, then a filterService, which has a categories property that is a Subject<Array<ICategory>>, this property is used to pass the data to the productsComponent where I am subscribed to the categories property.

This logic worked when I wanted to pass a simple string using this pattern, but it does not seem to work when I want to pass an array of objects.

In my filters.component.html file I am calling a method when the checkbox value is changing:

<li *ngFor="let category of categories">
        <mat-checkbox (change)="addOrRemoveCategory(category)" [(ngModel)]="category.isChecked">
                {{'category.' + category.Name | translate}}
        </mat-checkbox>
</li>

The addOrRemoveCategory method implementation looks as:

private addOrRemoveCategory(category: ICategory): void {
    if (!this.chosenCategories.includes(category)) {
        this.add(category);
    } else {
        this.remove(category);
    }
    this.filterService.categories.next(this.chosenCategories);
}

So whatever is happening to a category, being added or removed, (I internally modify the chosenCategories array and I am calling .next() with it's value), I am calling .next() with the updated array.

The problem is that, when the chosenCategories array is empty, and I push to it, and I call .next() with it, I correctly get the value in my subscriber function, but if this action is performed again, and I have a 2 elements array, and I call .next(this.chosenCategories), my subscriber method is not notified.

However my subscriber method is being notified again, once I am calling .next() with an empty array (because I have removed all my previously selected categories).

Subscriber method:

this.categoriesChangeSubscription = this.filterService.categories
            .pipe(
                debounceTime(500),
                distinctUntilChanged()
            )
            .subscribe((categories: Array<ICategory>) => {
                this.categories = categories.map(category => category.Name);
                this.loadData();
            });

Am I doing something wrong? Do I have to handle working with arrays differently than strings?

Conclusion: if my array that I use as argument for .next() changes:


Solution

  • My guess is that distinctUntilChanged() filters out your changed array because technically it is the same object as before.

    You may solve it by cloning the array:

    this.filterService.categories.next([...this.chosenCategories]);
    

    More solutions under a similar question.