J-man
J-man

Reputation: 1833

Reactive Form Changes Angular 2

I have a reactive form that I want to detect changes for. For example, when a user views a product, a "view product" page opens filling in all form fields with the details of that product. If a change is made to any value in the form, I want a "Save" button to be enabled (it is disabled by default). However, if the user undos the changes or reverts back to what it was on load, the Save button will be disabled again.

Is this possible? I've seen some people do it where angular detects form changes and makes the form "dirty" but once the form has been dirtied it isn't easy or intuitive to change the state back to pristine. I've also read where people load the initial product details into local storage and compare the form values JSON of the current state to the local storage JSON and enable/disable buttons based on that. Does anyone have a preferred or better method?

Thanks

Upvotes: 2

Views: 2020

Answers (2)

Michael Dimmitt
Michael Dimmitt

Reputation: 1054

Building on what BeetleJuice mentioned:

Finding out what is dirty: JSON stringify comparison works for deeply nested objects and seems less expensive than tracking all form controls individually because of all the observables that would be created that the browser needs to watch.

  patchValueLocation(yourFormValues){
    this.form.patchValue(yourFormValues);
    this.createReference(this.formGroup.value)
    this.loading = false;
  }

  private createReference(obj: any){
    this.reference = JSON.stringify(obj)
  }

  ngOnInit() {
    this.form.valueChanges.subscribe(newValues=> {
      if(!this.loading){
        const hasChanges = !( JSON.stringify(newValues) === this.reference );
        this.dirty = hasChanges;
      }
    })
  }

You can listen to individual form controls too as seen in this document.

https://alligator.io/angular/reactive-forms-valuechanges

ngOnInit(): void {
  this.myForm.get('name').valueChanges.subscribe(val => {
    this.formattedMessage = `My name is ${val}.`;
  });
}

Upvotes: 2

BeetleJuice
BeetleJuice

Reputation: 40896

When the initial data arrives, save it locally as a component property. You can then compare it to the form's current values at any time to figure out whether there has been a change.

You'll need:

  • initValues, the starting form values (before user interaction)

  • disableSaveBtn:boolean property that is bound to the button in the template with: [disabled]="disableSaveBtn"

  • valuesMatch(val1,val2):boolean function that will compare two models of the form and return true if they match

Do the comparison each time the form value change. Since you're using reactive forms, you can just listen to the valueChanges observable

// will emit every time a form control value is changed
this.form.valueChanges.subscribe(newValues => {
    // disable the button if new value matches initial value
    this.disableSaveBtn = this.valuesMatch(newValues, initValues)
})

Upvotes: 4

Related Questions