我有一个包含几个自定义表单组件的反应表单。我创建了这个组件以在多种表单中使用,并且我从 “ControlValueAccessor”接口继承,它运行良好,我查看每个自定义组件的值并查看表单和组件是否有效。但是我提交表单后无法显示验证错误消息。
例如,我有一个自动完成组件来显示办公室位置,通常当触摸此组件并且未选择位置时,您会看到有关用户必须选择位置的错误;但它不适用于表单提交。
这是组件的html:
<div [formGroup]="cityForm">
<mat-form-field appearance="outline">
<mat-label i18n >Office locations</mat-label>
<input matInput i18n-aria-label
aria-label="cities"
[matAutocomplete]="auto"
[formControl]="officeLocationControl">
<mat-error *ngIf="officeLocationControl.hasError('required')" i18n >
Please select an <strong>Ofice location</strong>
</mat-error>
<mat-autocomplete #auto="matAutocomplete">
<mat-option *ngFor="let city of filteredCities | async" [value]="city.name">
<span>{{city.name}}</span>
</mat-option>
</mat-autocomplete>
</mat-form-field>
</div>
import { CityService } from './../../services/city.service';
import { ChangeDetectionStrategy, Component, forwardRef, OnDestroy, OnInit } from '@angular/core';
import { City } from 'src/app/shared/models/city';
import { ControlValueAccessor, FormBuilder, FormControl, FormGroup, NG_VALIDATORS, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { Observable, Subscription } from 'rxjs';
import { map, startWith } from 'rxjs/operators';
export interface CityFormValues{
officeLocation : string
}
@Component({
selector: 'app-city',
templateUrl: './city.component.html',
styleUrls: ['./city.component.css'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CityComponent),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => CityComponent),
multi: true
}
],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class CityComponent implements ControlValueAccessor, OnInit, OnDestroy {
cityForm: FormGroup;
cities : City[];
selectedCity: string;
officeLocationControl = new FormControl(true,Validators.required);
filteredCities : Observable<City[]>;
subscriptions: Subscription[] = [];
get value(): CityFormValues {
return this.cityForm.value ;
}
set value(value: CityFormValues) {
this.cityForm.setValue(value);
this.onChange(value);
this.onTouched();
}
constructor(private cityService: CityService, private formBuilder: FormBuilder) {
this.cityForm = this.formBuilder.group({
officeLocation: this.officeLocationControl
});
this.subscriptions.push(
this.cityForm.valueChanges.subscribe(value => {
this.onChange(value);
this.onTouched();
})
);
}
ngOnInit(): void {
this.cityService.getAllCities().subscribe(p => { this.cities = p;
this.filteredCities = this.officeLocationControl.valueChanges.pipe(
startWith(''),
map(value => this._filter(value))
)
}
);
}
ngOnDestroy() {
this.subscriptions.forEach(s => s.unsubscribe());
}
onChange: any = () => {};
onTouched: any = () => {};
registerOnChange(fn) {
this.onChange = fn;
}
writeValue(value) {
if (value) {
this.value = value;
}
if (value === null) {
this.cityForm.reset();
}
}
registerOnTouched(fn) {
this.onTouched = fn;
}
validate(_: FormControl) {
return this.cityForm.valid ? null : { profile: { valid: false } };
}
private _filter(value: string): City[] {
const filterValue = value.toLowerCase();
return this.cities.filter(city => city.name.toLowerCase().includes(filterValue));
}
}
这是父表单控件html:
<form style="width: 100%;" [formGroup]="clientProfileForm" (ngSubmit)="submit()">
<div class="wrapper">
<div class="one" fxLayout="row" fxLayoutAlign="start start" >
<mat-card style="height: auto; width: 100%; margin: 1%; ">
<div class="component-wrapper">
<app-city formControlName="officeLocation"></app-city>
</div>
</mat-card>
</div>
<mat-divider class="three" ></mat-divider>
<div class="three" fxLayout="row" fxLayoutAlign="end center">
<button type="submit" style="width: 10%;" mat-stroked-button i18n="@@clientProfileFormNextButton" color="primary">Next</button>
</div>
</div>
</form>
<p *ngIf="showValidationError">
Form is {{clientProfileForm.valid ? 'Valid' : 'Invalid'}}
</p>
和 ts 文件:
import { ClientService } from './../../services/client.service';
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector: 'app-client-form',
templateUrl: './client-form.component.html',
styleUrls: ['./client-form.component.css']
})
export class ClientFormComponent implements OnInit {
clientProfileForm: FormGroup;
showValidationError = false;
constructor(private formbuilder: FormBuilder, private clientService: ClientService) {
this.clientProfileForm = this.formbuilder.group({
officeLocation:[]
});
}
ngOnInit(): void {
}
submit() {
if(this.clientProfileForm.valid){
this.clientService.postClient(this.clientProfileForm.value);
}else{
this.showValidationError = true;
this.clientProfileForm.get("officeLocation").updateValueAndValidity();
this.clientProfileForm.get("officeLocation").markAsTouched();
}
}
}
我想如果我将组件设置为已触摸(我相信这不是一个好的解决方案)它可能会起作用,但它也不起作用。
this.clientProfileForm.get("officeLocation").updateValueAndValidity();
this.clientProfileForm.get("officeLocation").markAsTouched();
当我单击下一步按钮提交表单时,未显示错误消息:
请问有什么想法吗?