有时想要自己做出组件,比如像更加花哨的input(可以在使用时加入自定义指令,自定义应用模式切换等等),然后直接调用组件的模板就可以使用之前做好的被封装的控件,但自定义的控件没有办法绑定组件类中的FormControl,这就对获取表单数据造成了很大的麻烦,现在就来通过一个小小的案例来封装一个自定义的表单控件
1、创建案例组件
# 组件名为testComponent
ng g c test/testComponent --skip-tests
编辑组件模板,写一个input
<!-- 使用 ngModel 绑定组件类中的数据 -->
<!-- test-component.component.html文件 -->
<input [(ngModel)]="data" type="text" name="" id="" style="width: 400px;height:30px;background:pink" > 请输入
2、ControlValueAccessor(重点)
//官方接口,用来实现element与FormControl的绑定
interface ControlValueAccessor {
writeValue(obj: any): void
registerOnChange(fn: any): void
registerOnTouched(fn: any): void
setDisabledState(isDisabled: boolean)?: void
}
让组件类实现这个接口
/*
test.component.component.ts类文件
*/
import { Component ,forwardRef, OnInit,} from '@angular/core';
//导入常量NG_VALUE_ACCESSOR
import { ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
@Component({
selector: 'app-test-component',
templateUrl: './test-component.component.html',
styleUrls: ['./test-component.component.css'],
//配置providers 特别重要
providers:[
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => TestComponentComponent),
multi: true
}
]
})
export class TestComponentComponent implements OnInit , ControlValueAccessor {
constructor() { }
//这个是组件将要获取的数据
_data: any;
//get set 方法
public get data(): any {
return this._data;
}
public set data(value: any) {
this._data = value;
this.OnChangeFn(value)
}
public OnChangeFn = (_:any) => {}
public OnTouchFn = (_:any) => {}
//方法重写
writeValue(obj: any): void {
this.data = obj
}
registerOnChange(fn: any): void {
this.OnChangeFn = fn
}
registerOnTouched(fn: any): void {
this.OnTouchFn = fn
}
setDisabledState?(isDisabled: boolean): void {
throw new Error('Method not implemented.');
}
ngOnInit(): void {
}
注意:需要在App.Module.ts导入ReactFormsModule(不然FormGroup绑定会失败)和FormSModule(不然NgModel绑定输入的数据会失败)
App.Component.ts中获取新控件的数据
//app.component.html
<form [formGroup]="test">
<app-test-component formControlName="in"></app-test-component>
<button type="button" (click)="sub()">按钮</button>
</form>
//app.component.ts
import { AfterContentInit, Component, ElementRef} from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterContentInit{
title = 'app-chujunjie';
test: FormGroup = new FormGroup({
in: new FormControl()
})
constructor(private element: ElementRef){}
ngAfterContentInit(): void {
}
sub(){
console.log(this.test.value)
}
}