13

I can't find out how to retrieve all fields modified by the user using angular2 forms. I did some research here and on angular2 official forms docs and I couldn't find such information.

This is how I do it using jQuery:

    this.isFormDirty = function (form) {
        var changeNames = [];

        $(form).find(":input:not(:button):not([type=hidden])").each(function () {
            if ((this.type == "text" || this.type == "textarea" || this.type == "number" || this.type == "hidden" || this.type == "file") && this.defaultValue != this.value) {
                changeNames.push(this.name);
            } else {
                if ((this.type == "radio" || this.type == "checkbox") && this.defaultChecked != this.checked) {
                    changeNames.push(this.name);
                } else {
                    if ((this.type == "select-one" || this.type == "select-multiple")) {
                        for (var x = 0; x < this.length; x++) {
                            if (this.options[x].selected != this.options[x].defaultSelected) {
                                changeNames.push(this.name);
                            }
                        }
                    }
                }
            }
        });

        return changeNames;
    };

Is there a way to do that using angular2 forms? I thought I'd have some sort of changedValues property, but I can't find it.

EDIT

This is how my form is created: (permissionForm is of type FormGroup)

this.permissionForm = this.fb.group({
      FullUrl: ['', Validators.required],
      Area: ['', Validators.required],
      Controller: ['', Validators.required],
      Action: ['', Validators.required],
      Name: ['', Validators.required],
      Description: ['', Validators.required],
      ParentPermissionId: ['', Validators.required],
      ShowInMenu: ['', Validators.required],
      Order: ['', Validators.required],
      Icon: ['', Validators.required]
    });
eestein
  • 4,914
  • 8
  • 54
  • 93

4 Answers4

11

Well, this is how I'm going by at the moment:

private getChangedProperties(): string[] {
  let changedProperties = [];

  Object.keys(this.permissionForm.controls).forEach((name) => {
    const currentControl = this.permissionForm.controls[name];

    if (currentControl.dirty) {
      changedProperties.push(name);
    }
  });

  return changedProperties;
}

I was really hoping angular2 forms would have a simple property with that information. Please post another answer if there's a better way of doing this.

eestein
  • 4,914
  • 8
  • 54
  • 93
9
const keyValue = Object.entries(this.form.controls).filter(value => value[1].dirty);

For get control names array:

keyValue.map(value => value[0]);

For get controls array:

keyValue.map(value => value[1]);

For get controls object:

keyValue.reduce((a, v) => Object.assign(a, { [v[0]]: v[1] }), {});

Сompact function:

type GetDirtyControlsTypes = 'object' | 'array' | 'names';

export function getDirtyControls(form: FormGroup, type: GetDirtyControlsTypes = 'object') {
  // keyValue
  const kv = Object.entries(form.controls).filter(val => val[1].dirty);
  return {
    object: () => kv.reduce((accum, val) => Object.assign(accum, { [val[0]]: val[1] }), {}),
    array: () => kv.map(val => val[1]),
    names: () => kv.map(val => val[0]),
  }[type]();
}
Nikolay
  • 211
  • 2
  • 11
4

You can achieve this using Observables:

Observable.from(Object.values(this.permissionForm.controls))
  .filter(control => control.dirty)
  .subscribe(control => {
    // Here doing stuff with all your dirty control
  })

You can also subscribe to control changes :

this.permissionForm
  .valueChanges
  .subscribe(control => {
    // Here doing stuff with your control
    // like checking if control is dirty and append it to an array
  });
soywod
  • 4,377
  • 3
  • 26
  • 47
  • Is there some way of determining the names of the dirty FormControls without iterating the entire FormGroup like this: '''Object.keys(formGroup.controls).forEach((key: string) => { ... }''' – RandyDaddis Mar 18 '19 at 18:35
3

You can use this helper method to obtain the dirty state of a form:

function getDirtyState(form: FormGroup): Object {
  return Object.keys(form.controls).reduce<Object>((dirtyState, controlKey) => {
    const control = form.controls[controlKey];

    if (!control.dirty) {
      return dirtyState;
    }

    if (control instanceof FormGroup) {
      return {
        ...dirtyState,
        [controlKey]: getDirtyState(control),
      };
    }

    return {
      ...dirtyState,
      [controlKey]: control.value,
    };
  }, {});
}

It also handles nested formGroup controls, and returns an object of values with the same structure as the entire form.

Merott
  • 7,189
  • 6
  • 40
  • 52