将formControlName用于自动形式的自定义输入组件

时间:2017-09-10 14:19:48

标签: angular angular-reactive-forms angular-forms angular-validation

有一个自定义输入组件,它以反应形式用于验证:

@Component({
    moduleId: module.id.toString(),
    selector: 'custom-select',
    templateUrl: 'custom-select.component.html',
    styleUrls: ['custom-select.component.css']
})
export class CustomSelectComponent {
    @Input() public items: SelectModel[];
    public model: SelectModel;
    constructor(private customSelectService: CustomSelectService) {
        this.customSelectService.Selected.subscribe((data: SelectModel) => {
            this.model = data;
        });
    }
    public newSelect(select: SelectModel): void {
        this.customSelectService.updateSelected(select);
    }
}

工作正常,我在反应式表单中使用custom-select并希望如下所示验证它:

<custom-select id="country" [items]="selectItems" formControlName="country"></custom-select>
<div *ngIf=" myFrom.controls['country'].invalid && (myFrom.controls['country'].dirty 
             || myFrom.controls['country'].touched) " class="ha-control-alert">
    <div *ngIf="myFrom.controls['country'].hasError('required')">Country is required</div>
</div>

这是我在组件

中声明表单的方式
this.myFrom = this.formBuilder.group({
    country: [null, Validators.required],
})

但是当我为验证添加formControlName时,会收到错误消息,其中没有值名称访问者,其名称为:&#39; country&#39; 。我该怎么办呢?

2 个答案:

答案 0 :(得分:2)

步骤

  1. 在装饰器中添加 NG_VALUE_ACCESSOR 的提供者

  2. 在类中实现 ControlValueAccessor

  3. 像这样创建 onChange 函数 onChange = (value: boolean) => {};

  4. 添加 ControlValueAccessor 接口的 registerOnChange、writeValue 和 registerOnTouched 方法

  5. 在改变select值的方法中,调用onChange函数,将select的值作为参数传递。

    var arr1 = ['banana', 'apple', 'orange', 'tomato', 'grape']
    var arr2 = ['banana', 'grape']
    
    arr2 = arr1.slice(0,2).filter( ( x ) => arr2.indexOf( x ) !== -1 )
    
    console.log(arr2 = arr2.length > 0 ? arr2 : false)

不要忘记在选择器中添加 formControlName。

答案 1 :(得分:0)

将此添加到孩子的提供者:

viewProviders: [{
  provide: ControlContainer, 
  useExisting: FormGroupDirective 
}]

它首先失败的原因是它没有在 FormGroup 的父作用域中查找,所以这只是将它传递给子级。

然后你需要欺骗它认为你的控件有一个 valueAccessor——它不需要,因为你刚刚创建了一种“垫片”。

export const NOOP_VALUE_ACCESSOR: ControlValueAccessor = 
{
    writeValue(): void {},
    registerOnChange(): void {},
    registerOnTouched(): void {}
};

然后在您孩子的构造函数中:

constructor(@Self() @Optional() public ngControl: NgControl) 
{
    if (this.ngControl)
    {
        this.ngControl.valueAccessor = NOOP_VALUE_ACCESSOR;
    }
}

然后你就可以在孩子内部正常使用 formControlName 了。

如果您需要从父组件传递 formControlName(如果它是一个可重用的控件,您可能会这样做)只需创建一个字符串 @Input 属性并在子组件中执行此操作:

    <input matInput [placeholder]="desc" 
           [formControlName]="formControlName">