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. 【Codeforces Round #460 (Div. 2) C】 Seat Arrangements

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 用pre[i][j]表示第i行前j列的和. 然后枚举连续座位的最左上点. (有两种可能向右或向下k个. 则还需要处理出pre2[i] ...

  2. Kinect 开发 —— 骨骼追踪

    骨骼追踪技术通过处理景深数据来建立人体各个关节的坐标,骨骼追踪能够确定人体的各个部分,如那部分是手,头部,以及身体.骨骼追踪产生X,Y,Z数据来确定这些骨骼点.骨骼追踪系统采用的景深图像处理技术使用更 ...

  3. Vue 实现分页+输入框关键字筛选

    分页的实现(Vue+Element)+输入框关键字筛选 1.这里用的是Element 自带的分页组件 <template> <div class="sales-table& ...

  4. gpasswd---指定要管理的工作组,及更改密码

    gpasswd 命令详解 gpasswd命令是Linux下工作组文件/etc/group和/etc/gshadow的管理工具,用于指定要管理的工作组. 2.选项详解: -a : 添加用户到组 -d : ...

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

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

  6. 有关cascade的结构体

    /* internal cascade classifier */ typedef struct CvCascadeHaarClassifier { CV_INT_HAAR_CLASSIFIER_FI ...

  7. 引用 Windows Server 2003 FTP服务器配置详解

    引用 昆神之星 的 Windows Server 2003 FTP服务器配置详解 1.FTP文件传输协议,主要用于计算机之间文件传输,是互联网上仅次于www的第二大服务.本文主要演示如何在Window ...

  8. excel表如何实现多if选择结构多分支判断

    excel表如何实现多if选择结构多分支判断 一.总结 一句话总结:把多if分支转换成单if分支相加. 也可以if分支,也可以lookup函数. 1.CHOICE: +2 if band A; +1 ...

  9. JavaScript 实现表格单列按字母排序

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

  10. C#监控代码运行的时间

    System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch(); watch.Start(); //开始监视代码运行时间 ...