Home > front end >  How to cancel valueChanges in Angular and set the old value again?
How to cancel valueChanges in Angular and set the old value again?

Time:02-10

I subscribed to valueChanges of a mat-selection-list to be notified when the user selects a new list item. In some cases I ask the user if he/she really wants to select the new item via a confirmation dialog. If the user clicks "No" in this dialog, I need to cancel the selection of the new item. This is how I attempted to do this:

this.createForm.controls.selectionList.valueChanges.subscribe((value: number[]) => {
  const prevValue = this.createForm.controls.selectionList.value;

  if (<condition>) {
    const confirmDialogRef = this.dialog.open(ConfirmationDialogComponent, {
      data: "Do you really want to do this?",
    });

    confirmDialogRef.afterClosed().subscribe((confirmResult) => {
      if (confirmResult === true) {
        // User clicked yes, continue...
      } else {
        // User clicked no, set the previous value again...
        this.createForm.controls.selectionList.setValue(prevValue, { emitEvent: false });
      }
    });
  } else {
    // No user confirmation required, just continue...
  }
});

Unfortunately, this does not seem to work because prevValue seems to already be the new value when I try to set it as current value. What can I do instead to set the previous value again and basically just pretend that the user never even selected a new list item to begin with? Do I really have to cache the previous value manually, or is there a better way to do this?

CodePudding user response:

I think you can use the (openedChange) output event of mat-select to save the previous value when the user opens the mat-select dropdown and then use that value to restore to your previous value when the user does not confirm the change.

 <mat-select formControlName="selectionList" (openedChange)="savePreviousValue()">

In your .ts component, create a variable that stores the previous value, if by default there is any value, set it to that value, or if be default it is empty then it is undefined

//Can be set to default value wherever you fetch the data.
prevValue: any = undefined;

Then you can use this prevValue in your valueChanges subscription.

For the first time if the user does not confirm in the dialog, the prevValue will be used to set the value back to undefined, if the user confirms the dialog, then update the prevValue with the latest value so that it can be used the next time user does not confirm the change and so on.

CodePudding user response:

You subscribe() to a form value change - why? Where is the unsubscribe() for this?

If you try to get prevValue inside the subscribe() then it's true, that this.createForm.controls.selectionList.value is already the new value.

I would bind the data and then use ngOnChanges to read previous and current value. We could then place the if (<condition>) block into ngOnChanges. We also then can get rid of the subscription.

If possible I would call Event.stopPropagation() to cancel value change event or reassign selectionList.value to be previousValue from simpleChange.

That or use pairwise and just use the previous value.

observable // [1, 5, 2, 3]
  .pipe(
    pairwise() // [[1, 5], [5, 2], [2, 3]]
  )

CodePudding user response:

Probably this could be the better one. Also, Set this.prevValue after creating the form with the value you are getting initially otherwise it's [].

Try to avoid subscriptions inside the subscription for good performance.

private prevValue: number[] = [];

this.createForm.controls.selectionList.valueChanges.pipe(mergeMap((value: number[]) => {
    if (<condition>) {
    const confirmDialogRef = this.dialog.open(ConfirmationDialogComponent, {
      data: "Do you really want to do this?",
    });

    return confirmDialogRef.afterClosed();
  } else {
    // No user confirmation required, just continue...
    this.prevValue = value;
    return of(undefined);
  }
})).subscribe((confirmResult) => {
    if(confirmResult != undefined) {
      if (confirmResult === true) {
        // User clicked yes, continue...
        this.prevValue = this.createForm.controls.selectionList.value;
       } else {
        // User clicked no, set the previous value again...
        this.createForm.controls.selectionList.setValue(prevValue, { emitEvent: false });
      }
  }
});
  • Related