20

The Angular FormControl has a valueChanges Observable that states:

Emits an event every time the value of the control changes, in the UI or programmatically.

Is there a way to set the FormControl to ignore programmatic value changes? (Basically the equivalent of OneWayToSource binding in .NET)

Specifically, the issue I'm facing is that my valueChanges subscription, I'm updating a bunch the values bound to a bunch of other controls, which then causes valueChanges to fire for all of them as well, which is problematic as the actions they perform in their valueChanges handlers conflicts with the control the user actually touched.

5 Answers 5

18

You can skip emitting the valueChange event by passing the option { emitEvent: false } to the setValue call.

setValue(value: any, options: {
    onlySelf?: boolean;
    emitEvent?: boolean;
    emitModelToViewChange?: boolean;
    emitViewToModelChange?: boolean;
} = {}): void

Also you might want to take a look at other options.

If onlySelf is true, this change will only affect the validation of this FormControl and not its parent component. This defaults to false.

If emitEvent is true, this change will cause a valueChanges event on the FormControl to be emitted. This defaults to true (as it falls through to updateValueAndValidity).

If emitModelToViewChange is true, the view will be notified about the new value via an onChange event. This is the default behavior if emitModelToViewChange is not specified.

If emitViewToModelChange is true, an ngModelChange event will be fired to update the model. This is the default behavior if emitViewToModelChange is not specified.

Docs

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, this is helpful. However, in my particular case, I'm update the values bound to the other form controls, not the form controls themselves. So I don't have the setValue method available, and it seems Angular's change detection is picking up on the changes and firing the events.
How to resolve the issue with two interdependent controls having valueChange? I have a parasite 3rd event triggering (for initiator)
2

You can pass { emitEvent: false } as options for the below reactive form methods to prevent them from triggering the valueChanges event

this.form.patchValue(value, { emitEvent: false })
this.form.setValue(value, { emitEvent: false })
this.form.controls.email.updateValueAndValidity({ emitEvent: false })
this.form.disable({ emitEvent: false })

yes disable triggers the valueChanges event

PS: above this.form is a reactive form

Read this excellent post, it'll answer all your questions and even give some great insights on reactive forms:

https://netbasal.com/angular-reactive-forms-tips-and-tricks-bb0c85400b58

Comments

1

That may be helpful:

    yourControl.valueChanges.pipe(
        filter(() => yourControl.touched)
    ).subscribe(() => {
       ....
    })

It will fire only if control was previously touched. It doesnt fix all the issues, but may solve some cases.

1 Comment

While this is a smell, this actually wasn't bad as a "workaround" until we have the time to properly. When I say "smell" what I mean, is that the real method we had for determining whether or not value changes should propagate is not working. Why isn't it working... who knows!
0

The reactive form group have property yourFormName.pristine

You can use !yourFormName.pristine to detect only UI changes

 * A control is `pristine` if the user has not yet changed
 * the value in the UI.
 *
 * @returns True if the user has not yet changed the value in the UI; compare `dirty`.
 * Programmatic changes to a control's value do not mark it dirty.
 */
readonly pristine: boolean;

1 Comment

pristine/dirty not reset after consequent patchValue's, are they?
-1

I could do it by putting this listener on the html file:

<ss-multiselect-dropdown ... (ngModelChange)="functionToTrigger($event)"></ss-multiselect-dropdown>

And on the .ts file:

functionToTrigger($event) {
    if (event === undefined) {
        // Put here are the instructions for UI changes
    } else {
        // Put here are the instructions for programmatic changes
}

I really don't know why it works this way. I came to this solution by trial and error.

1 Comment

The $event passed in the ngModelChange is just the value of the model. It has nothing to do with how the model was changed in the UI or not.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.