网站换服务器要怎么做公司做网站需要多少钱
简介
在 Angular 中创建表单时,有时您希望拥有一个不是标准文本输入、选择或复选框的输入。通过实现 ControlValueAccessor
接口并将组件注册为 NG_VALUE_ACCESSOR
,您可以将自定义表单控件无缝地集成到模板驱动或响应式表单中,就像它是一个原生输入一样!
!Rating Input 组件示例的动画 GIF,选择不同数量的星星。
在本文中,您将把一个基本的星级评分输入组件转换为 ControlValueAccessor
。
先决条件
要完成本教程,您需要:
- 本地安装 Node.js,您可以按照《如何安装 Node.js 并创建本地开发环境》进行操作。
- 一些设置 Angular 项目和使用 Angular 组件的基础知识可能会有所帮助。
本教程已在 Node v16.4.2、npm
v7.18.1、angular
v12.1.1 上进行验证。
步骤 1 — 设置项目
首先,创建一个新的 RatingInputComponent
。
可以使用 @angular/cli
完成此操作:
ng generate component rating-input --inline-template --inline-style --skip-tests --flat --prefix
这将向应用程序的 declarations
中添加新组件,并生成一个 rating-input.component.ts
文件:
import { Component, OnInit } from '@angular/core';@Component({selector: 'rating-input',template: `<p>rating-input works!</p>`,styles: []
})
export class RatingInputComponent implements OnInit {constructor() { }ngOnInit(): void {}}
添加模板、样式和逻辑:
import { Component } from '@angular/core';@Component({selector: 'rating-input',template: `<span*ngFor="let starred of stars; let i = index"(click)="rate(i + (starred ? (value > i + 1 ? 1 : 0) : 1))"><ng-container *ngIf="starred; else noStar">⭐</ng-container><ng-template #noStar>·</ng-template></span>`,styles: [`span {display: inline-block;width: 25px;line-height: 25px;text-align: center;cursor: pointer;}`]
})
export class RatingInputComponent {stars: boolean[] = Array(5).fill(false);get value(): number {return this.stars.reduce((total, starred) => {return total + (starred ? 1 : 0);}, 0);}rate(rating: number) {this.stars = this.stars.map((_, i) => rating > i);}
}
我们可以获取组件的 value
(从 0
到 5
),并通过调用 rate
函数或点击所需的星级来设置组件的值。
您可以将组件添加到应用程序中:
<rating-input></rating-input>
然后运行应用程序:
ng serve
并在 Web 浏览器中进行交互。
这很棒,但我们不能只是将此输入添加到表单中并期望一切立即正常工作。我们需要将其设置为 ControlValueAccessor
。
步骤 2 — 创建自定义表单控件
为了使 RatingInputComponent
表现得就像是一个原生输入(因此是一个真正的自定义表单控件),我们需要告诉 Angular 如何做一些事情:
- 写入输入的值 -
writeValue
- 注册一个函数,告诉 Angular 输入的值何时发生变化 -
registerOnChange
- 注册一个函数,告诉 Angular 输入已被触摸 -
registerOnTouched
- 禁用输入 -
setDisabledState
这四个内容构成了 ControlValueAccessor
接口,它是表单控件和原生元素或自定义输入组件之间的桥梁。一旦我们的组件实现了该接口,我们需要告诉 Angular 通过提供它作为 NG_VALUE_ACCESSOR
来使用它。
在代码编辑器中重新查看 rating-input.component.ts
,并进行以下更改:
import { Component, forwardRef, HostBinding, Input } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';@Component({selector: 'rating-input',template: `<span*ngFor="let starred of stars; let i = index"(click)="onTouched(); rate(i + (starred ? (value > i + 1 ? 1 : 0) : 1))"><ng-container *ngIf="starred; else noStar">⭐</ng-container><ng-template #noStar>·</ng-template></span>`,styles: [`span {display: inline-block;width: 25px;line-height: 25px;text-align: center;cursor: pointer;}`],providers: [{provide: NG_VALUE_ACCESSOR,useExisting: forwardRef(() => RatingInputComponent),multi: true}]
})
export class RatingInputComponent implements ControlValueAccessor {stars: boolean[] = Array(5).fill(false);// 允许输入被禁用,并在禁用时使其略微透明。@Input() disabled = false;@HostBinding('style.opacity')get opacity() {return this.disabled ? 0.25 : 1;}// 当评分发生变化时调用的函数。onChange = (rating: number) => {};// 当输入被触摸时(点击星星时)调用的函数。onTouched = () => {};get value(): number {return this.stars.reduce((total, starred) => {return total + (starred ? 1 : 0);}, 0);}rate(rating: number) {if (!this.disabled) {this.writeValue(rating);}}// 允许 Angular 更新模型(评分)。// 在这里更新模型和视图所需的更改。writeValue(rating: number): void {this.stars = this.stars.map((_, i) => rating > i);this.onChange(this.value);}// 允许 Angular 注册一个在模型(评分)更改时调用的函数。// 将函数保存为以后调用的属性。registerOnChange(fn: (rating: number) => void): void {this.onChange = fn;}// 允许 Angular 注册一个在输入被触摸时调用的函数。// 将函数保存为以后调用的属性。registerOnTouched(fn: () => void): void {this.onTouched = fn;}// 允许 Angular 禁用输入。setDisabledState(isDisabled: boolean): void {this.disabled = isDisabled;}
}
此代码将允许输入被禁用,并在禁用时使其略微透明。
运行应用程序:
ng serve
并在 Web 浏览器中进行交互。
您还可以禁用输入控件:
<rating-input [disabled]="true"></rating-input>
现在我们可以说我们的 RatingInputComponent
是一个自定义表单组件!它将在模板驱动或响应式表单中像任何其他原生输入一样工作(Angular 为这些提供了 ControlValueAccessors
!)。
结论
在本文中,您将一个基本的星级评分输入组件转换为了 ControlValueAccessor
。
现在您会注意到:
ngModel
现在可以正常工作。- 我们可以添加自定义验证。
- 控件状态和有效性可以通过
ngModel
获得,比如ng-dirty
和ng-touched
类。
如果您想了解更多关于 Angular 的知识,请查看我们的 Angular 专题页面,了解练习和编程项目。