【问题标题】:How can I nest an Angular 2+ form inside an AngularJS form?如何在 AngularJS 表单中嵌套 Angular 2+ 表单?
【发布时间】:2020-08-06 18:05:54
【问题描述】:

我正在努力将一个大型 AngularJS 应用程序升级到 Angular 5+。这意味着在混合 AngularJS 应用程序中使用新的 Angular 5 组件。在许多情况下,表单嵌套在其他表单中。旧的 AngularJS 代码有这样的父表单:

export default function PersonDirective() {
    return {
        restrict: "E",
        template: `
              <div ng-form="personForm">
                <input type="text" name="surname" ng-model="person.surname" ng-required="true">
                <address-form address="person.homeAddress"></address-form>
              </div>`,
        replace: true,
        scope: {
            person: "="
        }
    };
}

和子窗体类似:

export default function AddressDirective() {
    return {
        restrict: "E",
        template: `
           <div ng-form="addressForm">
             <input type="text" name="firstLine" ng-model="address.firstLine" ng-required="true">
             <input type="text" name="city" ng-model="address.city" ng-required="true">
           </div>`,
        replace: true,
        scope: {
            address: "="
        }
    };
}

这会为 PersonDirective 生成​​一个 FormController,它的地址表单是一个名为 addressForm 的嵌套 FormController 字段。子表单中的验证错误会影响父表单的有效性。

我已将地址表单转换为 Angular 5 组件,将 AngularJS ng-formng-required 指令替换为标准 HTML:

@Component({
    selector: 'address-form',
    template: `
          <div>
            <form #addressForm="ngForm">
              <input type="text" name="firstLine" [(ngModel)]="address.firstLine" required>
              <input type="text" name="city" [(ngModel)]="address.city" required>
           </div>`
})
export class AddressFormComponent {
    @Input() address: any;
}

新组件在index.ts 中降级以在AngularJS 中使用:

angular.module('common')
 .directive("ng2AddressForm", downgradeComponent({component: AddressFormComponent}));

以及修改为使用新组件的 PersonDirective 模板:

<div ng-form="personForm">
  <input type="text" name="surname" ng-model="person.surname" ng-required="true">
  <ng2-address-form address="person.homeAddress"></ng2-address-form>
</div>

新组件按预期显示和验证。问题是它不再作为字段出现在父表单中,其有效性和状态也不再传播给父表单。一次转换所有表格是不可能的。任何人都可以提出解决方案吗?

【问题讨论】:

  • 在这个过程中使用 Angular Elements 怎么样?

标签: angularjs angular angular-hybrid


【解决方案1】:

我找到的最佳解决方案是创建一个实现 ControlValueAccessor 和 Validator 的子组件。 ControlValueAccessor 允许使用新 Angular 2+ 模板中的 [(ngModel)] 和旧 AngularJS 模板中的 ng-model 将组件绑定到任意对象(上面示例中的地址)。

在新模板中,子组件的有效性状态会自动影响父表单的有效性。在 AngularJS 中,我不得不使用事件处理程序向父级报告子级状态。所以关系看起来是这样的:

在 AngularJS 父表单模板中:

<ng2-address-form 
    ng-model="myCtrl.person.homeAddress" 
    (status)="myCtrl.onAddressStatus($event)">
</ng2-address-form>

在 Angular 2+ 组件中:

export class AddressFormComponent implements ControlValueAccessor, Validator   {
    @Output("status") statusEvent = new EventEmitter<ValidationErrors | null>();
    addressForm: FormGroup;
...
        this.addressForm.statusChanges.subscribe(s => this.statusEvent.emit(this.validate(null)));
...
    validate(c: AbstractControl): ValidationErrors | null {
         // validate the form
    }

我发现使用响应式表单更容易,因为它使组件逻辑可以直接访问表单控件。

【讨论】:

    猜你喜欢
    • 2016-10-23
    • 2013-03-09
    • 1970-01-01
    • 2018-02-21
    • 2019-02-08
    • 2016-10-12
    • 1970-01-01
    • 1970-01-01
    • 2017-08-04
    相关资源
    最近更新 更多