将表格传递给指令

Ema*_*mad 74 angularjs angularjs-directive

我想将我的表单字段封装在一个指令中,所以我可以简单地这样做:

<div ng-form='myForm'>
  <my-input name='Email' type='email' label='Email Address' placeholder="Enter email" ng-model='model.email' required='false'></my-input>

</div>
Run Code Online (Sandbox Code Playgroud)

如何访问myForm我的指令,以便进行验证检查,例如myForm.Email.$valid

Mar*_*cok 151

要在指令中访问FormController:

require: '^form',
Run Code Online (Sandbox Code Playgroud)

然后它将作为链接函数的第4个参数:

link: function(scope, element, attrs, formCtrl) {
    console.log(formCtrl);
}
Run Code Online (Sandbox Code Playgroud)

fiddle

您可能只需要访问NgModelController:

require: 'ngModel',
link: function(scope, element, attrs, ngModelCtrl) {
     console.log(ngModelCtrl);
}
Run Code Online (Sandbox Code Playgroud)

fiddle

如果您需要访问两者:

require: ['^form','ngModel'],
link: function(scope, element, attrs, ctrls) {
    console.log(ctrls);
}
Run Code Online (Sandbox Code Playgroud)

fiddle

  • @OverZealous,显然是当在HTML中找到`form`或`ng-form`指令时,Angular使用的指令名是`form`而不是`ngForm`.我花了几次试图弄清楚名称是`form`.我认为这是[Angular源代码](https://github.com/angular/angular.js/blob/f1b94b4b599ab701bc75b55bbbbb73c5ef329a93/src/ng/directive/form.js#L304),我们看到`form`被使用了. (9认同)
  • 如果你不介意回答,为什么这个用''^ form'而不用''^ ngForm'?我试图让它第一次工作,但它出现了"无控制器"错误.我比你的好得多. (3认同)
  • @mtpultz,把它放在你的链接函数的范围:`scope.formCtrl = formCtrl;`,然后你可以使用`$ scope`在你的控制器中访问它:`controller:function($ scope){...}` .但请注意,您的指令控制器将首先运行,因此当控制器功能首次执行时,引用将不存在. (3认同)
  • @eibrahim,Angular不支持动态表单元素名称. (2认同)

tan*_*y_k 32

这是一个完整的例子(使用Bootstrap 3.1设计)

它包含一个包含多个输入(名称,电子邮件,年龄和国家/地区)的表单.姓名,电子邮件和年龄是指令.国家是"常规"投入.

当用户未输入正确的值时,每个输入都会显示一条帮助消息.

表单包含一个保存按钮,如果表单至少包含一个错误,该按钮将被禁用.

<!-- index.html -->
<body ng-controller="AppCtrl">
  <script>
    var app = angular.module('app', []);

    app.controller('AppCtrl', function($scope) {
      $scope.person = {};
    });
  </script>
  <script src="inputName.js"></script>
  <script src="InputNameCtrl.js"></script>
  <!-- ... -->

  <form name="myForm" class="form-horizontal" novalidate>
    <div class="form-group">
      <input-name ng-model='person.name' required></input-name>
    </div>

    <!-- ... -->

    <div class="form-group">
      <div class="col-sm-offset-2 col-sm-4">
        <button class="btn btn-primary" ng-disabled="myForm.$invalid">
          <span class="glyphicon glyphicon-cloud-upload"></span> Save
        </button>
      </div>
    </div>
  </form>

  Person: <pre>{{person | json}}</pre>
  Form $error: <pre>{{myForm.$error | json}}</pre>
  <p>Is the form valid?: {{myForm.$valid}}</p>
  <p>Is name valid?: {{myForm.name.$valid}}</p>
</body>

// inputName.js
app.directive('inputName', function() {
  return {
    restrict: 'E',
    templateUrl: 'input-name.html',
    replace: false,
    controller: 'InputNameCtrl',
    require: ['^form', 'ngModel'],

    // See Isolating the Scope of a Directive http://docs.angularjs.org/guide/directive#isolating-the-scope-of-a-directive
    scope: {},

    link: function(scope, element, attrs, ctrls) {
      scope.form = ctrls[0];
      var ngModel = ctrls[1];

      if (attrs.required !== undefined) {
        // If attribute required exists
        // ng-required takes a boolean
        scope.required = true;
      }

      scope.$watch('name', function() {
        ngModel.$setViewValue(scope.name);
      });
    }
  };
});

// inputNameCtrl
app.controller('InputNameCtrl', ['$scope', function($scope) {
}]);
Run Code Online (Sandbox Code Playgroud)

带有指令的AngularJS表单

  • 这是一个很好的例子.我已经更改了你的Plunk,使你的指令更通用,因为它现在可以支持任何类型的输入,例如文本或密码或电子邮件等.请参阅此处:http://plnkr.co/edit/13rqpfrTiTwDMpCPmT7X?p = preview (2认同)

Ove*_*ous 17

编辑2:我会留下我的答案,因为它可能有其他原因,但Mark Rajcok的另一个答案是我原本想做的,但未能开始工作.显然,这里的父控制器将是form,而不是ngForm.


您可以使用指令中的属性传递它,尽管这会变得相当冗长.

这是一个有效的,简化的jsFiddle.

HTML:

<div ng-form="myForm">
    <my-input form="myForm"></my-input>
</div>
Run Code Online (Sandbox Code Playgroud)

指令的基本部分:

app.directive('myInput', function() {
    return {
        scope: {
            form: '='
        },
        link: function(scope, element, attrs) {
            console.log(scope.form);
        }
    };
});
Run Code Online (Sandbox Code Playgroud)

发生了什么

我们已经要求Angular将form属性中指定的范围值绑定到我们的隔离范围,方法是使用'='.

这样做可以将实际形式与输入指令分离.

注意:我尝试使用require: "^ngForm",但是ngForm指令没有定义控制器,也不能以这种方式使用(这太糟糕了).


所有这一切,我认为这是一个非常冗长和混乱的方式来处理这个问题.您可能最好将新指令添加到表单元素,并用于require访问该项目.我会看看能不能把东西放在一起.

编辑:使用父指令

好的,这是我可以找到的最好的父指令,我会在一秒钟内解释更多:

使用父指令工作jsFiddle

HTML:

<div ng-app="myApp">
    <div ng-form="theForm">
        <my-form form="theForm">
            <my-input></my-input>
        </my-form>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

JS(部分):

app.directive('myForm', function() {
    return {
        restrict: 'E',
        scope: {
            form: '='
        },
        controller: ['$scope', function($scope) {
            this.getForm = function() {
                return $scope.form;
            }
        }]
    }
});

app.directive('myInput', function() {
    return {
        require: '^myForm',
        link: function(scope, element, attrs, myForm) {
            console.log(myForm.getForm());
        }
    };
});
Run Code Online (Sandbox Code Playgroud)

这将表单存储在父指令scope(myForm)中,并允许子指令通过要求父表单(require: '^myForm')和访问链接函数(myForm.getForm())中的指令控制器来访问它.

优点:

  • 您只需要在一个地方识别表单
  • 您可以使用父控制器来存放公共代码

劣势:

  • 您需要一个额外的节点
  • 您需要将表单名称放入两次

我更喜欢什么

我试图使用表单元素上的属性使其工作.如果这样做,你只需要将指令添加到同一个元素中ngForm.

但是,我在范围内得到了一些奇怪的行为,其中myFormName变量将在其中可见$scope,但是undefined当我尝试访问它时.那个让我困惑的人.


Pri*_*mre 7

从AngularJS 1.5.0开始,有更清晰的解决方案(与link直接使用该功能相反).如果要访问FormController子组件的指令控制器中的表单,可以简单地require在指令上打一个属性,如下所示:

return {
  restrict : 'EA',
  require : {
    form : '^'
  },
  controller : MyDirectiveController,
  controllerAs : 'vm',
  bindToController : true,
  ...
};
Run Code Online (Sandbox Code Playgroud)

接下来,您将能够像在任何其他范围变量中一样在模板或指令控制器中访问它,例如:

function MyDirectiveController() {
  var vm = this;
  console.log('Is the form valid? - %s', vm.form.$valid);
}
Run Code Online (Sandbox Code Playgroud)

请注意,为此,您还需要bindToController: true在指令上设置属性.查看文档$compile这个问题的更多信息.

文件中的相关部分:

要求

需要另一个指令并将其控制器作为链接函数的第四个参数注入.require属性可以是字符串,数组对象:

如果require属性是一个对象并且bindToController是真实的,那么使用require属性的键将所需的控制器绑定到控制器.如果所需控制器的名称与本地名称(密钥)相同,则可以省略该名称.例如,{parentDir: '^parentDir'}相当于{parentDir: '^'}.