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/C++】链表的理解与使用

    转载自:http://blog.csdn.NET/xubin341719/article/details/7091583/ 最近不是太忙,整理些东西,工作也许用得到. 1,为什么要用到链表 数组作为存 ...

  2. web安全:防范点击劫持的两种方式

    防范点击劫持的两种方式 什么点击劫持?最常见的是恶意网站使用 <iframe> 标签把我方的一些含有重要信息类如交易的网页嵌入进去,然后把 iframe 设置透明,用定位的手段的把一些引诱 ...

  3. Java Web学习总结(21)——http协议响应状态码大全以及常用状态码

    http协议响应状态码大全以及常用状态码 当我们在浏览网页或是在查看服务器日志时,常会遇到3位数字的状态码,这3位数字是什么意思呢?其实,这3位数字是HTTP状态码,用来表示网页服务器HTTP响应状态 ...

  4. vue.js 第一课:实例化vue

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. Spark MLlib Deep Learning Convolution Neural Network (深度学习-卷积神经网络)3.3

    3.Spark MLlib Deep Learning Convolution Neural Network(深度学习-卷积神经网络)3.3 http://blog.csdn.net/sunbow0 ...

  6. 网上看到的一些IT资源

    A.网站模板+logo+服务器主机+发票生成 HTML5 UP:响应式的HTML5和CSS3网站模板. Bootswatch:免费的Bootstrap主题. Templated:收集了845个免费的C ...

  7. hdp spark beeline

    thriftserver端口号10016 hdp所用端口号由10000改为10016 !connect jdbc:hive2://localhost:10016

  8. 【Django】序列化

    Django中序列化主要应用于将数据库中检索的数据返回给客户端用户,特别是Ajax请求一般返回为Json格式. * 1.from django.core import serializers** fr ...

  9. WPF MVVM架构 EF、WCF、IOC 设计示例经典

    概要 该演示项目利用WPF应用程序构建的MVVM架构示例, 运用了Unity容器接口注入, MVVM的经典设计, 后台利用的EF+WCF. 后台实现: 从数据库生成的emdx 结合上下文进行数据交互, ...

  10. hdu4336Card Collector 概率dp+状态压缩

    //给n个卡片每次出现的概率,求全部卡片都出现的须要抽的次数的期望 //dp[i]表示在状态的情况下到全部的卡片都出现的期望 //dp[i] = 1 + p1*dp[i] + ${p2[j]*dp[i ...