Reputation: 768
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>
Upvotes: 0
Views: 10156
Reputation: 551
This answer is based on an example from angular.material.io: https://material.angular.io/components/slide-toggle/examples
If you bind a variable from your component to the [(ngModel)]
property of the slide-toggle then you can simply change the value of that variable back to its previous state, which will update the UI accordingly.
In your HTML template you can set the slide-toggle like this:
<mat-slide-toggle [(ngModel)]="checked" (change)="postChangeToServer()">
Slide me!
</mat-slide-toggle>
And set up your component typescript like this:
@Component({
selector: 'slide-toggle-example',
templateUrl: 'slide-toggle-example.html',
})
export class SlideToggleExample {
checked = false;
postChangeToServer(): {
//Do your POST call here and handle the negative response with the line below
//For the sake of demonstration I've just set a one second timeout instead of making a server call
setTimeout(() => {
this.checked = !this.checked;
}, 1000);
}
}
Upvotes: 2