0

0

在Angular19中有关自定义表单控件使用

亚连

亚连

发布时间:2018-06-08 16:23:42

|

1303人浏览过

|

来源于php中文网

原创

这篇文章主要介绍了angular19 自定义表单控件的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下

1 需求

当开发者需要一个特定的表单控件时就需要自己开发一个和默认提供的表单控件用法相似的控件来作为表单控件;自定义的表单控件必须考虑模型和视图之间的数据怎么进行交互

2 官方文档 -> 点击前往

Angular为开发者提供了ControlValueAccessor接口来辅助开发者构建自定义的表单控件,开发者只需要在自定义表单控件类中实现ControlValueAccessor接口中的方法就可以实现模型和视图之间的数据交互

interface ControlValueAccessor { 
 writeValue(obj: any): void
 registerOnChange(fn: any): void
 registerOnTouched(fn: any): void
 setDisabledState(isDisabled: boolean)?: void
}

2.1 writeValue

writeValue(obj: any): void

该方法用于将值写入到自定义表单控件中的元素;

这个参数值(obj)是使用这个自定义表单控件的组件通过模板表单或者响应式表单的数据绑定传过来的;

在自定义表单控件的类中只需要将这个值(obj)赋值给一个成员变量即可,自定义表单控件的视图就会通过属性绑定显示出来这个值

2.2 registerOnChange

registerOnChange(fn: any): void

自定义表单控件的数据发生变化时会触发registerOnChange方法,该方用于如何处理自定义表单控件数据的变化;

registerOnChange方法接收的参数(fn)其实是一个方法,该方法负责处理变化的数据

当自定义控件数据变化时就会自动调用fn执行的方法,但是通常的做法是自定义一个方法 propagateChange 让自定义的方法指向fn,这样当数据变化时只需要调用 propagateChange 就可以对变化的数据进行处理

2.3 registerOnTouched

registerOnTouched(fn: any): void

表单控件被触摸时会触发registerOnTouched方法,具体细节待更新......2018-1-31 11:18:33

2.4 setDisabledState

setDisabledState(isDisabled: boolean)?: void

待更新......2018-1-31 11:19:30

3 编程步骤

3.1 创建自定义表单控件组件

当前计数为:{{countNumber}}


HTML

import { Component, OnInit } from '@angular/core';
import { ControlValueAccessor } from '@angular/forms';
@Component({
 selector: 'app-counter',
 templateUrl: './counter.component.html',
 styleUrls: ['./counter.component.scss']
})
export class CounterComponent implements OnInit {
 countNumber: number = 0;
 constructor() { }
 ngOnInit() {
 }
 onIncrease() {
 this.countNumber++;
 }
 onDecrease() {
 this.countNumber--;
 }
}

3.1.1 功能描述

点击增加按钮时当前计数会增加1,点击减少按钮时当前计数会剪1

 

3.1.2 直接在其他组件中使用时会报错

 

报错信息如下:

 

错误信息是说我们我们使用的组件还不是一个表单控件

3.2 如何让组件变成一个表单控件组件

3.2.1 实现 ControlValueAccessor 接口

漂亮jQuery单选框/复选框美化插件Labelauty.js?1.1.2
漂亮jQuery单选框/复选框美化插件Labelauty.js?1.1.2

漂亮jQuery单选框/复选框美化插件Labelauty.js,支持自定义灰色按钮不可点、支持input控件定义选项直接提交后端即可获取数据还是非常方便的单选框/多选框美化JS插件,特别是在手机端使用,还是非常 适用的。

下载

 

export class CounterComponent implements OnInit, ControlValueAccessor {
 countNumber: number = 0;
 constructor() { }
 ngOnInit() {
 }
 onIncrease() {
 this.countNumber++;
 }
 onDecrease() {
 this.countNumber--;
 }
 /**将数据从模型传输到视图 */
 writeValue(obj: any): void {
 }
 /**将数据从视图传播到模型 */
 registerOnChange(fn: any): void {
 }
 registerOnTouched(fn: any): void {
 }
 setDisabledState?(isDisabled: boolean): void {
 }
}

3.2.2 指定依赖信息providers

 

import { Component, OnInit, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
 selector: 'app-counter',
 templateUrl: './counter.component.html',
 styleUrls: ['./counter.component.scss'],
 providers: [
 {
  provide: NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => CounterComponent),
  multi: true
 }
 ]
})
export class CounterComponent implements OnInit, ControlValueAccessor {
 countNumber: number = 0;
 constructor() { }
 ngOnInit() {
 }
 onIncrease() {
 this.countNumber++;
 }
 onDecrease() {
 this.countNumber--;
 }
 /**将数据从模型传输到视图 */
 writeValue(obj: any): void {
 }
 /**将数据从视图传播到模型 */
 registerOnChange(fn: any): void {
 }
 registerOnTouched(fn: any): void {
 }
 setDisabledState?(isDisabled: boolean): void {
 }
}

