typescript 如何在 Angular 2 NgForm 上观察触摸事件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/41337024/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to observe touched event on Angular 2 NgForm?
提问by Chedy2149
It is possible to subscribe a callback to an NgForm
's valueChanges
observable property in order to react to changes in the values of the controls of the form.
因此能够订阅回调到NgForm
的valueChanges
观察特性,以反应形式的控制的值的变化。
I need, in the same fashion, to react to the event of the user touching one of the form controls.
我需要以同样的方式对用户触摸表单控件之一的事件做出反应。
This classseem to define the valueChanges
Observable and the touched
property is defined as a boolean.
这个类似乎定义了valueChanges
Observable 并且touched
属性被定义为一个布尔值。
Is there a way to to react to the "control touched" event?
有没有办法对“控制触摸”事件做出反应?
采纳答案by Valikhan Akhmedov
There is not direct way provided by ng2 to react on touched event. It uses (input) event to fire the valueChangesevent and (blur) event to set touched/untouchedproperty of AbstractControl. So you need to manually subscribe on desired event in the template and handle it in your component class.
ng2 没有提供直接的方式来对触摸事件做出反应。它使用 ( input) 事件来触发valueChanges事件和 ( blur) 事件来设置AbstractControl 的已触摸/未触摸属性。因此,您需要在模板中手动订阅所需的事件并在您的组件类中处理它。
回答by Eggy
You can extend default FormControl
class, and add markAsTouched
method that will call native method, plus your side effect.
您可以扩展默认FormControl
类,并添加markAsTouched
将调用本机方法的方法,以及您的副作用。
import { Injectable } from '@angular/core';
import { FormControl, AsyncValidatorFn, ValidatorFn } from '@angular/forms';
import { Subscription, Subject, Observable } from 'rxjs';
export class ExtendedFormControl extends FormControl {
statusChanges$: Subscription;
touchedChanges: Subject<boolean> = new Subject<boolean>();
constructor(
formState: Object,
validator: ValidatorFn | ValidatorFn[] = null,
asyncValidator: AsyncValidatorFn | AsyncValidatorFn[] = null
) {
super(formState, validator, asyncValidator);
this.statusChanges$ = Observable.merge(
this.valueChanges,
this.touchedChanges.distinctUntilChanged()
).subscribe(() => {
console.log('new value or field was touched');
});
}
markAsTouched({ onlySelf }: { onlySelf?: boolean } = {}): void {
super.markAsTouched({ onlySelf });
this.touchedChanges.next(true);
}
}
回答by Ethan Standel
If your issue was anything like mine, I was trying to mark a field as touched in one component and then respond to that in another component. I had access to the AbstractControl
for that field. The way I got around it was
如果您的问题与我的类似,我会尝试在一个组件中将某个字段标记为已触及,然后在另一个组件中响应该字段。我可以访问AbstractControl
该字段的 。我绕过它的方式是
field.markAsTouched();
(field.valueChanges as EventEmitter<any>).emit(field.value);
And then I just subscribed to valueChanges in my other component. Noteworthy: field.valueChanges
is exported as an Observable, but at runtime it's an EventEmitter
, making this a less than beautiful solution. The other limitation of this would obviously be the fact that you're subscribing to a lot more than just the touched state.
然后我只是在我的另一个组件中订阅了 valueChanges。值得注意的是:field.valueChanges
作为 Observable 导出,但在运行时它是一个EventEmitter
,这使得这不是一个漂亮的解决方案。另一个限制显然是您订阅的不仅仅是触摸状态。
回答by mbdavis
Had this same issue - put together this helper method to extract an observable which you can subscribe to in a form to be notified when touched status changes:
有同样的问题 - 将这个辅助方法放在一起以提取一个可观察的对象,您可以在一个表单中订阅它,以便在触摸状态更改时收到通知:
// Helper types
/**
* Extract arguments of function
*/
export type ArgumentsType<F> = F extends (...args: infer A) => any ? A : never;
/**
* Creates an object like O. Optionally provide minimum set of properties P which the objects must share to conform
*/
type ObjectLike<O extends object, P extends keyof O = keyof O> = Pick<O, P>;
/**
* Extract a touched changed observable from an abstract control
* @param control AbstractControl like object with markAsTouched method
*/
export const extractTouchedChanges = (control: ObjectLike<AbstractControl, 'markAsTouched' | 'markAsUntouched'>): Observable<boolean> => {
const prevMarkAsTouched = control.markAsTouched;
const prevMarkAsUntouched = control.markAsUntouched;
const touchedChanges$ = new Subject<boolean>();
function nextMarkAsTouched(...args: ArgumentsType<AbstractControl['markAsTouched']>) {
touchedChanges$.next(true);
prevMarkAsTouched.bind(control)(...args);
}
function nextMarkAsUntouched(...args: ArgumentsType<AbstractControl['markAsUntouched']>) {
touchedChanges$.next(false);
prevMarkAsUntouched.bind(control)(...args);
}
control.markAsTouched = nextMarkAsTouched;
control.markAsUntouched = nextMarkAsUntouched;
return touchedChanges$;
}
// Usage (in component file)
...
this.touchedChanged$ = extractTouchedChanges(this.form);
...
I then like to do merge(this.touchedChanged$, this.form.valueChanges)
to get an observable of all changes required to update validation.
然后我喜欢做得到merge(this.touchedChanged$, this.form.valueChanges)
更新验证所需的所有更改的可观察性。