1. 组件继承ControlValueAccessor,ControlValueAccessor接口需要实现三个必选方法

writeValue()  用于向元素中写入值,获取表单的元素的元素值
registerOnChange()设置一个当控件接受到改变的事件时所要调用的函数;这也是我们把变化 emit 回表单的机制;
registerOnTouched() 设置一个当控件接受到 touch 事件时所要调用的函数
export class ImageListSelectComponent implements ControlValueAccessor {

  _onChange = (_:any)=>{};

  writeValue(obj: any): void{
this.selectedImg = obj;
}
registerOnChange(fn: (_: any) => void): void {
this._onChange = fn;
} registerOnTouched(fn: any): void {
} }

2.  一个的 token 是 NG_VALUE_ACCESSOR 。这是将控件本身注册到 DI 框架成为一个可以让表单访问其值的控件。

但问题来了,如果在元数据中注册了控件本身,而此时控件仍未创建,这怎么破?这就得用到 forwardRef 了,这个函数允许我们引用一个尚未定义的对象。

另外一个 NG_VALIDATORS 是让控件注册成为一个可以让表单得到其验证状态的控件

providers:[
{
provide:NG_VALUE_ACCESSOR,
useExisting:forwardRef(()=>ImageListSelectComponent),
multi:true
},
{
provide:NG_VALIDATORS,
useExisting:forwardRef(()=>ImageListSelectComponent),
multi:true
}
]

3. 控件的验证器函数(必写方法,否则会报错)

validate(c:FormControl):{[key:string]:any}{
return this.selectedImg ? null :{
imageListNotValid:true
}
}

4. 表单控制器命名formControlName="avatar"

      <app-image-list-select
[cols]="'6'"
[rowHeight]="'1:1'"
[items]='items'
[title]="'选择头像:'"
formControlName="avatar">
</app-image-list-select>

完整代码:

app-image-list-select.component.ts
 import { Component, Input, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR, NG_VALIDATORS, FormControl } from '@angular/forms'; @Component({
selector: 'app-image-list-select',
templateUrl: './image-list-select.component.html',
styles: [],
providers:[
{
provide:NG_VALUE_ACCESSOR,
useExisting:forwardRef(()=>ImageListSelectComponent),
multi:true
},
{
provide:NG_VALIDATORS,
useExisting:forwardRef(()=>ImageListSelectComponent),
multi:true
}
]
})
export class ImageListSelectComponent implements ControlValueAccessor { @Input() cols=6;
@Input() rowHeight='1:1';
@Input() items:string[]=[];
@Input() title = '选择';
selectedImg:string; _onChange = (_:any)=>{}; constructor() { } writeValue(obj: any): void{
console.log(obj);
this.selectedImg = obj;
}
registerOnChange(fn: (_: any) => void): void {
this._onChange = fn;
} registerOnTouched(fn: any): void {
} validate(c:FormControl):{[key:string]:any}{
return this.selectedImg ? null :{
imageListNotValid:true
}
} changeSelected(index){
this.selectedImg = this.items[index];
this._onChange(this.selectedImg);
} }
app-image-list-select.component.html
 <div>
<h3>{{title}}</h3>
<mat-icon [svgIcon]='selectedImg'></mat-icon>
</div>
<mat-grid-list [cols]="cols" [rowHeight]="rowHeight">
<mat-grid-tile *ngFor="let item of items;let i = index">
<mat-icon [svgIcon]='item' (click)="changeSelected(i)"></mat-icon>
</mat-grid-tile>
</mat-grid-list>

register.component.html引用自定义表单控件app-image-list-select

 <div class="login-wrap">
<form [formGroup]="myGroup" (ngSubmit)="onSubmit(myGroup,$event)">
<mat-card class="example-card">
<mat-card-header><mat-card-title>注册</mat-card-title></mat-card-header>
<mat-card-content>
<mat-form-field>
<input matInput placeholder="您的email" formControlName="email">
</mat-form-field>
<mat-form-field>
<input matInput placeholder="您的姓名" formControlName="username">
</mat-form-field>
<mat-form-field>
<input matInput placeholder="您的密码" formControlName="password">
</mat-form-field>
<mat-form-field>
<input matInput placeholder="请重新输入密码" formControlName="repassword">
</mat-form-field>
<div>
<app-image-list-select
[cols]="'6'"
[rowHeight]="'1:1'"
[items]='items'
[title]="'选择头像:'"
formControlName="avatar">
</app-image-list-select>
</div>
</mat-card-content>
<mat-card-actions>
<button mat-raised-button type="submit">注册</button>
</mat-card-actions>
</mat-card>
</form>
</div>

register.component.ts

 import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder } from '@angular/forms'; @Component({
selector: 'app-register',
templateUrl: './register.component.html',
styles: [`
mat-form-field{width:100%;}
form{
width: 500px;
margin: 20px auto;
}
`]
})
export class RegisterComponent implements OnInit { myGroup:FormGroup;
items=[];
constructor(private fb:FormBuilder) { } ngOnInit() {
const nums = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16];
this.items = nums.map(d=> `avatars:svg-${d}`); const img = `avatars:svg-${Math.floor(Math.random()*16).toFixed()}`; this.myGroup = this.fb.group({
email:[],
username:[],
password:[],
repassword:[],
avatar:[img]
});
}
onSubmit({value,valid},ev:Event){
console.log(value);
console.log(valid);
} }

