将表单传递给 AngularJS 组件进行验证

Posted

技术标签:

【中文标题】将表单传递给 AngularJS 组件进行验证【英文标题】:Passing form to AngularJS component for validation 【发布时间】:2016-08-27 03:14:57 【问题描述】:

我正在将我的旧代码库迁移到使用 AngularJS 1.5 推广的新组件架构中。我在为较大的表单执行此操作时遇到了一个问题。传统上,我会按如下方式附加表单验证:

<form name="myForm">
  <input type="text" name="input1" ng-model="vm.input1" required />
  <div ng-messages="myForm.input1.$error">
    <div ng-message="required">Please fill out this field.</div>
  </div>
  <!-- many more inputs -->
</form>

当过渡到组件架构时,我必须明确地将表单传递给组件:

<form name="vm.myForm">
  <my-awesome-input-component model="vm.input1" form="vm.myForm"><my-awesome-input-component>
  <!-- many more inputs -->
</form>

我想避免用我的表单污染vm。有没有更好的方法来实现表单所需的组件架构?

【问题讨论】:

您不需要污染您的视图模型,表单名称纯粹是表单控制器的名称,您可以将其传递给您的输入组件。您的视图模型应该只需要担心输入值。 【参考方案1】:

实际上,您不需要传递表单父级来执行此操作。在你的 awesome-component 的模板中添加一个 ng-form 标签,然后使用它:

组件的模板:

<ng-form name="myComponentForm">
    <input type="number" ng-model="$ctrl.myModel" name="myField"/>
    <span ng-show="myComponentForm.myField.$invalid">There's an error</span>
</ng-form>

这就是ngForm指令的意思,指令和组件中有子表单对表单字段的子组进行验证。

【讨论】:

【参考方案2】:

这是另一种可能对某些人有用的方法。使用require 将父form 包含在您的$ctrl 中:

angular.module("myApp")
    .component("myInput",
        templateUrl:'path/to/template.html'
        bindings:
            myInputModel:'<',
            onUpdate:'&'
        ,
        controller: MyInputController,
        require: 
            form: '^form'
        

在输入模板中:

<input type="text" name="myInput" ng-model="$ctrl.myInputModel" ng-change="$ctrl.update($ctrl.myInputModel)" required />
    <div ng-messages="$ctrl.form.myInput.$error">
    <div ng-message="required">Please fill out this field.</div>
</div>

无需将表单显式传递到您的组件中,因为form 会自动添加到您的$ctrl

<form name="myForm" ng-submit="ctrl.someFunction()" novalidate>
    <my-input my-input-model="ctrl.anyModelIWant" on-update="ctrl.updateMyInput(value)"></my-input>
    <button type="submit">Some button</button>
</form>

我猜从技术上讲,你仍然在污染你的虚拟机,但至少你不必在整个层次结构中明确地传递它。

添加文本以满足 6 个字符的编辑要求,将句点更改为逗号以更正示例。对于新人来说,时期是令人困惑的。

【讨论】:

【参考方案3】:

更新 - 将 form-name 更改为 form-reference,因为我们传递实际的表单引用而不只是名称表格。这可以随心所欲地调用,只是要清楚它实际上是什么。

正如 Iain Reid 所说,您不需要为此使用 vm。您只需将表单命名为您想要的任何名称,然后将该名称传递给您的组件,因此它看起来像这样:

<form name="myForm" ng-submit="ctrl.someFunction()" novalidate>
   <my-input form-reference="myForm"></my-input>
   <button type="submit">Some button</button>
</form>

如果您想自己处理验证(我认为您可以使用 ng-messages),请确保您在表单中编写“novalidate”以禁用默认浏览器验证。

然后从那里,在我的组件上我会写如下内容:

angular.module("myApp")
  .component("myInput",
     templateUrl:'path/to/template.html'
     bindings:
       formReference:'<',
       myInputModel:'<',
       onUpdate:'&'
     ,
     controller: MyInputController
  

然后在输入模板中:

<input type="text" name="myInput" ng-model="$ctrl.myInputModel" ng-change="$ctrl.update($ctrl.myInputModel)" required />
<div ng-messages="$ctrl.formReference.myInput.$error">
  <div ng-message="required">Please fill out this field.</div>
</div>

关于绑定以及如何传递和更新模型的一些额外说明:

' :表示一种方式绑定,Angular 说它适用于所有人 组件从现在开始。为了更新值并有两种方式 绑定,我们需要包含一个“onUpdate”函数。 onUpdate : '&' 我在这里说的是我将通过一个 更新模型的函数(组件事件的回调)。

所以在输入控制器中我会写如下内容:

function MyInputController()
    var ctrl = this;
    ctrl.update = function(value)
        ctrl.onUpdate(value: value);
    ;

最后,当我在表单中使用我的组件时:

<form name="myForm" ng-submit="ctrl.someFunction()" novalidate>
   <my-input form-reference="myForm" my-input-model="ctrl.anyModelIWant" on-update="ctrl.updateMyInput(value)"></my-input>
   <button type="submit">Some button</button>
</form>

并且表单的控制器会有一个功能:

...
ctrl.updateMyInput = function(value)
   ctrl.anyModelIWant = value;

...

官方文档:https://docs.angularjs.org/guide/component

我希望所有这些都能帮助到那里的人:-)

【讨论】:

很好的例子,但有一件事可能令人困惑——在你给出的例子中,你没有将表单名称(“myForm”)绑定到组件——你将实际引用绑定到表格。不过,它的效果很好,但一开始确实让我有些困惑。

以上是关于将表单传递给 AngularJS 组件进行验证的主要内容,如果未能解决你的问题,请参考以下文章

将 AngularJS 数组传递给降级的 Angular 7 组件

angularJS 表单验证

AngularJS - 将值传递给组件

angularjs组件控制器未将初始绑定值传递给模板中的指令(summernote)

将表单与原始输入传递给服务层

将 AngularJs 控制器的令牌传递给 Laravel API