angular - 如何使异步数据以 Angular 动态形式模式工作

标签 angular typescript angular-forms

我在 Angular 中使用我们拥有的各种表单的动态表单模式。这对我们来说是一种方便的方法,因为我们只需要在 ngOnInit 中定义我们的控件,它将动态构建我们需要的表单。然而,有一些形式的值必须被初始化,并且一些值可以使用 async/await 来检索。

这是动态表单的问题,因为当我初始化异步数据时,它会在控制台上抛出错误,并且表单不会显示在 View 中。

我尝试在 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;
}

我还在 View 上添加了一个异步管道:

<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>

但是,这不起作用。

详情请看截图。 enter image description here

附加代码:

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() 方法填充表单控件。对于用户来说,差异甚至不明显,但在我看来,这是一种更可靠的预填充表单方法。例如,您可以通过以下方式预填充用户 Angular 色编辑表单的“用户 Angular 色名称”:

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

关于angular - 如何使异步数据以 Angular 动态形式模式工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45282918/

相关文章:

带有数据的 Angular 嵌套组件

typescript - 如何在 Typescript 库项目中生成子模块?

reactjs - Ref 对象可能是未定义的 TypeScript React

angular - 只读/禁用输入未在 Angular 中提交

angular - *ngFor 内的 mat-datepicker

angular - 选择错误 SQLITE.ALL - 准备错误 1

angular - 如何在 Angular 中添加顶级路由器导出

angular - 如何从 Angular Material `mat-menu`中获取所选项目

javascript - 语法错误: Unexpected token { when trying to run protractor test

angular - 根据其他表单控件更新 Angular Reactive Form 禁用字段的值