我使用 angular 8 和 angular 材料来创建我的应用程序。
我定义了以下表单字段:
<mat-form-field floatLabel="always">
<app-my-datetime-input placeholder="From" formControlName="fromDatetime"></app-my-datetime-input>
<mat-error>{{getError('fromDatetime')}}hello</mat-error>
<mat-hint>YYYY-MM-DD HH:MM:SS</mat-hint>
</mat-form-field>
并且app-my-datetime-input
是我使用以下代码创建的组件:
的HTML:
<div [formGroup]="parts">
<input matInput mask="0000-00-00 00:00:00" formControlName="datetime" (input)="_handleInput()" />
</div>
这是打字稿:
import {Component, ElementRef, forwardRef, HostBinding, Input, OnDestroy, OnInit, Optional, Self, ViewChild} from '@angular/core';
import {ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, NgControl} from '@angular/forms';
import {MatFormFieldControl, MatInput} from '@angular/material';
import {Subject} from 'rxjs';
import {coerceBooleanProperty} from '@angular/cdk/coercion';
import {FocusMonitor} from '@angular/cdk/a11y';
@Component({
selector: 'app-my-datetime-input',
templateUrl: './my-datetime-input.component.html',
styleUrls: ['./my-datetime-input.component.scss'],
providers: [{provide: MatFormFieldControl, useExisting: MyDatetimeInputComponent}],
})
export class MyDatetimeInputComponent implements ControlValueAccessor, MatFormFieldControl<string>,
OnDestroy {
get empty() {
const {value: {datetime}} = this.parts;
return !datetime;
}
// TODO: fix should label float
get shouldLabelFloat() { return this.focused || !this.empty; }
@Input()
get placeholder(): string { return this._placeholder; }
set placeholder(value: string) {
this._placeholder = value;
this.stateChanges.next();
}
@Input()
get required(): boolean { return this._required; }
set required(value: boolean) {
this._required = coerceBooleanProperty(value);
this.stateChanges.next();
}
@Input()
get disabled(): boolean { return this._disabled; }
set disabled(value: boolean) {
this._disabled = coerceBooleanProperty(value);
this._disabled ? this.parts.disable() : this.parts.enable();
this.stateChanges.next();
}
@Input()
get value(): string {
const {value: {datetime}} = this.parts;
return datetime;
}
set value(datetime: string) {
this.parts.setValue({datetime});
this.stateChanges.next();
}
constructor(
formBuilder: FormBuilder,
// tslint:disable-next-line:variable-name
private _focusMonitor: FocusMonitor,
// tslint:disable-next-line:variable-name
private _elementRef: ElementRef<HTMLElement>,
@Optional() @Self() public ngControl: NgControl) {
this.parts = formBuilder.group({
datetime: '',
});
_focusMonitor.monitor(_elementRef, true).subscribe(origin => {
if (this.focused && !origin) {
this.onTouched();
}
this.focused = !!origin;
this.stateChanges.next();
});
if (this.ngControl != null) {
this.ngControl.valueAccessor = this;
}
}
static nextId = 0;
parts: FormGroup;
stateChanges = new Subject<void>();
focused = false;
errorState = false;
controlType = 'my-datetime-input';
id = `my-datetime-input-${MyDatetimeInputComponent.nextId++}`;
describedBy = '';
// tslint:disable-next-line:variable-name
private _placeholder: string;
// tslint:disable-next-line:variable-name
private _required = false;
// tslint:disable-next-line:variable-name
private _disabled = false;
onChange = (_: any) => {};
onTouched = () => {};
ngOnDestroy() {
this.stateChanges.complete();
this._focusMonitor.stopMonitoring(this._elementRef);
}
setDescribedByIds(ids: string[]) {
this.describedBy = ids.join(' ');
}
onContainerClick(event: MouseEvent) {
if ((event.target as Element).tagName.toLowerCase() !== 'input') {
// tslint:disable-next-line:no-non-null-assertion
this._elementRef.nativeElement.querySelector('input')!.focus();
}
}
writeValue(val: string): void {
this.value = val;
}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
}
_handleInput(): void {
this.onChange(this.parts.value.datetime);
}
}
这是我第一次创建自己的表单字段组件,所以我可能在那里做错了什么......mat-error
不可见。如您所见,我将单词附加hello
到末尾,mat-error
但仍然看不到它显示。所以我猜我应该实现MatFormFieldControl
的是一种..少错误的方式?!:) 所以我真的不知道我做错了什么,所以关于这个问题的任何信息都将不胜感激。
谢谢你
更新
添加(blur)="onTouched()
但不幸的是结果是一样的。
我有一个表单验证,可确保从日期不是较新的日期。这是我的验证功能:
static fromToRangeValidator(): ValidatorFn {
return (group: FormGroup): ValidationErrors => {
const fromDate = group.get('fromDatetime');
const toDate = group.get('toDatetime');
if (fromDate.value !== '' && toDate.value !== '') {
const fromMoment = moment(fromDate.value, 'YYYYMMDDHHmmss');
const toMoment = moment(toDate.value, 'YYYYMMDDHHmmss');
if (toMoment.isBefore(fromMoment)) {
fromDate.setErrors({greaterThen: true});
toDate.setErrors({lessThen: true});
}
}
return;
};
}
并且由于错误而没有提交表单,但仍然没有显示错误