angular 响应式自定义表单控件—注册头像实例的更多相关文章

  1. Angular19 自定义表单控件

    1 需求 当开发者需要一个特定的表单控件时就需要自己开发一个和默认提供的表单控件用法相似的控件来作为表单控件:自定义的表单控件必须考虑模型和视图之间的数据怎么进行交互 2 官方文档 -> 点击前 ...

  2. Angular:自定义表单控件

    分享一个最近写的支持表单验证的时间选择组件. import {AfterViewInit, Component, forwardRef, Input, OnInit, Renderer} from & ...

  3. AngularJS自定义表单控件

    <!doctype html> <html ng-app="myApp"> <head> <script src="G:\\So ...

  4. Angular 从入坑到挖坑 - 表单控件概览

    一.Overview angular 入坑记录的笔记第三篇,介绍 angular 中表单控件的相关概念,了解如何在 angular 中创建一个表单,以及如何针对表单控件进行数据校验. 对应官方文档地址 ...

  5. C#中缓存的使用 ajax请求基于restFul的WebApi(post、get、delete、put) 让 .NET 更方便的导入导出 Excel .net core api +swagger(一个简单的入门demo 使用codefirst+mysql) C# 位运算详解 c# 交错数组 c# 数组协变 C# 添加Excel表单控件(Form Controls) C#串口通信程序

    C#中缓存的使用   缓存的概念及优缺点在这里就不多做介绍,主要介绍一下使用的方法. 1.在ASP.NET中页面缓存的使用方法简单,只需要在aspx页的顶部加上一句声明即可:  <%@ Outp ...

  6. MVC树控件,mvc中应用treeview,实现复选框树的多层级表单控件

    类似于多层级的角色与权限控制功能,用MVC实现MVC树控件,mvc中应用treeview,实现复选框树的多层级表单控件.最近我们的项目中需要用到树型菜单,以前使用WebForm时,树型菜单有微软提供的 ...

  7. Ideal Forms – 帮助你建立响应式 HTML5 表单

    Ideal Forms 是建立和验证响应式 HTML5 表单的终极框架.它刚刚发布 V3 版本,更小,更快,更具可扩展性.它支持实时验证,完全自适应(适应容器,没有 CSS 媒体查询需要),键盘支持, ...

  8. Vue.js学习 Item9 – 表单控件绑定

    基础用法 可以用 v-model 指令在表单控件元素上创建双向数据绑定.根据控件类型它自动选取正确的方法更新元素.尽管有点神奇,v-model 不过是语法糖,在用户输入事件中更新数据,以及特别处理一些 ...

  9. 表单控件 css的三中引入方式css选择器

    1. 表单控件: 单选框 如果两个单选的name值一样,会产生互斥效果 <p> <!--单选框--> 男<input type="radio" nam ...

随机推荐

  1. C++ Primer笔记12_运算符重载_递增递减运算符_成员訪问运算符

    1.递增递减运算符 C++语言并不要求递增递减运算符必须是类的成员.可是由于他们改变的正好是所操作对象的状态.所以建议设定为成员函数. 对于递增与递减运算符来说,有前置与后置两个版本号,因此.我们应该 ...

  2. 华为OJ平台试题 ——数组:整形数组合并

    代码: /* * 将两个整型数组依照升序合并,而且过滤掉反复数组元素 */ #include <stdio.h> #define N 256 #define M 512 /* * 合并数组 ...

  3. js中由undefined说起

    typeof()函数 返回的是字符串.有六种可能:"number"."string"."boolean"."object" ...

  4. 56.lambda表达式与绑定以及伪函数和绑定

    #include <iostream> #include <functional> using namespace std; using namespace std::plac ...

  5. BZOJ 1231 状压DP

    思路: f[i][j] i表示集合的组成 j表示选最后一个数 f[i][j]表示能选的方案数 f[i|(1<< k)][k]+=f[i][j]; k不属于i j属于i且符合题意 最后Σf[ ...

  6. javafx DragDropped file

    public class EffectTest extends Application { @Override public void start(Stage primaryStage) { Grou ...

  7. Kinect开发 —— 基础知识

    转自:http://www.cnblogs.com/yangecnu/archive/2012/04/02/KinectSDK_Application_Fundamentals_Part2.html ...

  8. 竖向 两级手风琴 TAB 栏

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  9. angularjs之ui-bootstrap的Datepicker Popup不使用JS实现双日期选择控件

    最开始使用ui-bootstrap的Datepicker Popup日期选择插件实现双日期选择时间范围时,在网上搜了一些通过JS去实现的方法,不过后来发现可以不必通过JS去处理,只需要使用其自身的属性 ...

  10. 一个简易版的Angular js 三层 示例

    var myApp = angular.module('produceline', []); myApp.factory('ajax', ["$http", "$q&qu ...