我想将表单字段封装在一个指令中,所以我可以这样做:
<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
?
答案 0 :(得分:149)
要在指令中访问FormController:
require: '^form',
然后它将作为链接函数的第4个参数:
link: function(scope, element, attrs, formCtrl) {
console.log(formCtrl);
}
您可能只需要访问NgModelController:
require: 'ngModel',
link: function(scope, element, attrs, ngModelCtrl) {
console.log(ngModelCtrl);
}
如果您需要访问两者:
require: ['^form','ngModel'],
link: function(scope, element, attrs, ctrls) {
console.log(ctrls);
}
答案 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) {
}]);
答案 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
bindToController
和documentation问题。
文件中的相关部分:
<强> 需要 强>
需要另一个指令并将其控制器作为链接函数的第四个参数注入。 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']];
}
}]
}
});