如何使用 Angular 重置自定义表单控件
Posted
技术标签:
【中文标题】如何使用 Angular 重置自定义表单控件【英文标题】:How can I reset a custom form control with Angular 【发布时间】:2018-11-09 21:54:04 【问题描述】:我有一个带有验证的自定义表单控件。我在其中使用了一个独立的 FormControl 来处理值和一些验证。
当控件从另一个 FormGroup 重置时,Angular 有没有办法重置内部 FormControl?
Bellow 是我的自定义表单控件。我希望能够重置 durationControl。
duration.component.ts
import ChangeDetectionStrategy, Component, Input, OnInit, Optional, Self from '@angular/core';
import AbstractControl, ControlValueAccessor, FormControl, NgControl, ValidationErrors, Validators from '@angular/forms';
import Observable from 'rxjs';
import map, startWith, tap from 'rxjs/operators';
import Regex from '../../constants';
@Component(
selector: 'my-duration',
templateUrl: 'duration.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
)
export class DurationComponent implements ControlValueAccessor, OnInit
@Input() required: boolean;
durations: string[] = [
'15m',
'30m',
'45m',
'1h',
'1h 15m',
'1h 30m',
'1h 45m',
'2h'
];
filteredDurations: Observable<string[]>;
durationControl = new FormControl('', [
Validators.required,
Validators.pattern(Regex.duration),
DurationComponent.zeroDurationValidator
]);
constructor(
@Self()
@Optional()
public ngControl: NgControl
)
if (ngControl)
ngControl.valueAccessor = this;
static zeroDurationValidator(control: AbstractControl): ValidationErrors
return control.value === '0m' ||
control.value === '00m' ||
control.value === '0h' ||
control.value === '00h' ||
control.value === '0h 0m' ||
control.value === '0h 00m' ||
control.value === '00h 00m' ||
control.value === '00h 0m'
? zeroDurationError: true
: null;
onChangeCallback = (value: string) => ;
onTouchCallback = () => ;
ngOnInit(): void
this.initializeFilters();
initializeFilters()
this.filteredDurations = this.durationControl.valueChanges.pipe(
tap(value => this.onChangeCallback(value)),
map(value => this.filterDurations(value))
);
onBlur()
this.onTouchCallback();
registerOnChange(fn: any): void
this.onChangeCallback = fn;
registerOnTouched(fn: any): void
this.onTouchCallback = fn;
writeValue(obj: any): void
this.durationControl.setValue(obj,
emitModelToViewChange: true
);
this.onChangeCallback(obj);
private filterDurations(value: string)
return this.durations.filter(duration => duration.indexOf(value) === 0);
duration.component.html
<mat-form-field>
<input [formControl]="durationControl"
type="text"
matInput
autocomplete="off"
[placeholder]="'DURATION' | translate"
[matAutocomplete]="durationAutocomplete"
>
<mat-error *ngIf="durationControl.hasError('required')"> 'FORM_VALIDATION.REQUIRED' | translate </mat-error>
<mat-error *ngIf="durationControl.hasError('pattern')"> 'FORM_VALIDATION.INVALID_FORMAT' | translate </mat-error>
<mat-error *ngIf="durationControl.hasError('zeroDurationError')"> 'FORM_VALIDATION.ZERO_DURATION_ERROR' | translate </mat-error>
<mat-autocomplete #durationAutocomplete="matAutocomplete">
<mat-option *ngFor="let duration of filteredDurations | async" [value]="duration">
duration
</mat-option>
</mat-autocomplete>
</mat-form-field>
【问题讨论】:
你可以使用markAsUntouched @mehany 这不是在重置任何东西,是吗? 【参考方案1】:重置表单时,所有控件在 writeValue 方法中都接收到 null。然后我可以像这样重置 durationControl:
writeValue(obj: any): void
if (obj === null)
this.durationControl.reset();
this.durationControl.setValue(obj,
emitModelToViewChange: true
);
this.onChangeCallback(obj);
【讨论】:
什么?这意味着我不能将表单控件的值设置为null
?我真的怀疑这是一个好的解决方案。
这是一个很棒的解决方案。作为对上述评论的回应,无论如何,将 ANY 控件设置为 null
都意味着它在 UI 上看起来很清晰,因此如何执行它并没有什么区别。如果您确实需要将该值设置为 null
以发送到后端或其他内容,您可以随时更改在提交调用后处理中收到的对象。
非常优雅。 .reset()【参考方案2】:
组件声明必须包含 provider NG_VALUE_ACCESSOR
。
在您的特定组件中,这看起来像:
@Component(
selector: 'my-duration',
templateUrl: 'duration.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DurationComponent),
multi: true
]
)
【讨论】:
我在使用另一种方式,在构造函数中: if (ngControl) ngControl.valueAccessor = this; 我正在使用您描述的提供程序,但表单重置不会重置我的组件。以上是关于如何使用 Angular 重置自定义表单控件的主要内容,如果未能解决你的问题,请参考以下文章