3

我正在努力将大型 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 具有地址表单作为嵌套的 FormController 字段,称为addressForm。子表单中的验证错误会影响父表单的有效性。

我已将地址表单转换为 Angular 5 组件,将 AngularJSng-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>

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

4

1 回答 1

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
    }

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

于 2020-05-29T10:46:08.840 回答