下面我将为你详细讲解“浅析Angular19自定义表单控件”的完整攻略。如果您是Angular开发者,那么您一定知道表单是Web应用程序中至关重要的一部分。Angular提供了很多内置的表单控件,例如文本框、下拉框、单选框等。但是,在某些情况下,内置控件可能无法满足我们的需求。因此,我们需要自定义表单控件。下面是自定义表单控件的完整攻略:
1. 创建自定义表单控件
创建自定义表单控件需要创建一个组件,并实现controlvalueaccessor接口。接口是一个用于控制表单控件值的方法集合。
控件本身应该继承AbstractControl类以实现表单校验。使用@HostBinding绑定DOM元素。具体的示例如下:
import { Component, Input, Output, forwardRef, EventEmitter, OnInit,
HostBinding } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR, AbstractControl }
from '@angular/forms';
@Component({
selector: 'app-custom-control',
template: '<input [(ngModel)]="value">',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CustomControlComponent),
multi: true
}
]
})
export class CustomControlComponent implements ControlValueAccessor {
@Input() placeholder: string;
@Output() customValueChange = new EventEmitter();
value: any;
onTouched: () => void = () => { };
onChange: (_: any) => void = () => { };
writeValue(value: any) {
this.value = value
}
registerOnChange(fn: any) {
this.onChange = fn;
}
registerOnTouched(fn: any) {
this.onTouched = fn;
}
onValueChange() {
this.customValueChange.emit(this.value);
this.onChange(this.value);
this.onTouched();
}
setDisabledState(isDisabled: boolean) {
// 写你自己的代码
}
}
上面代码中,CustomControlComponent 组件是一个基本的输入框,它通过实现ControlValueAccessor接口来控制表单控件的值,通过监听输入框的变化,通知 onChange,onTouched两个回调函数。注意控件值的读取和写入都需要手动实现。
在父组件中,您可以像使用内置表单控件一样使用自定义表单控件:
<app-custom-control [(ngModel)]="value"></app-custom-control>
2. 自定义表单控件实现表单验证
在 Angular 中,表单验证由 Validators 类提供的一些内置验证器完成。同样地,我们也可以自定义表单验证器。
下面是一个自定义表单验证器的示例。该验证器将最小长度设置为4。
import { AbstractControl } from '@angular/forms';
export function minLengthValidator(minLength: number) {
return (control: AbstractControl) => {
const value = control.value;
return value && value.length >= minLength ? null : {
mininumLength: {
expectedLength: minLength,
actualLength: value ? value.length : 0
}
};
};
}
上面的自定义表单验证器接受一个最小长度值作为参数,返回一个验证函数。valid()方法返回null表示验证通过,否则返回一个包含验证失败信息的对象。您可以像下面这样使用自定义表单验证器:
form = this.fb.group({
customControl: ['', [minLengthValidator(4)]]
});
示例1:自定义单选框控件
如下是一个可以用来展示生肖列表的自定义单选框控件示例:
import { Component, Input, Output, forwardRef, EventEmitter, OnInit, HostBinding } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR, AbstractControl } from '@angular/forms';
@Component({
selector: 'app-custom-checkbox',
template: `
<div *ngFor="let item of data">
<input
type="radio"
[checked]="item.value === value"
(blur)="onTouched()"
[name]="name"
[value]="item.value"
(change)="writeValue(item.value)">
{{item.text}}
</div>
`,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CustomRadioComponent),
multi: true
}
]
})
export class CustomRadioComponent implements ControlValueAccessor {
@Input() data: any[];
@Input() name: string;
@Output() customValueChange = new EventEmitter();
value: any;
onTouched: () => void = () => {};
onChange: (_: any) => void = () => {};
writeValue(value: any) {
this.value = value;
this.customValueChange.emit(this.value);
this.onTouched();
}
registerOnChange(fn: any) {
this.onChange = fn;
}
registerOnTouched(fn: any) {
this.onTouched = fn;
}
setDisabledState(isDisabled: boolean) {
// 写你自己的代码
}
}
上述代码中,我们使用了两个模板变量:data 和 name,其中 data 表示一个数组,包含每个单选项的值和显示文本。name 表示单选框的名称。每个单选项都会生成一个单选框元素,并绑定各种属性。
示例2:自定义上传文件组件
下面是一个自定义的上传文件组件,该组件可以允许用户上传多个文件并在上传时展示进度条:
import { Component, OnInit, Input, EventEmitter, Output } from '@angular/core';
@Component({
selector: 'app-file-upload',
templateUrl: './file-upload.component.html',
styleUrls: ['./file-upload.component.scss']
})
export class FileUploadComponent implements OnInit {
@Input() files: any = [];
@Input() multiple: boolean = false;
@Input() label: string = '选择文件';
@Input() uploadUrl: string = '';
@Input() uploadFieldName: string = 'file';
@Input() maxSize?: number = null;
@Input() accept: string = '*';
@Output() done: EventEmitter<any> = new EventEmitter<any>();
@Output() progress: EventEmitter<number> = new EventEmitter<number>();
@Output() error: EventEmitter<any> = new EventEmitter<any>();
@Output() removed: EventEmitter<any> = new EventEmitter<any>();
@Output() added: EventEmitter<any> = new EventEmitter<any>();
pendingFiles: any[] = [];
ngOnInit(): void {
}
onChange(event) {
this.pendingFiles = Array.from(event.target.files || []);
for (let i = 0; i < this.pendingFiles.length; i++) {
if (this.validate(this.pendingFiles[i])) {
this.added.emit(this.pendingFiles[i]);
} else {
this.pendingFiles.splice(i, 1);
i--;
}
}
}
upload() {
const files = this.pendingFiles.slice(0);
this.pendingFiles = [];
for (let i = 0; i < files.length; i++) {
const file = files[i];
const xhr = new XMLHttpRequest();
const formData = new FormData()
formData.append(this.uploadFieldName, file, file.name)
xhr.onload = () => {
if (xhr.status === 200) {
this.done.emit(xhr.responseText);
} else {
this.error.emit(xhr.responseText);
}
const progress = ((i + 1) / files.length) * 100;
this.progress.emit(progress);
}
xhr.onerror = () => {
this.error.emit(xhr.responseText);
}
xhr.upload.onprogress = (e) => {
const progress = ((e.loaded / e.total) * 100);
this.progress.emit(progress);
}
xhr.upload.onabort = () => {
this.removed.emit(file);
}
xhr.open('POST', this.uploadUrl, true)
xhr.send(formData)
}
}
remove(file) {
const index = this.pendingFiles.indexOf(file);
if (index !== -1) {
this.pendingFiles.splice(index, 1);
this.removed.emit(file);
}
}
validate(file): boolean {
if (this.maxSize && file.size / 1024 > this.maxSize) {
this.error.emit('文件超出最大大小');
return false;
}
if (this.accept !== '*' && !new RegExp(this.accept).test(file.type)) {
this.error.emit('文件类型不允许');
return false;
}
return true;
}
}
上述代码中,我们使用了一个文件选择器元素来允许用户选择文件。当文件选择器的值发生变化时,我们将选中的文件保存在数组变量pendingFiles中,并校验文件类型和大小。然后我们根据服务器API将文件上传到服务端,并在上传完成后通知使用此组件的父组件以显示上传进度。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:浅析Angular19 自定义表单控件 - Python技术站