Как заставить асинхронные данные работать с динамическим шаблоном формы в угловых
Я использую динамический шаблон формы в Angular с различными формами, которые у нас есть. Это удобный способ для нас, так как нам нужно только определить наши элементы управления в ngOnInit
и он будет динамически строить ту форму, которая нам нужна. Однако существуют некоторые формы, в которых значения должны быть инициализированы, а некоторые значения могут быть получены с использованием async / await.
Это проблема с динамической формой, так как при инициализации асинхронных данных она выдает ошибки на консоли, а форма не отображается в представлении.
Я попытался добавить асинхронный на ngOnInit и ждать данных асинхронного. Как показывает пример кода ниже:
async ngOnInit() {
const pageUrl = await this.fooService.getTabUrl();
const security = this.barService.getSecurity();
const controls: Array<ControlBase<any>> = [
new ControlTextbox({
key: "url",
order: 0,
readonly: true,
type: "text",
value: pageUrl
}),
new ControlDropdown({
key: "security",
label: "Security",
order: 2,
options: security,
type: "dropdown",
value: security[0].id
})
];
this.controls = controls;
}
Я также добавляю асинхронный канал в представление:
<form class="{{formClass}}" (ngSubmit)="onSubmit()" [formGroup]="form" role="form">
<app-form-control *ngFor="let ctrl of controls | async" [control]="ctrl | async" [form]="form | async"></app-form-control>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-block" [disabled]="!form.valid">{{btnText}}</button>
</div>
</form>
Однако это не работает.
Для более подробной информации смотрите скриншот.
Дополнительные коды:
export class FormControlComponent implements OnInit {
@Input() public control: ControlBase<string | boolean | undefined>;
@Input() public form: FormGroup;
constructor() { }
get valid() {
return this.form.controls[this.control.key].valid;
}
get invalid() {
return !this.form.controls[this.control.key].valid && this.form.controls[this.control.key].touched;
}
ngOnInit() { }
}
export class DynamicFormComponent implements OnInit {
@Input() public controls: Array<ControlBase<any>> = [];
@Input() public btnText = "Submit";
@Output() public formSubmit: EventEmitter<any> = new EventEmitter<any>();
public form: FormGroup;
constructor(public _controlService: FormControlService) { }
ngOnInit() {
const sortedControls = this.controls.sort((a, b) => a.order - b.order);
this.form = this._controlService.toControlGroup(sortedControls);
}
onSubmit(): void {
this.formSubmit.emit(this.form.value);
}
}
export class FormControlService {
constructor() { }
public toControlGroup(controls: Array<ControlBase<any>>) {
const group: any = {};
controls.forEach(control => {
const validators: any = [];
// Required
if (control.required) {
validators.push(Validators.required);
}
// remove for brevity
group[control.key] = new FormControl(control.value || "", validators);
});
return new FormGroup(group);
}
}
Я все еще новичок и изучаю Angular. Любое предложение о том, как я буду преодолевать проблему при инициализации асинхронных данных?
1 ответ
Я, как правило, буду ngIf
оператор в элементе формы, если он ожидает каких-либо асинхронных данных или если форма особенно сложна. По сути, то, что происходит, и я думаю, что вы уже знаете это, заключается в том, что форма не инициализируется вовремя, чтобы превзойти страницу, отображаемую на экране. В зависимости от обстоятельств он может иногда выдавать ошибку, а может и нет. Добавляя:
<form *ngIf="form">
Вы заставите угловой ждать, пока form
был создан Другая проблема, которую я вижу, может быть связана с тем, что вы предварительно заполняете свои формы управления во время процесса создания формы с использованием асинхронных данных. Это обычно не сулит ничего хорошего. Лучший способ (если у вас нет данных сразу) - создать экземпляр формы emtpy с последующим вызовом для получения данных, которые вы хотите поместить в форму. Затем используйте get()
а также setValue()
методы для заполнения элементов управления формы. Для пользователя разница даже не заметна, но, на мой взгляд, это гораздо более надежный метод предварительного заполнения форм. Например, вот что вы можете сделать, чтобы предварительно заполнить "Имя роли пользователя" формы редактирования роли пользователя:
некоторые-component.component.ts
ngOnInit() {
// Instantiate your form.
buildUserRoleFormGroup();
}
buildUserRoleFormGroup() {
// INSTANTIATE YOUR FORM HERE.....
// Then populate it.
populateUserRoleForm();
}
populateUserRoleForm() {
this._UserRolesService.getUserRole(this.userRoleID)
.subscribe(_UserRole => {
// Save the data to a component property
this.userRole = _UserRole.data;
// Get the user role name form control
let userRoleName = this.createUserRoleForm.get('userRoleName')
// Set the user role name form control value
userRoleName.setValue(this.userRole.userRoleName);
},
_Error => {
console.log(_Error);
})
}