如何在 AngularJS 表单中嵌套 Angular 2+ 表单?

Posted

技术标签:

【中文标题】如何在 AngularJS 表单中嵌套 Angular 2+ 表单?【英文标题】:How can I nest an Angular 2+ form inside an AngularJS form? 【发布时间】: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 怎么样? 【参考方案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
    

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

【讨论】:

以上是关于如何在 AngularJS 表单中嵌套 Angular 2+ 表单?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 AngularJS 中收听 jQuery 事件

构建混合 angular/angularjs 应用程序 - 如何在 angularjs 应用程序中加载 Angular 模块

我如何在 angularjs 中显示子嵌套评论

列表中的项目数过滤 AngularJS

如何在嵌套的Json中使用angularjs进行过滤

如何在 AngularJS 中设置嵌套视图?