【问题标题】:connecting a custom form control to its parent form validation in angular 2以角度 2 将自定义表单控件连接到其父表单验证
【发布时间】:2026-01-16 13:25:01
【问题描述】:

我最近尝试使用 Angular 2 创建自己的自定义表单控件。 自定义控件应该有 2 个输入,并编辑具有已知结构的现有对象。例如:

class model {
    public fieldOne: number;
    public fieldSec: number;
}

我遵循了在这里找到的很好的解释: Guide For Writing custom form controls

一切正常,只是指南没有提到我如何连接 自定义控件表单验证到使用它的表单。 让我们看一个简化的例子:

自定义控件模板看起来像这样:

<form>
    <input [(ngModel)]="existingModel.fieldOne">
    <input [(ngModel)]="existingModel.fieldSec" required>
</form>

我们使用它来编辑现有模型,其值为:

{
    fieldOne: 20,
    fieldSec: undefined
}

我们在我的应用程序中以某种形式使用它,我们需要自定义控件来编辑这个模型:

<form #formVar="ngForm">
    <my-custom-control [(ngModel)]="existingModel" required>
    </my-custom-control>
</form>

这种示例适用于我的应用程序,因为我可以编辑模型。 问题是我想在表单无效时向用户显示,如果我查看 formVar.valid 它将是正确的,即使 existingModel.fieldSec 未定义并且它在自定义控件表单中对其进行了必需的验证。

【问题讨论】:

    标签: angular angular2-template angular2-forms html-validation angular2-components


    【解决方案1】:

    我不确切知道您的自定义控件的行为方式,但即使您正在动态编译组件本身,以下解决方案也是有效的。

    即使在模板驱动表单的场景中(比如你的),底层引擎仍然可以通过利用响应式组件(FormGroupFormControl)来工作。因此,您始终可以以编程方式更改组和子控件的层次结构,以按预期传播更改。 您可以 - 例如 - 为您的自定义控件公开一个属性,接受 NgForm:

    @Input('form') peerForm : NgForm;
    @Input('entity') model : any;
    

    然后在你的视图中设置绑定:

    <form #formVar="ngForm">
    <my-custom-control [entity]="existingModel" [form]="formVar">
    </my-custom-control></form>
    

    您的组件模板应如下所示:

    <div>
    <input [(ngModel)]="model.fieldOne" #ctrl1="ngModel">
    <input [(ngModel)]="model.fieldSec" required #ctrl2="ngModel">
    </div>
    

    并且,再次在您的组件代码中:

    @ViewChild('ctrl1') ngModel1 : NgModel;
    @ViewChild('ctrl2') ngModel2 : NgModel;
    ...
    ngAfterViewInit(){
        // assuming the form does exist (TODO: check if set here)
        this.peerForm.control.addControl('entity_fieldOne', this.ngModel1.control);
        this.peerForm.control.addControl('entity_fieldSec', this.ngModel2.control);
    }
    

    应该够了。在此处查看 Plunker:https://plnkr.co/gb3XroZNoGuZa05e76X0

    【讨论】:

    • 这就是最初解决它的方式。我没有提到它,因为我觉得它太麻烦了,并且觉得应该有更多的内置解决方案来处理这样一个常见的用例
    • 谢谢。花了好几个小时试图找出如何做到这一点!
    • 所以还没有内置的解决方案吗?