Angular reactive forms: valueChanges doesn't work as expected

10,339

The valueChanges event is fired after the new value is updated to the FormControl value, and before the change is bubbled up to its parent and ancestors. Therefore, you will have to access the value of the FormControl itself, not a field of the FormGroup value object.

console.log this.inputGroup.get('myControl').value inside the subscribe and it will be having the new value.

Share:
10,339
Master_T
Author by

Master_T

Updated on June 04, 2022

Comments

  • Master_T
    Master_T almost 2 years

    I'm learning to use Reactive Forms in Angular 6, so forgive me if this question is stupid, but here's my issue:

    I want to monitor for changes of a certain value in my reactive form, because when a change occurs I need to run some logic that recalculates stuff based on the new values. So I've tried doing this:

    this.inputGroup = formBuilder.group({
      myControl: 'something'
    });
    
    this.inputGroup.get('myControl').valueChanges.subscribe(newVal => {
      console.log("new value", newVal); //Prints the correct new value
      console.log("actual value", this.inputGroup.value.myControl); //Prints the previous (old) value!
    
      this.someFuncThatExpectsTheValuesToBeUpToDate(); //This will find the OLD value inside this.inputGroup.value.myControl, instead of the new one!
    });
    

    but, as you can see from the comments I put in the code, this doesn't work because valueChanges seems to get called before the value is actually changed in the model! Is this intended behavior? The method signature for valueChanges says:

    A multicasting observable that emits an event every time the value of the control changes, in the UI or programmatically.

    so I would have assumed that it was called AFTER the value was changed in the form, but apparently not... is this correct? And if so, how can I detect when the value has actually changed in the control?

    EDIT: there seems to be some confusion (as always here on SO :D) about WHY I want my function to access the data directly from the Form group, instead of passing the new value to the function itself. This is easily explained: the function gathers data from several form groups and uses this data to do some side-calculations. By accessing the data directly from the form groups, the function is generic and can be invoked from anywhere. If I start to put input parameters there, this would break. Take this example:

    someFuncThatExpectsTheValuesToBeUpToDate(){
      let val1 = inputGroup.value.myControl;
      let val2 = someOtherFormGroup.value.myOtherControl;
      let val3 = yetAnotherFormGroup.value.someOtherControl;
      //do something with the vals
    }
    

    With this function, I can invoke it from anywhere and it will work. But if I need to pass in the values each time, I would need 3 different functions with different signatures to do the same thing, much more messy and complicated.

  • Master_T
    Master_T over 5 years
    Thanks Franklin, this was the correct answer! I'm very new to angular and apparently I did not properly understand the difference between the two. If I understand correctly: I was accessing the values as set in the FormGroup (basically: the values that are used to generate/populate the controls) instead of accessing the current data in the control itself. Am I correct?
  • Franklin Pious
    Franklin Pious over 5 years
    @Master_T Initially the form control value gets updated and then it gets bubbled up to the parent and updates the form and value. And you were trying the access the value of the form (parent) which was not yet updated.
  • Master_T
    Master_T over 5 years
    Thanks for the explanation, much appreciated