简体   繁体   English

Angular 反应性 Forms valueChanges - 仅 UI 更改

[英]Angular Reactive Forms valueChanges - UI changes only

The Angular FormControl has a valueChanges Observable that states: Angular FormControl有一个valueChanges Observable 声明:

Emits an event every time the value of the control changes, in the UI or programmatically.每当控件的值在 UI 中或以编程方式更改时发出一个事件。

Is there a way to set the FormControl to ignore programmatic value changes?有没有办法将 FormControl 设置为忽略编程值更改? (Basically the equivalent of OneWayToSource binding in .NET) (基本上等同于 .NET 中的OneWayToSource绑定)

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.具体来说,我面临的问题是我的valueChanges订阅,我正在更新一堆绑定到一堆其他控件的值,然后导致valueChanges也为所有这些控件触发,这是有问题的,因为它们的操作在他们的valueChanges处理程序中执行与用户实际触摸的控件冲突。

You can skip emitting the valueChange event by passing the option { emitEvent: false } to the setValue call.您可以通过将选项{ emitEvent: false }传递给setValue调用来跳过发出 valueChange 事件。

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.如果 onlySelf 为 true,则此更改只会影响此 FormControl 的验证,而不影响其父组件。 This defaults to false.这默认为 false。

If emitEvent is true, this change will cause a valueChanges event on the FormControl to be emitted.如果emitEvent 为true,则此更改将导致在FormControl 上发出一个valueChanges 事件。 This defaults to true (as it falls through to updateValueAndValidity).这默认为 true(因为它属于 updateValueAndValidity)。

If emitModelToViewChange is true, the view will be notified about the new value via an onChange event.如果emitModelToViewChange 为true,将通过onChange 事件通知视图新值。 This is the default behavior if emitModelToViewChange is not specified.如果未指定emitModelToViewChange,这是默认行为。

If emitViewToModelChange is true, an ngModelChange event will be fired to update the model.如果emitViewToModelChange 为true,将触发ngModelChange 事件以更新模型。 This is the default behavior if emitViewToModelChange is not specified.如果未指定emitViewToModelChange,这是默认行为。

Docs文档

The reactive form group have property yourFormName.pristine反应式表单组具有属性 yourFormName.pristine

You can use !yourFormName.pristine to detect only UI changes您可以使用 !yourFormName.pristine 仅检测 UI 更改

 * 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;

You can pass { emitEvent: false } as options for the below reactive form methods to prevent them from triggering the valueChanges event您可以传递{ emitEvent: false }作为以下反应式表单方法的选项,以防止它们触发 valueChanges 事件

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 yes disable 触发 valueChanges 事件

PS: above this.form is a reactive form PS:上面的this.form是一个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 https://netbasal.com/angular-reactive-forms-tips-and-tricks-bb0c85400b58

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.它并不能解决所有问题,但可以解决某些情况。

I could do it by putting this listener on the html file:我可以通过将此侦听器放在 html 文件中来做到这一点:

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

And on the .ts file:在 .ts 文件上:

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.我通过反复试验得出了这个解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM