angular4 自定义表单组件

自定义表单组件分为单值组件和多值组件.

单值组件:input/select/radio/textarea

多值组件:checkbox/tree组件

条件:

1.必须实现ControlValueAccessor接口

不同输入控件的数据更新方式不一样。

比如input是设置value值,而checkbox是设置checked属性。

因此不同类型的输入控件都有一个ControlValueAccessor来更新视图

export interface  ControlValueAccessor{
     writeVlaue(obj:any) :void;             //model->view
     registerOnchange(fn:any) :void;    //view->model
     registerOnTouched(fn:any):void;
     setDisabledState?( isDisabled:boolean):void
}
//实现

writeValue(value:any){
   if(value!=this.innerVal){
       this.innerVal=value;
   }
}

2.必须注册成为表单组件(使用providers属性)

注释:

1.provide:将组件注册到DI框架,让其成为一个可被表单访问的组件

2.useExisting:让组件暴露对应的validatate方法实现表单验证

3.multi:为true时表示这个token对应多个依赖项,可在多个表单里使用,互不影响

@Component({
  selector:'nw-input',
  templateUrl:'./nw-input.component.html',
  styleUrls:'./nw-input.component.scss',
  providers:[
      provide:NG_VALUE_ACCESSOR,                    
      useExisting:forwardRef(()=>nwInputComponent), 
      multi:true                                
  ]
})

具体实现:

1.如果是单值表单组件,使用FormControl

//nw-select.component.ts

@Component({
  selector:'nw-select',
  templateUrl:'./nw-select.component.html',
  styleUrls:'./nw-select.component.scss',
  providers:[
      provide:NG_VALUE_ACCESSOR,                                                      
      useExisting:forwardRef(()=>NwSelectComponent),
       multi:true
  ]
})

export class NwSelectComponent implements ControlValueAccessor{
    selectFormControl:FormControl=new FormControl();

    getControl(vfn:ValidatorFn[]):FormControl{
      if(!this.selectFormControl){
           this.selectFormControl=new FormControl('',vfn)
      }
     return this.selectFormControl
   }
}
//xx.component.ts

export class xxComponent implements OnInit {
  thatForm:formGroup;
  @ViewChild('xxComp')
  xxComp:NwSelectComponent;

   ngOnInit(){       
    xx:this.xxComp.getControl([Validator.required,Validators.minLength(5)])   //验证条件还是数组
  }
}
    

2.如果是多值表单组件,使用FormArray

//nw-checkbox.component.ts

@Component({
  selector:'nw-checkbox',
  templateUrl:'./nw-checkbox.component.html',
  styleUrls:'./nw-checkbox.component.scss',
  providers:[
      provide:NG_VALUE_ACCESSOR,                                                      
      useExisting:forwardRef(()=>NwCheckboxGroupComponent),
       multi:true
  ]
})

export class NwCheckboxGroupComponent implements ControlValueAccessor{
    checkboxFormArray:FormArray=new FormArray([]);

    getControls(vfn:ValidatorFn):FormArray{
     if(!this.checkboxkFormArray){
        this.checkboxFormArray=new FormArray([],vfn);
    }
   }
    cleanControls(){
      while(this.checkboxFormArray.controls.length!==0){
           this.checkboxFormArray.removeAt(0) 
     }
   pushControl(id:any){
      this.checkboxFormArray.push(new FormControl(id))
   }
 }
}
//xx.component.ts

export class xxComponent implements OnInit {
   thatForm:FormGroup;
   @ViewChild(xxComp)
   xxComp:NwCheckboxGroupComponent;

   ngOnInit(){
     this.thatFom=this.formBuilder.group({
        xx:this.xxComp.getControls(Valitators.required)  //验证条件不再允许数组了
    })    
  }
}