How to watch all FormControls ValueChanges except specific control?
Asked Answered
A

6

9

I have a form that do a computation whenever a control input value changes.

Here is my form_group looks like:

form_group = this.fb.group({
    control1: [],
    control2: [],
    control3: [],
    ...
    control10: [],
});

I can detect all controls value changes via form_group.valueChanges observable, and do a computation. However i want to exclude some of the control that doesn't need to do such an action.

But there is anyway how to not detect the changes on a particular control?

It is very burdensome to write a form_group.get('controlN').valueChanges and do a computation there. I have 5 or more controls in my form.

Areca answered 26/4, 2018 at 6:54 Comment(0)
L
15

You can merge individual valueChanges Observables into one like so :

Observable.merge(
    [ control1.valueChanges,
      control2.valueChanges ]
  ).subscribe(() => {
    // do your computation
  });
Likelihood answered 26/4, 2018 at 7:2 Comment(4)
It 's the same just think about it how do get control1 or another control refrence , and merage is the same like all the observable have one observer ,I think the problem not fixed yet ,I will be habe if I got from valueChange like this control has new value imagin like I have 50 item of formArray, good luckDunseath
now if you want to watch 9 of your controls you need 9 refrence so I still hope if there is a better wayDunseath
@MuhammadAlbarmawi It works efficiently and with less code, rather than declaring subscription per control. And Yes of course it is the same with your suggestion the difference is simplicity.Thatcher
Maybe you could put all the form controls you want to watch into a new group or FormArray so you can more easily manage them?Acrimony
L
4

Is there a reason why you couldn’t create a FormArray instead of multiple form controls? For example

form_group = this.fb.group({
    'controls': this.fb.array([...])
});

Then you can define a property in your component

get controls(): FormArray {
    return <FormArray>this.form_group.get('control');
}

And then from this you can iterate the form array and subscribe to valueChanges

this.controls.controls.forEach(control => {
    control.valueChanges.subscribe(...)
});

You can then apply some logic in the for each to exclude the controls you do not want to subscribe to

Loge answered 26/4, 2018 at 8:22 Comment(0)
C
3

You can do it following way :

combineLatest(this.getControlsForWatch()).subscribe(() => applyFilter());

getControlsForWatch(): Array<Observable<any>> {
        return (
            Object.entries(this.from.controls)
                .filter(([key]) => key !== 'exceptedControl')
                .map(([key]) => this.from.controls[key].valueChanges)
        );
    }

also you can adjust filter for your current task

Covenantee answered 18/1, 2021 at 12:56 Comment(0)
H
1

Like so, I wanted to observe changes from multiple controls, I was able to do this like this.

import { merge } from 'rxjs';
...
const merged = merge(this.control1.valueChanges,this.control2.valueChanges, this.control3.valueChanges, this.control4.valueChanges);

merged.subscribe(x => console.log(x));

Reference:- https://rxjs-dev.firebaseapp.com/api/index/function/merge

Hynda answered 14/10, 2020 at 11:48 Comment(0)
D
0

You just need to access to the control and subscribe to value changes property like this

    this.form_group.get('control1').valueChanges.subscribe(value => {
        console.log(value)
    })
Dunseath answered 26/4, 2018 at 6:59 Comment(1)
That is bad though, i want to avoid that since i have a lot of form control in my form and im seeking a much simpler approachThatcher
C
0
this.myForm = this.fb.group({
  control1: [''],
  control2: [''],
  excludedControl: [''], // The control you want to exclude
});

// Subscribe to value changes for all FormControls except excludedControl
Object.keys(this.myForm.controls)
  .filter(key => key !== 'excludedControl') // Exclude the specific control
  .forEach(controlName => {
    this.myForm.get(controlName).valueChanges
      .pipe(
        debounceTime(300), // Add any debounce time if needed
        distinctUntilChanged()
      )
      .subscribe(newValue => {
        // Handle the value change here
        console.log(`Value changed for ${controlName}: ${newValue}`);
      });
  });

} }

Chambray answered 14/9, 2023 at 13:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.