3.2.3 待修复bug

虽然可以正常运行,但是表单控件中的元素接受不到使用表单控件那个组件中表单模型传过来的数据,表单控件变化的数据也无法回传到使用表单控件那个组件中的表单模型中去;简而言之,就是模型和视图之间无法进行数据交互

3.3 实习那模型和试图的数据交互

3.3.1 模型到视图

重构自定义表单控件类中的 writeValue 方法

技巧01:writeValue 方法中的参数是使用自定义表单控件的那个组件通过表单的数据绑定传进来的

 

3.3.2 视图到模型

》自定义一个方法来处理自定义表单控件中的变化数据

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

》重构自定义表单控件类中的 registerOnChange 方法

 /**将数据从视图传播到模型 */
 registerOnChange(fn: any): void {
 this.propagateChange = fn;
 }

》在数据变化的地方调用那个自定义的方法

 

3.4 自定义表单控件组件代码汇总

当前计数为:{{countNumber}}


HTML

import { Component, OnInit, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
 selector: 'app-counter',
 templateUrl: './counter.component.html',
 styleUrls: ['./counter.component.scss'],
 providers: [
 {
  provide: NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => CounterComponent),
  multi: true
 }
 ]
})
export class CounterComponent implements OnInit, ControlValueAccessor {
 countNumber: number = 0;
 propagateChange = (_: any) => {};
 constructor() { }
 ngOnInit() {
 }
 onIncrease() {
 this.countNumber++;
 this.propagateChange(this.countNumber);
 }
 onDecrease() {
 this.countNumber--;
 this.propagateChange(this.countNumber);
 }
 /**将数据从模型传输到视图 */
 writeValue(obj: any): void {
 this.countNumber = obj;
 }
 /**将数据从视图传播到模型 */
 registerOnChange(fn: any): void {
 /**fn其实是一个函数,当视图中的数据改变时就会调用fn指向的这个函数,从而达到将数据传播到模型的目的 */
 this.propagateChange = fn; // 将fn的指向赋值给this.propagateChange,在需要将改变的数据传到模型时只需要调用this.propagateChange方法即可
 }
 registerOnTouched(fn: any): void {
 }
 setDisabledState?(isDisabled: boolean): void {
 }
}

3.5 使用自定义表单控件的那个组件的代码汇总

技巧01:如果自定义表单控件和使用自定义表单控件的组件都在不在同一个模块时需要对自定义表单控件对应组件进行导出和导入操作

 

面板模板

面板测试内容

自定义提取表单控件

绿线上是自定义提取的表单控件显示的内容

绿线下是使用自定义表单控件时表单的实时数据

表单控件的值为:{{myForm.value | json}}

提取表单控件

outerCounterValue value: {{outerCounterValue}}



{{form.value | json}}

ngIf指令测试


ngif变量的值为true

ngif变量的值为false

RXJS使用

测试内容

自定义验证器



响应式表单

@163.com

表单整体信息如下:

表单数据有效性:{{testForm.valid}}

表单数据为:{{testForm.value | json}}

获取单个或多个FormControl:{{testForm.controls['email'] }}


email输入框的信息如下:

有效性:{{testForm.get('email').valid}}

email输入框的错误信息为:{{testForm.get('email').errors | json}}

required验证结果:{{testForm.hasError('required', 'email') | json}}

minLength验证结果:{{ testForm.hasError('minLength', 'email') | json }}

hello:{{ testForm.controls['email'].errors | json }}


password输入框啊的信息如下:

有效性:{{testForm.get('password').valid}}

password输入框的错误信息为:{{testForm.get('password').errors | json }}

required验证结果:{{testForm.hasError('required', 'password') | json}}

data变量:{{data}}

利用响应式编程实现表单元素双向绑定

姓名为:{{name.value}}

-->

模板表单

名为desc的表单控件的值为:{{ a.value }}

md-chekbox的使用

测试

测试checkbox被选中啦

md-tooltip的使用

鼠标放上去

md-select的使用

{{taskList.name}}

ngNonBindable指令的使用

描述

使用了ngNonBindable的标签,会将该标签里面的元素内容全部都看做时纯文本

例子

{{taskLists | json }} ← 这是{{taskLists | json }}渲染的内容

HTML

 

