Angular 开箱即用,带有一个在此处记录的改进标签。 基本上,它围绕表单和其中的所有标签创建了一个控制器形式的范围。所以你这样做:
<body ng-app="TestApp">
<form ng-controller="FormCtrl" name="testForm">
<input name="firstInput" ng-model="data.first">
<input name="secondInput" ng-model="data.second">
<button ng-click="submit()">Submit</button>
</form>
</body>
JS:
var app = angular.app('TestApp', []);
app.controller('FormCtrl', function($scope) {
$scope.submit = function() {
// Form submit logic here
console.log("Submitting the form");
console.log($scope);
}
})
这为表单创建了一个范围,因为表单标签包含 ng-controller 标签。在范围内,testForm
是表单的 javascript 对象,并且testForm.firstInput
是第一个输入的 javascript 对象。看起来这些对象也有一些可用的验证功能,请参阅此处的文档。
表单上的数据将在 FormCtrl 范围内作为对象数据提供,键为“first”和“second”,您可以在控制器中定义处理该数据的方法。
你也可以使用同一个 FormCtrl 来放置多个表单,而且看起来 Angular 会为每个表单创建新的实例,所以你不必担心表单会污染彼此的数据。
使用指令
现在让我们假设我们有某种在指令中实现的复杂输入或小部件。此示例使用两个选择框来显示一个州的所有城市。您必须首先选择一个州,然后它将查询该州的城市并填充第二个选择框。
app.directive('citySelect', function() {
return {
replace: true,
template: '<div><select ng-change="getCities()" ng-options="s.name for s in states"></select>' +
'<select ng-model="data.selectedCity" ng-options="c.name for c in cities"></select>',
controller: function($scope) {
// Omitting the logic for getCities(), but it'd go here
}
};
})
然后你可以把它粘贴到表单标签中,它就可以工作了。因为该指令没有定义范围,它只会附加到 FormCtrl 的范围。
<body ng-app="TestApp">
<form ng-controller="FormCtrl" name="testForm">
<input name="firstInput" ng-model="data.first">
<input name="secondInput" ng-model="data.second">
<div city-select></div>
<button ng-click="submit()">Submit</button>
</form>
</body>
参数化指令
编辑:
所以显然这确实有效:
scope: {someParameter: "="},
template: '<div><select ng-model="someParameter"></select></div>'
您只需在没有卷曲的情况下执行此操作,它就会绑定。我的猜测是父作用域绑定到子作用域中的 someParameter,然后 select 绑定到子作用域中的 somParameter。
所以下面关于在链接函数中手动编译的所有这些都是不必要的。
=====
但问题是我的 citySelect 指令有一个硬编码的 ng-model 绑定,所以如果我创建了某种通用小部件,我不能在一个表单中使用多个它。不幸的是,这似乎不起作用:
scope: {someParameter: "="},
template: '<div><select ng-model="{{ someParameter }}"></select></div>'
我让它工作的唯一方法是在链接函数中手动构建 DOM 元素,但我不确定这是否可取。我将感谢任何人对此实施的评论:
<body ng-app="TestApp">
<form ng-controller="FormCtrl" name="testForm">
<input name="firstInput" ng-model="data.first">
<input name="secondInput" ng-model="data.second">
<div city-select bind-to="data.homeCity"></div>
<div city-select bind-to="data.workCity"></div>
<button ng-click="submit()">Submit</button>
</form>
</body>
app.directive('citySelect', function($compile) {
return {
replace: true,
template: '<div></div>',
controller: function($scope) {
// Omitting the logic for getCities(), but it'd go here
}
link: function(scope, iElem, iAttrs) {
var html = '<div><select ng-bind="' + iAttrs['bindTo'] + '"></div>';
iElem.replaceWith($compile(html)(scope));
}
};
})
在表单上混合参数
由于为每个表单创建了单独的 FormCtrl 实例,因此您可以重用 FormCtrl 中的许多功能。但是您也可以在表单标签上使用其他指令来添加参数或拆分功能。例如:
<form ng-controller="FormCtrl" name="testForm" post-form post-path="/path/to/resource/">
app.directive('postForm', function() {
return {
controller: function($scope) {
$scope.post = function() {
// Some generic POST behavior
};
},
link: function(scope, iElem, iAttr) {
scope.postPath = iAttr['postPath'];
},
};
});
然后,表单的范围将结合 FormCtrl 和 postForm 的范围,以便可以访问所有内容。在我的实验中,似乎 FormCtrl 优先,所以如果在 FormCtrl 和 postForm 中都定义了 $scope.submit() 之类的东西,FormCtrl 将优先(我认为),也许这是异步加载的竞争条件,我不知道。
除了使用 ng-controller,我认为您还可以scope:true
在 mixin 指令 (postForm) 上使用,或者更安全地使用scope: {}
.