Search code examples
angulartypescript

Angular: on form change event


I have form group in my angular app. Since I would like to aviod writing onChange for each form element, my idea was to subscribe to entire form changes, and then on event check changed element

So this is relevant part of the code:

constructor(){
this.orderForm = this.formBuilder.group({
  ...
});

this.event$ = this.orderForm.valueChanges.subscribe((x:any) => {
  console.log('form value changed')
  console.log(x)
});

Problem is, this x is just entire form so I have no idea what element is changed

Is there any smart way to find out what form element changed?


Solution

  • "stolen" the idea of AT82, we can has a recursive function that return an observable. Well, instead of use "tap", we can use map to return an object with two properties: name (the control has changed) and value.

    So some like

      mergeForm(form: FormGroup | FormArray, suffix: string) {
        if (form instanceof FormArray) {
          console.log(suffix)
          const formArray = form as FormArray;
          const arr = [];
          for (let i = 0; i < formArray.controls.length; i++) {
            const control = formArray.at(i);
            arr.push(
              control instanceof FormGroup
                ? this.mergeForm(control, suffix + i+'.')
                : control.valueChanges.pipe(
                    map((value) => ({ name: suffix + i, value: value }))
                  )
            );
          }
          return merge(...arr);
        }
        return merge(
          ...Object.keys(form.controls).map((controlName: string) => {
            const control = form.get(controlName);
            return control instanceof FormGroup || control instanceof FormArray
              ? this.mergeForm(control, suffix + controlName + '.')
              
              : control.valueChanges.pipe(
                  map((value) => ({ name: suffix + controlName, value: value }))
                );
          })
        );
      }
    

    We can call in the way

    this.mergeForm(this.orderForm, '')
      .pipe(takeWhile((_) => this.alive))
      .subscribe((res) => {
        console.log(res);
      });
    

    You can see the stackblitz

    NOTE: If you don't use FormArray you can simply the recursive function