我正在尝试从后端的用户表中获取布尔值 isCompany 和字符串 companyName 和 nip 等数据,并将其设置为表单字段中的默认值。所有其他数据均已正确修补。只有这些有问题。
数据已正确获取并且存在于数据库中。问题是我收到此
create-order.component.html:14 ERROR TypeError: Cannot read properties of undefined (reading 'companyForm')
错误,并且这些字段在表单中保持为空。
这就是我在
form.service.ts
中初始化表单的方式:
initCompanyForm(): FormGroup {
return new FormGroup({
companyName: new FormControl('', {}),
nip: new FormControl('', {
validators: [Validators.pattern(/^\d{10}$/)]
})
});
}
这是
company-form.component.ts
:
export class CompanyFormComponent {
companyForm: FormGroup;
constructor(private formService: FormService) {
this.companyForm = this.formService.initCompanyForm();
}
get controls() {
return this.companyForm.controls as { [key: string]: FormControl };
}
getErrorMessage(control: FormControl): string {
return this.formService.getErrorMessage(control);
}
}
这个 Angular 组件
create-order.component
管理一个多步骤订单表单,其中包含客户、地址、交货、公司和其他信息的子组件。出现此问题的原因是,当 fetchUserProfile() 尝试修补其表单值时,CompanyFormComponent 未完全初始化,从而导致未定义的错误。即使使用 ngAfterViewInit,配置文件获取 (profileService.getUserProfile()) 的异步性质也会导致时间不匹配。我猜问题是配置文件数据在 CompanyFormComponent 准备好之前到达。
export class CreateOrderComponent implements OnInit, AfterViewInit {
errorMsg: null | string = null;
saveShipping = false;
isAuthenticated = false;
isCompany = false;
@ViewChild(CustomerFormComponent) customerFormComp!: CustomerFormComponent;
@ViewChild(AddressFormComponent) addressFormComp!: AddressFormComponent;
@ViewChild(DeliveryFormComponent) deliveryFormComp!: DeliveryFormComponent;
@ViewChild(CompanyFormComponent) companyFormComp!: CompanyFormComponent;
@ViewChild(InfoFormComponent) infoFormComp!: InfoFormComponent;
constructor(
private location: Location,
private router: Router,
private ordersService: OrdersService,
private profileService: ProfileService,
private authService: AuthService
) {}
ngOnInit(): void {
const locationState = this.location.getState() as {
summaryPrice: undefined | number;
navigationId: number;
};
if (!locationState.summaryPrice) {
this.router.navigate(['']);
}
this.checkIfUserIsLoggedIn();
}
ngAfterViewInit(): void {
if (this.isAuthenticated) {
this.fetchUserProfile();
}
}
checkIfUserIsLoggedIn(): void {
this.authService.isLoggedIn().subscribe({
next: (response) => {
this.isAuthenticated = response.message;
if (this.isAuthenticated) {
this.fetchUserProfile();
}
},
error: (err) => {
this.isAuthenticated = false;
console.error('Error checking login status:', err);
}
});
}
fetchUserProfile(): void {
this.profileService.getUserProfile().subscribe({
next: (profile) => {
console.log('User profile:', profile);
this.customerFormComp.customerForm.patchValue({
firstName: profile.firstName || '',
lastName: profile.lastName || '',
email: profile.email || ''
});
if (profile.phone) {
this.customerFormComp.controls.phone.setValue(profile.phone);
}
this.addressFormComp.addressForm.patchValue({
city: profile.city || '',
street: profile.street || '',
number: profile.number || '',
postCode: profile.postCode || ''
});
if (profile.company) {
this.isCompany = true;
if (this.companyFormComp?.companyForm) { // this if omits the error, but doesn't solve the problem
console.log('Patching company form with:', {
companyName: profile.companyName,
nip: profile.nip
});
this.companyFormComp.companyForm.enable();
this.companyFormComp.companyForm.patchValue({
companyName: profile.companyName || '',
nip: profile.nip || ''
});
}
} else {
this.isCompany = false;
if (this.companyFormComp?.companyForm) {
this.companyFormComp.companyForm.reset();
this.companyFormComp.companyForm.disable();
}
}
},
error: (err) => {
this.errorMsg = 'Nie udało się załadować danych użytkownika';
console.error('Error fetching user profile:', err);
}
});
}
onCompanyChange(): void {
console.log('Checkbox changed:', this.isCompany);
if (this.isCompany) {
console.log('Enabling company fields...');
this.companyFormComp.companyForm.enable();
} else {
console.log('Disabling and resetting company fields...');
this.companyFormComp.companyForm.reset();
this.companyFormComp.companyForm.disable();
}
}
order(): void {
if (
this.customerFormComp.customerForm.valid &&
this.addressFormComp.addressForm.valid &&
this.deliveryFormComp.deliveryForm.valid &&
(!this.isCompany || this.companyFormComp.companyForm.valid)
) {
const orderData = {
address: this.addressFormComp.addressForm.getRawValue(),
deliver: this.deliveryFormComp.deliveryForm.getRawValue(),
customerDetails: this.customerFormComp.customerForm.getRawValue(),
isCompany: this.isCompany,
companyName: this.isCompany
? this.companyFormComp.companyForm.get('companyName')?.value
: null,
nip: this.isCompany
? this.companyFormComp.companyForm.get('nip')?.value
: null,
info: this.infoFormComp.infoForm.get('info')?.value || null
};
console.log(
'Order data being sent to backend:',
JSON.stringify(orderData, null, 2)
);
this.ordersService.addOrder(orderData).subscribe({
next: () => {
if (this.saveShipping && this.isAuthenticated) {
this.saveShippingDetails(orderData.address);
}
},
error: (err) => {
this.errorMsg = err;
console.error('Order submission error:', err);
}
});
} else {
console.warn('Form is invalid');
}
}
所有表单组件都在
create-order.component
中。
我猜
onCompanyChange
方法会在视图子项可用之前触发。仅当 companyFormComp
视图子级存在时,您才可以更改触发重置的方法。
onCompanyChange(): void {
console.log('Checkbox changed:', this.isCompany);
if(this.companyFormComp?.companyForm) {
if (this.isCompany) {
console.log('Enabling company fields...');
this.companyFormComp.companyForm.enable();
} else {
console.log('Disabling and resetting company fields...');
this.companyFormComp.companyForm.reset();
this.companyFormComp.companyForm.disable();
}
}
}