angular8 报错Cannot create property 'validator' on string 'age'
如何调试angular程序,一有错误就指向源码?
程序是一个自定义表单组件,
typescript如下
import { Component, OnInit, Input, forwardRef, OnDestroy } from "@angular/core"
import {
ControlValueAccessor,
NG_VALUE_ACCESSOR,
NG_VALIDATORS,
FormControl,
FormBuilder,
FormGroup
} from "@angular/forms"
import {
map,
filter,
startWith,
debounceTime,
distinctUntilChanged
} from "rxjs/operators"
import { Observable, Subscription } from "rxjs"
import { combineLatest, merge } from "rxjs"
import {
subDays,
subMonths,
subYears,
differenceInDays,
differenceInMonths,
differenceInYears,
isBefore,
parse,
isDate,
isFuture,
format,
isValid,
toDate
} from "date-fns"
export enum AgeUnit {
Year = 0,
Month,
Day
}
import { isValidDate } from "../../utils/date.util"
export interface Age {
age: number
unit: AgeUnit
}
@Component({
selector: "app-age-input",
templateUrl: "./age-input.component.html",
styleUrls: ["./age-input.component.scss"],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => AgeInputComponent),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => AgeInputComponent),
multi: true
}
]
})
export class AgeInputComponent
implements ControlValueAccessor, OnDestroy, OnInit {
selectedUnit = AgeUnit.Year
@Input() daysTop = 90
@Input() daysBottom = 0
@Input() monthsTop = 24
@Input() monthsBottom = 1
@Input() yearsTop = 150
@Input() yearsBottom = 0
@Input() format = "yyyy-MM-DD"
@Input() debounceTime = 300
ageUnits = [
{ value: AgeUnit.Year, Label: "岁" },
{ value: AgeUnit.Month, Label: "月" },
{ value: AgeUnit.Day, Label: "天" }
]
dateOfBirth
private propageteChange = (_: any) => {}
form: FormGroup
sub: Subscription
// dateFormat = "YYYY-MM-DD"
constructor(private fb: FormBuilder) {}
ngOnInit() {
const initDate = this.dateOfBirth
? this.dateOfBirth
: toDate(subYears(Date.now(), 30))
const initAge = this.toAge(initDate)
// this.propageteChange("ss")
this.form = this.fb.group({
birthday: [initDate, this.validateDate],
age: this.fb.group(
{
ageNum: [initAge.age],
ageUnit: [AgeUnit.Year]
},
{
validator: this.validateAge("ageNum", "ageUnit")
}
)
})
const birthday = this.form.get("birthday")
const ageNum = this.form.get("age").get("ageNum")
const ageUnit = this.form.get("age").get("ageUnit")
const birthday$ = birthday.valueChanges.pipe(
map(d => {
return {
date: d,
from: "birthday"
}
}),
debounceTime(this.debounceTime),
distinctUntilChanged(),
filter(_ => birthday.valid)
)
const ageNum$ = ageNum.valueChanges.pipe(
startWith(ageNum.value),
debounceTime(this.debounceTime),
distinctUntilChanged()
)
const ageUnit$ = ageUnit.valueChanges.pipe(
startWith(ageUnit.value),
debounceTime(this.debounceTime),
distinctUntilChanged()
)
const age$ = combineLatest(ageNum$, ageUnit$, (_n, _u) => {
return this.toDate({
age: _n,
unit: _u
})
}).pipe(
map(d => {
return {
date: d,
from: "age"
}
}),
filter(_ => this.form.get("age").valid)
)
const merged$ = merge(birthday$, age$).pipe(filter(_ => this.form.valid))
this.sub = merged$.subscribe(d => {
const age = this.toAge(d.date)
if (d.from === "birthday") {
if (age.age !== ageNum.value) {
ageNum.patchValue(age.age, { emitEvent: false })
}
if (age.unit !== ageUnit.value) {
this.selectedUnit = age.unit
ageUnit.patchValue(age.age, { emitEvent: false })
}
this.propageteChange(d.date)
} else {
const ageToCompare = this.toAge(birthday.value)
if (age.age !== ageToCompare.age || age.unit !== ageToCompare.unit) {
birthday.patchValue(d.date, { emitEvent: false })
this.propageteChange(d.date)
}
}
})
}
writeValue(obj: any): void {
// 用来写值的
// this.selected = obj
// this.propageteChange(this.selected)
if (obj) {
this.form.get("birthday").patchValue(format(obj, this.format))
}
}
registerOnChange(fn: any): void {
this.propageteChange = fn
}
registerOnTouched(fn: any): void {}
toAge(dateStr: string): Age {
const date = parse(dateStr, this.format, Date.now())
const now = new Date()
return isBefore(subDays(now, this.daysTop), date)
? { age: differenceInDays(now, date), unit: AgeUnit.Day }
: isBefore(subMonths(now, this.monthsTop), date)
? { age: differenceInMonths(now, date), unit: AgeUnit.Month }
: {
age: differenceInYears(now, date),
unit: AgeUnit.Year
}
}
toDate(age: Age): string {
const now = Date.now()
switch (age.unit) {
case AgeUnit.Year: {
return format(subYears(now, age.age), this.format)
}
case AgeUnit.Month: {
return format(subMonths(now, age.age), this.format)
}
case AgeUnit.Day: {
return format(subDays(now, age.age), this.format)
}
default: {
return null
}
}
}
ngOnDestroy() {
if (this.sub) {
this.sub.unsubscribe()
}
}
validate(c: FormControl): { [key: string]: any } {
const val = c.value
if (!val) {
return null
}
if (isValidDate(val)) {
return null
}
return {
dateOfBirthInvalid: true
}
}
validateDate(c: FormControl): { [key: string]: any } {
const val = c.value
return isValidDate(val)
? null
: {
birthdayInvalid: true
}
}
validateAge(ageNumKey: string, ageUnitKey: string) {
return (group: FormGroup): { [key: string]: any } => {
const ageNum = group.controls[ageNumKey]
const ageUnit = group.controls[ageUnitKey]
let result = false
const ageNumVal = ageNum.value
switch (ageUnit.value) {
case AgeUnit.Year: {
result = ageNumVal >= this.yearsBottom && ageNumVal < this.yearsTop
break
}
case AgeUnit.Month: {
result = ageNumVal >= this.monthsBottom && ageNumVal < this.monthsTop
break
}
case AgeUnit.Day: {
result = ageNumVal >= this.daysBottom && ageNumVal < this.daysTop
break
}
default: {
result = false
return null
}
}
}
}
}
Html如下
<form [formGroup]="form" class="age-input">
<mat-form-field>
<input matInput [matDatepicker]="birthday" placeholder="出生日期" formControlName="birthday" type="text">
<mat-error></mat-error>
<mat-datepicker-toggle matSuffix [for]="birthday"></mat-datepicker-toggle>
<!-- <button matSuffix [matDatepickerToggle]="birthday"></button> -->
<mat-datepicker touchUi='true' #birthday></mat-datepicker>
</mat-form-field>
<ng-container formGroup="age">
<div class="age-num">
<mat-form-field>
<input matInput placeholder="年龄" type="number" formControlName="birthday">
</mat-form-field>
</div>
<div>
<mat-button-toggle-group formControlName="ageUnit" [(ngModel)]="selectUnit">
<mat-button-toggle *ngFor="let unit of ageUnits" [value]='unit.value'>
{{unit.Label}}
</mat-button-toggle>
</mat-button-toggle-group>
</div>
<mat-error *ngIf="form.get('age').hasError('ageInvalid')">年龄或单位不正确</mat-error>
</ng-container>
</form>
报错如下
问题描述
问题出现的环境背景及自己尝试过哪些方法
相关代码
// 请把代码文本粘贴到下方(请勿用图片代替代码)
你期待的结果是什么?实际看到的错误信息又是什么?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
应该是
formControlName
有问题,少了一个formControlName=age
的表单组件。你这个的
formControlName=age
应该写错了吧。