0
votes

i want to ask user before he changes to any form control using reactive form.

lets say when you type/select in input/select box it should show the alert first saying 'do you want to make this change' if user says yes then only update form control.

I have achieved it using template driven form but not able to do it using reactive forms.

https://stackblitz.com/edit/angular-nyohjv?file=src%2Fapp%2Fapp.module.ts

code

<div class="container-fluid template-driven-form">
  <h4>Form control value change prevent in template driven form</h4>
  <select [ngModel]="selectedDevice" (ngModelChange)="onDeviceChange($event)" name="sel2">
    <option [value]="i" *ngFor="let i of devices">{{i}}</option>
  </select>
  <h6>{{selectedDevice}}</h6>

  <input type="text" class="from-control" [ngModel]="textValue" (ngModelChange)="onChange($event)">

  <h6>{{textValue}}</h6>
</div>

<div class="container-fluid">
  <h4>Form control value change prevent in reactive form</h4>

  <form [formGroup]="reactiveForm">
    <div class="form-group">
      <label for="">Example without startWith</label>
      <input type="text" class="form-control" formControlName='example1'>
    </div>
  </form>

  <pre>{{reactiveForm.value | json}}</pre>
</div>
import { Component, OnInit, ChangeDetectorRef } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { pairwise, startWith } from 'rxjs/operators';

@Component({
  selector: 'kar-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
  textValue = '2';

  selectedDevice = 'd2';

  devices = ['d1', 'd2', 'd3'];

  reactiveForm: FormGroup;

  constructor(
    private changeDetectorRef: ChangeDetectorRef,
    private fb: FormBuilder
  ) {}

  onChange(val) {
    console.log('PREV1', this.textValue);
    // this.textValue = val;
    console.log('NEXT1', val);
    console.log('----');

    console.log(val);
    if (confirm('device value will be changed')) {
      this.textValue = val;
    } else {
      const temp = this.textValue;
      this.textValue = '1';
      this.changeDetectorRef.detectChanges();
      this.textValue = temp;
      this.changeDetectorRef.detectChanges();
    }
  }

  onDeviceChange(val) {
    console.log(val);
    if (confirm('device value will be changed')) {
      this.selectedDevice = val;
    } else {
      const temp = this.selectedDevice;
      this.selectedDevice = '1';
      this.changeDetectorRef.detectChanges();
      this.selectedDevice = temp;
      this.changeDetectorRef.detectChanges();
    }
  }

  ngOnInit() {
    // setTimeout(() => {
    //   this.selectedDevice = 'd3';
    // }, 2000);
    this.reactiveForm = this.fb.group({
      example1: ['']
      // example2: ['']
    });

    // this.reactiveForm.get('example1').valueChanges.subscribe(val => {
    //   console.log('example 1', val);
    // });

    // this.reactiveForm.get('example2').valueChanges.subscribe(val => {
    //   console.log('example 2', val);
    // });
    const control = this.reactiveForm.get('example1');

    control.valueChanges
      .pipe(startWith(''), pairwise())
      .subscribe(([prev, cur]) => {
        console.log('example 1 prev val', prev);
        console.log('example 1 cur val', cur);
        console.log('---');

        if (confirm('value will be changed')) {
        } else {
          control.setValue(prev, { emitEvent: false });
        }
      });
  }
}

1
Did you omitted to add (ngModelChange)="onChange($event)" on your reactive form's input ? - Alexis
with pairwise work in your stackblitz :( - Eliseo
@eliseo.. Its not working properly using pairwise operator. Try clicking cancel couple of times you will see the problem - kartik4

1 Answers

0
votes

If emitEvent is set to true then it will do the job. To avoid going into valueChanges infinitely, you may use a boolean. For example showAlert in the following:

var showAlert = true;
control.valueChanges ...

    if(showAlert)
    {
    
      if (confirm('value will be changed')) {
      } else {
        //control.setValue(null, {emitEvent:true})
        showAlert = false;
        control.setValue(prev, { emitEvent: true });
      }
    }
    else
    {
      showAlert  = true;
    }

  }...