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. ExtAspNet依据Grid导出Excel

    protected void Button1_Click(object sender, EventArgs e) { Response.ClearContent(); Response.AddHead ...

  2. UML图和C#

        这段时间学习了楚光明老师解说的C#视频,接触这个学习材料的第一感觉就是老师解说的通俗易懂,非常easy让人去接受:再有就是在学习到UML图和C#的一节时非常有收获,之前自己也学习过UML图的一 ...

  3. 使用cecil 完毕 code injection

    1. 安装Mono.Cecil watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFuX2xpYW5n/font/5a6L5L2T/fontsize/400 ...

  4. Excel的版本

    https://en.wikipedia.org/wiki/Microsoft_Excel 取自维基百科,需要特别注意的是,从v12开始,有很大的改变.后缀名从xls变为xlsx Versions 5 ...

  5. Get Started with Git and Team Services

    https://www.visualstudio.com/en-us/docs/git/gitquickstart Visual Studio查看日志 LocalHistory和Incoming是拆开 ...

  6. Hive里的分区、分桶、视图和索引再谈

    福利 => 每天都推送 欢迎大家,关注微信扫码并加入我的4个微信公众号:   大数据躺过的坑      Java从入门到架构师      人工智能躺过的坑         Java全栈大联盟   ...

  7. maven项目引入sqljdbc4 找不到包的完美 解决方案

    今天碰到了这个问题,解决了,顺便做一下记录.首先来 重现 一下这个问题,maven install报错,说 找不到这个包,但是其实 我已经安装了. 我们 再来 看看 maven本地仓库里面有 什么,这 ...

  8. shell 日期转换

    1.字符串转换为时间戳可以这样做: date -d "2010-10-18 00:00:00" +%s 输出形如: 1287331200 其中,-d参数表示显示指定的字符串所表示的 ...

  9. Markdown最简单常用的语法

    1,文本强调: 文本倾斜,*我是倾斜的文本* 文本加粗,**我是加粗的文本** 文本删除线,~~带删除线的文本~~ 2,链接,分为行内式与参数式,参数式多用于在文章中多次使用相同的链接 行内式写法:[ ...

  10. chfn---改变finger命令显示的信息

    chfn命令   chfn命令用来改变finger命令显示的信息.这些信息都存放在/etc目录里的passwd文件里.若不指定任何选项,则chfn命令会进入问答式界面. 语法 chfn(选项)(参数) ...