访问自定义表单控件的有效值

Posted

技术标签:

【中文标题】访问自定义表单控件的有效值【英文标题】:Access valid value of custom form control 【发布时间】:2018-01-14 02:55:59 【问题描述】:

我创建了代表密码表单控件的自定义组件(以下代码已简化)。

密码组件 (html)

<form [formGroup]="passwordForm">
  ...
  <input formControlName="password" type="password">
</form>

密码组件 (ts)

...
@Component(
  selector: 'password',
  templateUrl: './password.component.html',
  styleUrls: ['./password.component.css'],
  providers: [
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => PasswordComponent),
    multi: true
  ]
)
export class PasswordComponent implements ControlValueAccessor 

  passwordForm: FormGroup;
  onChange = (password: string) =>  ;  
  onTouched = () =>  ;                  

  constructor() 
    this.passwordForm = new FormGroup(
      ...
      password: new FormControl('')
    );

    this.passwordForm.valueChanges.subscribe(data => this.onChange(this.value));
  

  get value(): string 
    return this.passwordForm.get('password').value;
  

  writeValue(password: string): void 
    this.passwordForm.get('password').setValue(password);
    this.onChange(this.value);
  

  registerOnChange(fn: any): void  this.onChange = fn;  

  registerOnTouched(fn: any): void  this.onTouched = fn; 

  setDisabledState?(isDisabled: boolean): void  

我在其他组件中使用它而不是标准输入元素:

<form [formGroup]="userForm">
  ...
  <password formControlName="password"></password>
</form>

验证器来自外部形式(它们没有在 PasswordComponent 中定义)

this.userForm = fb.group(
  ...
  password: ['', [Validators.minLength(10), Validators.maxLength(100)]] 
);

我的问题是:如何从 PasswordComponent 中获取 &lt;password&gt; 元素的有效性?我想根据有效性对其进行风格化。换句话说,我怎样才能从代表该控件的 PasswordComponent 中获取 userForm 的“密码”控件的有效性。

【问题讨论】:

【参考方案1】:

因为我们无法直接从 DI 系统获取 NgControl 实例,因为我们会遇到循环依赖错误。下图显示了如果我们在自定义值访问器中注入 NgControl 会发生这种情况的原因:

现在应该清楚我们有NgControl -&gt; FormControlName -&gt; ValueAccessor -&gt; CustomValueAccessor -&gt; NgControl循环依赖

要解决这个问题,您可以利用Injector 来实现:

component.ts

import  NgControl  from '@angular/forms';
export class PasswordComponent implements ControlValueAccessor 
  ...
  ngControl: NgControl;

  constructor(private inj: Injector) 
    ...
  

  ngOnInit() 
    this.ngControl = this.inj.get(NgControl)
  

template.html

 ngControl.control.valid 

Plunker Example

【讨论】:

这就像一个魅力,但它看起来很丑,还是只有我这么认为?它看起来像一个非常基本的用例 您能否更详细地解释一下这里发生了什么?为什么会出现循环 dep 错误?为什么喷油器没有? 感谢您直观地了解事物的设置方式。 Angular 文档将受益于这些事情! 当我this.inj.get(NgControl) 我得到一个FormControlName 这是无用的,因为formControlname.parent.control 是一个formgroup 并且“我不知道”哪个控件是“自定义控件”。 我的生命周期错误。在ngAfterViewInit 我可以阅读name 然后得到正确的控制。 _parent 是私人的。【参考方案2】:

解决此问题的另一种方法是从提供程序中删除 NG_VALUE_ACCESSOR 并注入 NgControl。使用 NgControl 实例,组件将被注册为 ValueAccessor。

constructor(
..., 
@Optional() @Self() public ngControl: NgControl,
...,
) 
// Setting the value accessor directly (instead of using
// the providers) to avoid running into a circular import.
if (this.ngControl != null)  this.ngControl.valueAccessor = this; 

【讨论】:

以上是关于访问自定义表单控件的有效值的主要内容,如果未能解决你的问题,请参考以下文章

Angular2- RC6 自定义表单控件不起作用

基于UEditor上开发的表单设计器--自定义文本控件

弹出窗口 WPF 表单自定义控件内容

如何使用 Angular 重置自定义表单控件

Angular 2 - 自定义表单控件 - 禁用

来自 FormGroup 的禁用控件(表单自定义表单控件的一部分)被父级中的 .getRawValue() 排除