Home > other >  Disable submit button until form value changes and reverts in Angular
Disable submit button until form value changes and reverts in Angular

Time:02-02

The submit button should be disabled until one value changes at least. I have found the solution:

<button [disabled]="!form.dirty">Submit</button>

But, the problem is that if the user deletes the changes and uses the existing values, it won't make the button disable again. For example, in the app.component.html file:

<form [formGroup]="createForm">
  <label for="email">formText</label>
  <input type="email"  formControlName="formText" />
  <br />
  <label>List</label>
  <input type="email"  formControlName="list" />
</form>
<button [disabled]="createForm.invalid || !createForm.dirty">Submit</button>
<h3>{{ someError }}</h3>

and in the app.component.ts file:

ngOnInit() {
    this.createForm = this.formBuilder.group({
      formText: ['hello', Validators.required],
      list: [10, Validators.required],
    });
  }
}

These generate this output:

If the user changes the value for example 11 in the second input; the disabled state has been removed as expected.

But, if the user reverts the changes (so the input value is 10 again), I want to add the disabled state in the button again. How to do that?

Code Demo

CodePudding user response:

You could do something like this:

export class MyComponent {
  originalValue = '';
  inputValue = '';

  ngOnInit() {
    this.originalValue = this.inputValue;
  }

  isButtonDisabled() {
    return this.inputValue !== this.originalValue;
  }
}
<form>
  <input [(ngModel)]="inputValue">
  <button [disabled]="isButtonDisabled()">Submit</button>
</form>

CodePudding user response:

Maybe something like this:

interface FormModel {                   // (1)
    formText: string;
    list: number;
}


private originalFormValue: FormModel;   // (2)
form?: FormGroup<FormModel>;

submitDisabled$: Observable<boolean>;   // (3)



constructor() {
    this.form = this.formBuilder.group({
        formText: ['hello', Validators.required],
        list: [10, Validators.required]
    }); 
    
    this.originalFormValue = this.form.value;   // (4)

    this.submitDisabled$ = this.form.valueChanges.pipe(        // (5)
        map(value => this.objectsAreEquals(value, this.originalFormValue) || this.form.inalid)
    );
}


private objectsAreEquals(model1: FormModel, model2: FormModel): boolean {
   ... do the comparison here (you could use a library like lodash, e.g. https://www.geeksforgeeks.org/lodash-_-isequal-method/)
}

and in the template:

...
<button [disabled]="submitDisabled$ | async">Submit</button>
...

(1) the datamodel for the form (since angular 14 forms are typed)
(2) contains the original form-value to compare with
(3) an observable, which emits boolean-values (true, if the submit-button should ebe disabled)
(4) save the original value (such that you can compare it, when the form-value changes)
(5) this is the tricky part for beginners:

  • form.valueChanges returns an Observable, which emits a new value each time any of the form-fields changes value. It contains the values of all fields (to be precise: the value of all enabled form-fields)
  • using the map-operator you convert this FormModel into a boolean by comparing it with the original value and checking the invalid-flag of the form)
  • Related