将表格传递给指令

时间:2013-07-12 15:18:30

标签: 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>

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

5 个答案:

答案 0 :(得分:149)

要在指令中访问FormController:

require: '^form',

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

link: function(scope, element, attrs, formCtrl) {
    console.log(formCtrl);
}

fiddle

您可能只需要访问NgModelController:

require: 'ngModel',
link: function(scope, element, attrs, ngModelCtrl) {
     console.log(ngModelCtrl);
}

fiddle

如果您需要访问两者:

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

fiddle

答案 1 :(得分:32)

这里有一个完整的example(使用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) {
}]);

AngularJS form with directives

答案 2 :(得分:17)

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


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

实施例

这是working, simplified jsFiddle

代码

HTML:

<div ng-form="myForm">
    <my-input form="myForm"></my-input>
</div>

指令的基本部分:

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

发生了什么

我们已经要求Angular使用form'='属性中指定的范围值绑定到我们的隔离范围。

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

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


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

编辑:使用父指令

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

工作jsFiddle using parent directive

HTML:

<div ng-app="myApp">
    <div ng-form="theForm">
        <my-form form="theForm">
            <my-input></my-input>
        </my-form>
    </div>
</div>

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());
        }
    };
});

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

优点:

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

否定:

  • 您需要一个额外的节点
  • 您需要将表单名称设置为两次

我更喜欢

我试图让它工作using an attribute on the form element。如果这样做,您只需将指令添加到与ngForm相同的元素。

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

答案 3 :(得分:7)

从AngularJS 1.5.0开始,有更清晰的解决方案(而不是直接使用link功能)。如果您想在子组件的指令控制器中访问表单FormController,您可以简单地在指令上打上require属性,如下所示:

return {
  restrict : 'EA',
  require : {
    form : '^'
  },
  controller : MyDirectiveController,
  controllerAs : 'vm',
  bindToController : true,
  ...
};

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

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

请注意,要使其正常工作,您还需要在指令中设置bindToController: true属性。有关详情,请参阅$compile bindToControllerdocumentation问题。

文件中的相关部分:

  

<强> 需要

     

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

     

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

答案 4 :(得分:2)

让你的'我更喜欢'小提琴工作! 出于某种原因,您可以在console.log中看到“$ scope.ngForm”字符串,但直接记录它不起作用,导致未定义。 但是,如果将属性传递给控制器​​函数,则可以获取它。

app.directive('myForm', function() {
return {
    restrict: 'A',
    controller: ['$scope','$element','$attrs', function($scope,$element,$attrs) {
        this.getForm = function() {
            return $scope[$attrs['ngForm']];
        }
    }]
}
});

http://jsfiddle.net/vZ6MD/20/