angular 如何使异步数据与动态表单模式一起工作

How to make async data work with dynamic form pattern in angular

我将 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。关于初始化异步数据时如何解决问题的任何建议?

如果表单元素正在等待任何异步数据,或者表单特别复杂,我通常会在表单元素上添加一个 ngIf 语句。基本上正在发生的事情,我想你已经知道了,是表单没有及时初始化以击败正在呈现到屏幕上的页面。根据具体情况,它有时可能会抛出错误,也可能不会。通过添加:

<form *ngIf="form">

您将强制 angular 等待 form 实例化。我看到的另一个问题可能是由于您在使用异步数据的表单实例化过程中预填充了表单控件。这通常不是什么好兆头。更好的方法(除非您立即手头有数据)是实例化一个空表单,然后调用以获取要放入表单中的数据。然后,使用 get()setValue() 方法填充表单控件。对于用户来说,差异甚至不明显,但在我看来,这是一种更可靠的预填充表单方法。例如,您可以通过以下方式预填充用户角色编辑表单的 "User Role Name":

一些-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);
            })
    }