I have a table that has a slide toggle inside of it that loads as toggled/not toggled based on data I am getting back from an API. This works as expected. The user can then toggle this switch, which causes a POST request to be sent to an API. If this POST fails, I want to reset the toggle switch to whatever position it originally loaded in. I am attempting this by emitting the original observable again on failure. I have verified through the console in the browser that this gives the toggle the value I expect, however the slider does not move accordingly.
At this point I am questioning if I am going about this the right way, as the toggle position does not seem to be affected by the value it's bound to if that value changes. I noticed that the mat slide toggle has a built in toggle()
method, should I be calling this instead? I want to know the proper way to manage the slide toggle's position as I cannot find any documentation on it.
Component.ts
ngOnInit() {
const lastItems$ = new ReplaySubject(1);
const getItemsAndCache = () => {
return this.myService
.getItems(this.accountId)
.pipe(
tap(itemsRes => lastItems$.next([...itemsRes])
)
)
};
geItemsAndCache().subscribe(items => lastItems$.next(items));
const updatedItems$ = this.itemChangeSubject.asObservable().pipe(
exhaustMap(itemChange =>
this.myService.changeItemToggle(
this.accountId,
itemChange.item.id
)
.pipe(
mergeMap(() => getItemsAndCache()),
catchError(() => lastItems$.pipe(first())
))
)
)
this.items$ = concat(lastItems$.pipe(first()), updatedItems$) as Observable<MyItem[]>;
}
onToggleChange(item: MyItem) {
this.itemChangeSubject.next({ item });
}
Component.html
<my--custom-table
[items]="items$ | async"
[displayedColumns]="displayedColumns"
[paginationOptions]="paginationOptions"
>
<ng-container matColumnDef="status">
<mat-header-cell *matHeaderCellDef>Status</mat-header-cell>
<mat-cell *matCellDef="let item">
{{ item.status }}
</mat-cell>
</ng-container>
<ng-container matColumnDef="toggled">
<mat-header-cell *matHeaderCellDef>Toggled?</mat-header-cell>
<mat-cell *matCellDef="let item">
<span>{{item.toggled}}</span>
<mat-slide-toggle
[(ngModel)]="item.toggled"
[disabled]="clicked"
(change)="onToggleChange(item); clicked = true"
></mat-slide-toggle>
</mat-cell>
</ng-container>
</my-custom-table>
private lockChangeSubject: ReplaySubject<{ item: MyItem; }> = new ReplaySubject();
I didn't think I needed to explicitly set item.toggled, as I am settingthis.items$
instead. My initial GET API call (getItemsAndCache()
) returns$items
which is then passed to my table to iterate over, and one of the props on each item istoggled
. On failure of my POST, I catch the error andlastItems$.pipe(first())
, which should emit the original observable – Joshthis.items$ = concat(lastItems$.pipe(first()), updatedItems$) as Observable<MyItem[]>;
should change $items, which should then update the table, and the toggle, accordingly since I am using an async pipe. – Josh