import { Component, OnInit, HostListener, Inject} from '@angular/core';
import { FormControl, FormGroup, FormBuilder, Validators } from '@angular/forms';
import { Http } from '@angular/http';
import { QuoteService } from '../../service/quote.service';
@Component({
 selector: 'app-test01',
 templateUrl: './test01.component.html',
 styleUrls: ['./test01.component.scss']
})
export class Test01Component implements OnInit {
 countNumber: number = 9;
 outerCounterValue: number = 5; 
 ngif = true;
 loginForm: FormGroup;
 testForm: FormGroup;
 data: any;
 name: FormControl = new FormControl();
 desc: string = 'hello boy';
 taskLists = [
 {label: 1, name: '进行中'},
 {label: 2, name: '已完成'}
 ];
 constructor(
 private formBuilder: FormBuilder,
 private http: Http,
 @Inject('BASE_CONFIG') private baseConfig,
 private quoteService: QuoteService
 ) {}
 ngOnInit() {
 this.testForm = new FormGroup({
  email: new FormControl('', [Validators.required, Validators.minLength(4)], []),
  password: new FormControl('', [Validators.required], [])
 });
 this.name.valueChanges
 .debounceTime(500)
 .subscribe(value => alert(value));
 this.loginForm = this.formBuilder.group({
  username: ['', [Validators.required, Validators.minLength(4), this.myValidator], []],
  userpwd: ['', [Validators.required, Validators.minLength(6)], []]
 });
 this.quoteService.test()
 .subscribe(resp => console.log(resp));
 }
 onChangeNgifValue() {
 if (this.ngif == false) {
  this.ngif = true;
 } else {
  this.ngif = false;
 }
 }
 @HostListener('keyup.enter')
 onTestNgModelClick() {
 alert('提交');
 }
 onTestClick() {
 // this.data = this.testForm.get('email').value;
 // console.log(this.testForm.getError);
 console.log(this.testForm.controls['email']);
 }
 onTestLogin() {
 console.log(this.loginForm.value);
 if (this.loginForm.valid) {
  console.log('登陆数据合法');
 } else {
  console.log('登陆数据不合法');
  console.log(this.loginForm.controls['username'].errors);
  console.log(this.loginForm.get('userpwd').errors);
 }
 }
 myValidator(fc: FormControl): {[key: string]: any} {
 const valid = fc.value === 'admin';
 return valid ? null : {myValidator: {requiredUsername: 'admin', actualUsername: fc.value}};
 }
}

3.6 初始化效果展示

 

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

JavaScript中Object基础内部方法图(图文教程)

在webpack中如何使用ECharts?

vue如何制作自动建站项目(详细教程)

相关专题

更多
php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

7

2025.12.31

php网站源码教程大全
php网站源码教程大全

本专题整合了php网站源码相关教程,阅读专题下面的文章了解更多详细内容。

4

2025.12.31

视频文件格式
视频文件格式

本专题整合了视频文件格式相关内容,阅读专题下面的文章了解更多详细内容。

7

2025.12.31

不受国内限制的浏览器大全
不受国内限制的浏览器大全

想找真正自由、无限制的上网体验?本合集精选2025年最开放、隐私强、访问无阻的浏览器App,涵盖Tor、Brave、Via、X浏览器、Mullvad等高自由度工具。支持自定义搜索引擎、广告拦截、隐身模式及全球网站无障碍访问,部分更具备防追踪、去谷歌化、双内核切换等高级功能。无论日常浏览、隐私保护还是突破地域限制,总有一款适合你!

7

2025.12.31

出现404解决方法大全
出现404解决方法大全

本专题整合了404错误解决方法大全,阅读专题下面的文章了解更多详细内容。

42

2025.12.31

html5怎么播放视频
html5怎么播放视频

想让网页流畅播放视频?本合集详解HTML5视频播放核心方法!涵盖<video>标签基础用法、多格式兼容(MP4/WebM/OGV)、自定义播放控件、响应式适配及常见浏览器兼容问题解决方案。无需插件,纯前端实现高清视频嵌入,助你快速打造现代化网页视频体验。

4

2025.12.31

关闭win10系统自动更新教程大全
关闭win10系统自动更新教程大全

本专题整合了关闭win10系统自动更新教程大全,阅读专题下面的文章了解更多详细内容。

3

2025.12.31

阻止电脑自动安装软件教程
阻止电脑自动安装软件教程

本专题整合了阻止电脑自动安装软件教程,阅读专题下面的文章了解更多详细教程。

3

2025.12.31

html5怎么使用
html5怎么使用

想快速上手HTML5开发?本合集为你整理最实用的HTML5使用指南!涵盖HTML5基础语法、主流框架(如Bootstrap、Vue、React)集成方法,以及无需安装、直接在线编辑运行的平台推荐(如CodePen、JSFiddle)。无论你是新手还是进阶开发者,都能轻松掌握HTML5网页制作、响应式布局与交互功能开发,零配置开启高效前端编程之旅!

2

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Vue.js:纪录片
Vue.js:纪录片

共1课时 | 0.2万人学习

Angular js入门篇
Angular js入门篇

共17课时 | 3.5万人学习

PHP自制框架
PHP自制框架

共8课时 | 0.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号