我尝试将材料步进器(https://material.angular.io/components/stepper/overview)与嵌套可重用形式(https://coryrylan.com/blog/building-reusable-forms-in-angular)一起使用。在为嵌套表单构建异步验证器之前,它工作得很好:尽管表单有效,但stepper不会继续进行下一步。 我相信问题来自“ NG_VALIDATORS”,嵌套表单使用它来将验证器信息传输到父表单,正如文档所说:“ InjectionToken用于注册与AbstractControls一起使用的其他同步验证器。”我尝试改用NG_ASYNC_VALIDATORS,但我真的不知道它是如何工作的。我需要帮助。
代码如下:
import {Component, EventEmitter, forwardRef, OnDestroy, OnInit, Output} from '@angular/core';
import {
ControlValueAccessor,
NG_VALUE_ACCESSOR,
FormBuilder,
FormGroup,
Validators,
FormControl,
NG_VALIDATORS,
NG_ASYNC_VALIDATORS, ValidationErrors
} from '@angular/forms';
import {BehaviorSubject, Observable, of, Subscription} from 'rxjs';
import { ValidationService } from '../../validators/validation.service';
import { FirestoreService } from '../../../services/firestore/firestore.service';
import {map, startWith} from 'rxjs/operators';
export interface CustomerFormValues {
firstName: string;
lastName: string;
email: string;
phone: number;
code: string;
}
@Component({
selector: 'app-customer-form',
templateUrl: './customer-form.component.html',
styleUrls: ['./customer-form.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CustomerFormComponent),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => CustomerFormComponent),
multi: true,
},
{
provide: NG_ASYNC_VALIDATORS,
useExisting: forwardRef(() => CustomerFormComponent),
multi: true,
}
]
})
export class CustomerFormComponent implements ControlValueAccessor, OnDestroy, OnInit {
form: FormGroup;
subscriptions: Subscription[] = [];
customers = [];
customerFilteredOptions: Observable<Array<any>>;
onCreateCustomer$ = new BehaviorSubject<boolean>(false);
isReadOnly = false;
isCodeReadOnly = false;
get value(): CustomerFormValues {
return this.form.getRawValue();
}
set value(value: CustomerFormValues) {
this.form.setValue(value);
this.onChange(value);
this.onTouched();
}
get customerControl() {
return this.form.controls.customer;
}
get firstNameControl() {
return this.form.controls.firstName;
}
get lastNameControl() {
return this.form.controls.lastName;
}
get emailControl() {
return this.form.controls.email;
}
get phoneControl() {
return this.form.controls.phone;
}
get codeControl() {
return this.form.controls.code;
}
constructor(private formBuilder: FormBuilder,
public validationService: ValidationService,
private firestoreservice: FirestoreService) {
this.firestoreservice.Customers$.subscribe(data => {
this.customers = data;
});
this.form = this.formBuilder.group({
firstName: ['', Validators.required],
lastName: ['', Validators.required],
email: ['', Validators.compose([Validators.email, Validators.required])],
customer: [''],
phone: ['', Validators.compose([Validators.maxLength(10), Validators.minLength(10), Validators.required])],
code: ['', [Validators.required], [ValidationService.checkCustomerCodeExist(this.firestoreservice.Customers$,
this.onCreateCustomer$)]]
});
this.subscriptions.push(
this.form.valueChanges.subscribe(value => {
this.onChange(value);
this.onTouched();
})
);
}
ngOnInit(): void {
this.customerFilteredOptions = this.customerControl.valueChanges
.pipe(
startWith(''),
map(value => this._customerFilter(value))
);
}
ngOnDestroy() {
this.subscriptions.forEach(s => s.unsubscribe());
}
private _customerFilter(myCustomers): Array<any> {
console.log('_customerFilter');
if (myCustomers) {
const filterValue = myCustomers.toLowerCase();
return this.customers.filter(customer => customer.nom.toLowerCase().includes(filterValue)
|| customer.prenom.toLowerCase().includes(filterValue)
|| customer.email.toLowerCase().includes(filterValue)
|| customer.telephone.toLowerCase().includes(filterValue)
|| customer.code.toLowerCase().includes(filterValue)
);
}
}
onCustomerOptionSelected(mycode) {
console.log('onCustomerOptionSelected');
console.log(mycode);
if (mycode !== '') {
this.onCreateCustomer$.next(false);
console.log('onCustomerOptionSelected');
this.disableCustomerForm();
this.onCreateCustomer$.next(false);
const selectedCustomer = this.customers.filter(customer => customer.email === mycode);
console.log(selectedCustomer[0].code);
this.customerControl.setValue('');
this.firstNameControl.setValue(selectedCustomer[0].nom);
this.lastNameControl.setValue(selectedCustomer[0].prenom);
this.emailControl.setValue(selectedCustomer[0].email);
this.phoneControl.setValue(selectedCustomer[0].telephone);
this.codeControl.setValue(selectedCustomer[0].code);
}
}
disableCustomerForm() {
this.isReadOnly = true;
this.isCodeReadOnly = true;
}
enableCustomerForm() {
this.isReadOnly = false;
this.isCodeReadOnly = false;
}
onAddCustomer() {
console.log('onAddCustomer');
this.onCreateCustomer$.next(true);
this.form.reset();
this.enableCustomerForm();
}
onEditCustomer() {
console.log('onEditCustomer');
this.onCreateCustomer$.subscribe(val => {
console.log('onEditCustomer val : ', val);
if (!val) {
this.enableCustomerForm();
this.isCodeReadOnly = true;
}
})
.unsubscribe();
}
onChange: any = () => {};
onTouched: any = () => {};
registerOnChange(fn) {
this.onChange = fn;
}
writeValue(value) {
if (value) {
this.value = value;
}
}
registerOnTouched(fn) {
this.onTouched = fn;
}
validate(_: FormControl): Observable<ValidationErrors | null> {
return of(this.form.valid ? null : { profile: { valid: false, }, });
}
}
import {Component, OnInit} from '@angular/core';
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
@Component({
selector: 'app-stepper',
templateUrl: './workshop-stepper.component.html',
styleUrls: ['./workshop-stepper.component.scss']
})
export class WorkshopStepperComponent {
isLinear = true;
step1Form: FormGroup;
step2Form: FormGroup;
step3Form: FormGroup;
step4Form: FormGroup;
step5Form: FormGroup;
step6Form: FormGroup;
constructor(private formBuilder: FormBuilder) {
this.step1Form = this.formBuilder.group({
customer: []
});
this.step2Form = this.formBuilder.group({
device: []
});
}
}
<div class="container-fluid content-wrapper">
<h1 class="page-title">Prise en charge matériel en atelier</h1>
<mat-horizontal-stepper [linear]="isLinear" #stepper style="background-color: #F9F9FA">
<mat-step [stepControl]="step1Form">
<form [formGroup]="step1Form">
<ng-template matStepLabel>Client</ng-template>
<app-customer-form formControlName="customer"></app-customer-form>
</form>
</mat-step>
<mat-step [stepControl]="step2Form">
<ng-template matStepLabel>Matériel</ng-template>
<form [formGroup]="step2Form">
<app-device-form formControlName="device" [customer]="step1Form.value"></app-device-form>
</form>
</mat-step>
<mat-step [stepControl]="step3Form">
<ng-template matStepLabel>Photos</ng-template>
</mat-step>
<mat-step [stepControl]="step4Form">
<ng-template matStepLabel>Prestations</ng-template>
</mat-step>
<mat-step [stepControl]="step5Form">
<ng-template matStepLabel>Validation</ng-template>
</mat-step>
</mat-horizontal-stepper>
</div>
答案 0 :(得分:0)
对于那些被打扰的人来说,问题在于validate()函数没有等待“代码”输入的异步验证。因此,返回总是“无效”。我不得不修改validate()函数:
validate(_: FormControl) {
return this.form.valid ? null : { profile: { valid: false, }, };
}
收件人:
validate(_: FormControl) {
if (this.codeControl.pending) {
console.log('validate customer : pending');
setTimeout(() => {
this.validate(_);
}, 100);
} else {
console.log('validate customer : ', this.form.valid);
return this.form.valid ? null : { profile: { valid: false, }, };
}
}