0
votes

I'm working on an Angular 8 Web App where a setting in the DB is either true or false. I want to update that value using a toggle/checkbox element when the toggle is changed - i.e. the request is sent immediately.

I have narrowed my problem down to the fact that the property I am setting in the view via [ngModel]="selectedView" isn't being set when the patch request is sent, the patch isn't giving the toggle enough time to set the property.

How can I delay the event so that the selectedView property is set and then updates the object successfully? As in the network-tab shows an empty payload object.

I notice this works if I set a button alongside the toggle and let the event off from the button, rather than the toggle. But I think this is a little overkill for what I need the toggle for. Toggle then click button is pretty poor UX, to me.

nav_bar.component.html

    <li *ngIf="config">
        <p><small>Show Match Hub {{ selectedView }}</small></p>
        <label class="switch">
            <input 
            type="checkbox"
            [(ngModel)]="selectedView"
            [checked]="config.hide_match === 1"
            (change)="config.hide_match = config.hide_match ? 1 : 0" value="hide_match"
            (click)="switchMatchHub(selectedView)"
            >
            <span class="slider"></span>
        </label>
    </li>

nav_bar.component.ts (click event)

selectedView: any;

switchMatchHub(){
    const updateView = {
      'hide_match': this.selectedView
    }
    this.configService.showMatch(updateView)
    .subscribe(
      response => {
        console.log(response);
      }
    )
 }

service.ts

showMatch(newConfig: any){
    return this.http.patch<{data: Config}>(this.configURL + '/' + this.id, newConfig)
    .pipe(
      retry(1),
      catchError(this.handleError),
    );
  }

Could I wrap the request in a TimeOut? or is that a little poor too? Does anyone have an idea of how this could work?

1
You could use a reactive form, and simply pipe onto the valueChanges Observable of the checkbox. That way, you can control how multiple clicks get processed, for example. - Will Alexander
Thanks Will, started the ball rolling and got this fixed. Thanks for your help. - Apex

1 Answers

0
votes

Use reactive forms. Use reactive forms to begin with, but especially for this use case. Then you can simply do:

this.formControl.valueChanges.pipe(
   // handle "monkey-clicking" the selectbox
   debounceTime(200), 
   // if the user clicks it on and back of again quickly, ignore it all together.
   distinctUntilChanges(),
   // Map it to your object notation 
   map(toggle => ({'hide_match': toggle})),
   // Switch map it to server uploads. SwitchMap cancels any previous requests in case the checkbox is changed, so the order of events doesn't screw up your server status.
   switchMap(updateView => this.configService.showMatch(updateView))
).subscribe(() => {});