2

I have a form with different input fields including input[type="file"] and input[type="checkbox"]. I get values of input form fields with get request from backend and I store them in company variable.

ngOnInit(): void {
    this.generateForm();

    this.companyService.getCompany().subscribe((response: Company) => {
      this.company = response;

      this.settingsForm.setValue({
        ...this.company,
        certificateUrl: [this.company.certificateUrl],
      });
    });
  }

I first generate form and then get my response from get request so I could set my company variable to the response and set value of form based on values I got. The problem is I want to enable button in html whenever my form is valid and changed. So button should be disabled when no change is made based on previous value. For example: If we have field name with value 'myName' and I type into input 'my' button should be enabled because change is made comparing to previous value. If I type back 'myName' it should be disabled because value is the same as previous. Same should happen if field is empty and user types in something and for fields type file and checkbox.

This is how I'm currently trying to do it.

inputChanged: boolean = false

ngOnInit() {
    this.settingsForm.valueChanges.subscribe((currentValue) => {
      if (JSON.stringify(currentValue) !== JSON.stringify(this.company)) {
        this.inputChanged = true;
      } else {
        this.inputChanged = false;
      }
    });
}
////

 <button
          [disabled]="!inputChanged || !settingsForm.valid"
          class="btn btn-md text-light"
        >
          Save
        </button>

This is my form

<form class="mt-4" [formGroup]="settingsForm" (ngSubmit)="saveChanges()">
    <div class="row">
      <div class="col-6">
        <div class="form-group">
          <label class="form-label fw-bold">ID</label>
          <input
            formControlName="identificationNumber"
            type="text"
            class="form-control"
          />
        </div>
        <div class="form-group d-none">
          <label class="form-label fw-bold">Id</label>
          <input formControlName="id" type="text" class="form-control" />
        </div>
        <div class="form-group d-none">
          <label class="form-label fw-bold">Country</label>
          <input formControlName="country" type="text" class="form-control" />
        </div>

        <div class="form-group">
          <label class="form-label fw-bold"
            >P</label
          >
          <input formControlName="tin" type="text" class="form-control" />
 
        </div>
        <div class="form-group">
          <label class="form-label fw-bold">Name</label>
          <input formControlName="name" type="text" class="form-control" />
        </div>
      </div>
      <div class="col-6">
        <div class="form-group">
          <label class="form-label fw-bold">City</label>
          <input formControlName="city" type="text" class="form-control" />
        </div>

        <div class="form-group">
          <label class="form-label fw-bold">Address</label>
          <input formControlName="address" type="text" class="form-control" />
        </div>
        <div class="form-group">
          <label class="form-label fw-bold">Postal code</label>
          <input
            formControlName="postalCode"
            type="text"
            class="form-control"
          />
        </div>
        <div class="form-check ms-1">
          <label class="form-check-label fw-bold">Vat</label>
          <input
            formControlName="inVat"
            type="checkbox"
            class="form-check-input"
            [checked]="company?.inVat"
          />
        </div>
      </div>
    </div>

    <div class="row align-items-end justify-content-between">
      <div class="col-8">
        <app-file-upload
          [company]="company"
          formControlName="certificateUrl"
        ></app-file-upload>
      </div>

      <div class="col-4">
        <button
          [disabled]="!inputChanged || !settingsForm.valid"
          class="btn btn-md text-light"
        >
          Save changes
        </button>
      </div>
    </div>
  </form>

But it doesn't work. How can I fix this?

Kate
  • 45
  • 1
  • 8
  • How is your form structured? Is the form perhaps still valid after your changes back to the way it was before? – Daniel B Mar 23 '22 at 10:50
  • I edited the question so you could see the form. My button is only disabled when I save changes and when my fields are empty. It's like it doesn't check if values are different at all – Kate Mar 23 '22 at 10:55

3 Answers3

4

You could make use of other reactive Form attributes

Using pristine for example

A control is pristine if the user has not yet changed the value in the UI.

<button
  [disabled]="settingsForm.pristine || settingsForm.invalid"
  class="btn btn-md text-light"
  >Save</button>

if you need to be more specific in the control values, it becomes more tricky as comparing Javascript objects is not as trivial.

This question is a great deep dive

The Fabio
  • 5,369
  • 1
  • 25
  • 55
  • To be noted though, a control that goes from pristine -> dirty wont go back to pristine if you input the same value, so I don't think this would work. – Daniel B Mar 23 '22 at 11:06
  • @DanielB That's the reason for the links on comparing js objects I added... Reactive Forms do not compare values, they just change state as the user interact with them. – The Fabio Mar 23 '22 at 11:10
0

The reactive form should have a valid and touched attribute and could be used as following.

<button
  [disabled]="!settingsForm.touched || settingsForm.invalid"
  class="btn btn-md text-light">Save</button>
MikkelDalby
  • 142
  • 2
  • 11
  • Let's say my form starts with input with value 'name'. When I remove name and input is empty, my button is disabled because form is not valid(fields are required). When I type back 'name' it is enabled which it shouldn't be since it is the same value I had before. So this approach doesn't work for me. – Kate Mar 23 '22 at 11:03
0

I found a solution using objectHash. First install it with npm i -D @types/hash.

import * as objectHash from 'object-hash';

this.settingsForm.valueChanges.subscribe((currentValue) => {
      if (objectHash.sha1(currentValue) !== objectHash.sha1(this.company)) {
        this.inputChanged = true;
      } else {
        this.inputChanged = false;
      }
    });

////
<button
    [disabled]="!inputChanged || !settingsForm.valid"
    class="btn btn-md text-light"
    >
    Save
</button>
Kate
  • 45
  • 1
  • 8