如何仅在输入模糊时触发反应表单 valueChanges 订阅并在 Angular 2 中输入键

Posted

技术标签:

【中文标题】如何仅在输入模糊时触发反应表单 valueChanges 订阅并在 Angular 2 中输入键【英文标题】:How to trigger reactive form valueChanges subscription only on input blur and enter key in Angular 2 【发布时间】:2018-03-21 16:47:39 【问题描述】:

我正在开发一个表单,该表单应该仅在输入模糊或按下输入键时更新某些 ui 部分。我是反应形式的忠实粉丝,我正在尝试找出正确的方法。到目前为止,我还没有找到太多关于反应形式的答案。他们中的大多数都专注于模板驱动的表单。到目前为止,我得到了类似的东西:

表单组件动态表单值在运行时更改(没有可预测的文件名)

import  Component, Input, Output, EventEmitter, 
    ChangeDetectionStrategy  from '@angular/core'
import  FormBuilder, FormGroup, FormControl  from '@angular/forms'
import  Observable  from "rxjs/Observable"
import  DEBUG  from '../../../../config/config'
import * as Debug from 'debug'

// Interfaces
import  Foo  from '../../interfaces/foo'

// Services
import  FooService  from '../../services/foo.service'

// Debug
const debugOff = (...any) =>  , debug = Debug('app:FooCmp')

@Component(
    selector: 'foo-data-cmp',
    templateUrl: './foo.data.cmp.html',
    changeDetection: ChangeDetectionStrategy.OnPush,
    styleUrls: ['./foo.data.cmp.css']
)
export class FooDataCmp 

    private _foo: Foo[] = null
    @Input('foo')
    set foo(foo: Foo[]) 
        this._foo = foo
        DEBUG.input && debug('Input foo:', this._foo)
    
    get foo(): Foo[] 
        return this._foo
    

    // Forms
    public fooForm: FormGroup
    public fooForm$: Observable<any>
    private updatedFoo: any[] // Updated form values

    // Subscriptions
    private subscriptions: any[] = []

    constructor(
        private formBuilder: FormBuilder,
        private fooService: FooService,
    ) 
        DEBUG.constr && debug('Construct FooDataCmp')
    

    ngOnInit() 
        DEBUG.init && debug('Initialise FooDataCmp')

        // Form
        this.initFooForm()
        this.subcribeToFormChanges()
    

    ngOnDestroy() 
        DEBUG.destroy && debug('Destroy FooDataCmp')
        this.subscriptions.forEach(sub => sub.unsubscribe())
    

    private initFooForm() 
        DEBUG.cmp && debug('Initialise foo form')

        // Build the form
        this.fooForm = this.formBuilder.group(this._foo)

        // Prevent undefined error at first keystroke
        this.updatedFoo = this._foo
    

    private subcribeToFormChanges() 
        this.fooForm$ = this.fooForm.valueChanges
        let sub = this.fooForm$.subscribe(fooForm => 
            DEBUG.cmp && debug('Form changes fooForm', fooForm)
            this.updatedFoo = fooForm
        )
        this.subscriptions.push(sub)
    

    /**
     * <!> Important step in the data update process
     * Update state store. 
     * Other services / components are subscribed to the state store itself
     */
    public refreshAllFooRelatedData () 
        DEBUG.cmp && debug('Refresh all foo related data')
        DEBUG.cmp && debugOff('Updated foo', this.updatedFoo)
        this.fooService.refreshAllFooRelatedData(this.updatedFoo)
    

    public refreshAllFooRelatedDataOnEnter (e: KeyboardEvent) 
        if (e.keyCode !== 13) return
        DEBUG.cmp && debug('Refresh all foo related data (on enter)')
        DEBUG.cmp && debugOff('Updated foo', this.updatedFoo)
        this.fooService.refreshAllFooRelatedData(this.updatedFoo)
    

    public debugTemplate() 
        DEBUG.render && debug('Render FooDataCmp')
    


表单模板

<form [formGroup]="fooForm">
    <table class="list expiries">
            <td *ngFor="let value of foo; let i = index">
                <input type="text" [formControlName]="foo[i]" 
                    (blur)="refreshAllFooRelatedData()" 
                    (keydown)="refreshAllFooRelatedDataOnEnter($event)">
            </td>
    </table>
</form>

 debugTemplate() 

这是一个不错的解决方案还是我错过了一些技巧?我的问题是这是否是正确的方法。我一直期待找到一些表单 API 选项来处理此任务。我的方法是在表单之上构建,但如果有任何可用于此任务的东西,我宁愿使用完整的表单 api

【问题讨论】:

这是一个不错的解决方案吗...? 您是在问我们是否喜欢您所做的事情,或者这对您不起作用?如果是这样,问题究竟出在哪里?反应形式非常好document。 Forms Controls 也是。 我的问题是这是否是正确的方法。我一直期待找到一些表单 API 选项来处理此任务。我的方法是在表单之上构建,但如果有任何可用于此任务的东西,我宁愿使用完整的表单 api。 【参考方案1】:

如果将来有人发现这个,实际上有一些内置在响应式表单中,updateOn 选项:

new FormControl('', updateOn: 'blur');

这将导致 valueChanges 和验证等仅在模糊时触发

【讨论】:

@Jojo OP 已经得到了接受的答案。从反应形式的角度来看,将 Observables 与已接受的答案相结合并使用更新模糊将是最佳解决方案。此外,接受答案中的可观察流甚至没有达到目标。 实际上这只对模糊运行验证检查,而每次值更改(击键)仍会触发 valuechanges 在我看来,这是一个更优雅的解决方案,可以完成原始问题所需的一切。 这是一个更好更简洁的解决方案,解决了我基于模糊只更新单个字段的目的【参考方案2】:

您可以将 blur 和 enter 事件组合到一个主题中,并将其与 valuechange Observable 合并,以便它仅在 blur 或 enter 时触发 value。我还没有完全测试代码只是一个想法,我之前遇到过类似的情况

// component
this.updateField=new Subject()

this.form.get('yourfield').valueChanges.withLatestFrom(updateField).map(res=>res[0]).subscribe()

//html
<input (blur)="updateField($event)" (keydown.enter)="updateField($event)"/>

【讨论】:

这是个好主意!我知道有些事情可以做得更好。谢谢!该死的,实际上我现在意识到我是如此盲目......我会在修改时更新。可观察的 Ftw! :D【参考方案3】:
// component
public ctrl: FormControl = new FormControl(0, updateOn: 'blur');

//html
<input [formControl]="ctrl" (keydown.enter)="$event.target.blur()"/>```

【讨论】:

以上是关于如何仅在输入模糊时触发反应表单 valueChanges 订阅并在 Angular 2 中输入键的主要内容,如果未能解决你的问题,请参考以下文章

角度反应形式 - 验证变化和模糊两者

jQuery 模糊事件在 Chrome 中触发了两次

jQuery - 更改 iframe src 时仅在第二次单击时触发

欧芹为空字段触发错误

即使在表单活动验证状态下,如何仅在提交时验证角度表单

mapGetters 的反应性问题仅在第一次加载时