我有以下代码尝试使用一些验证样式ng-class.
<tr ng-repeat="item in items">
<td>
<select name="itemName{{$index}}" ng-model="item.name" ng-options="o for o in nameOptions"
ng-class="{ 'custom-error': myForm.itemName{{$index}}.$invalid && !myForm.itemName{{$index}}.$pristine }"
required>
<option value="">SELECT</option>
</select>
</td>
</tr>
Run Code Online (Sandbox Code Playgroud)
我的班级没有申请,我不明白为什么.生成的html看起来与预期的一样,名称与ng-class表达式中的对应项匹配.
当我在一个ng-repeat(不$index用于命名)之外复制它时,它按预期工作.
发生这种情况是因为控件的名称(在其父表单上注册的名称)在ngModelController实例化期间被检索,根据文档在预链接阶段*之前发生(因此还没有插值).
如果你检查了它myForm的属性,你会发现它确实有一个带有键"itemName {{$ index}}"的属性.
*更新
文档$compile是一个很好的资源,用于理解指令的内容以及"幕后"的内容.
简而言之,有两个主要阶段:编译阶段和链接阶段.
在编译阶段,正在准备模板(例如,它可能需要克隆等)并使其成为Angular-aware(例如,编译指令并解析表达式并准备好进行评估),但它不受约束范围(因此无需评估).
编译函数处理转换模板DOM.由于大多数指令不进行模板转换,因此不经常使用.需要编译函数的示例是转换模板DOM的指令,例如ngRepeat,或者异步加载内容,例如ngView.
的连接相被进一步分为两个子阶段:预连接和联交.
在此阶段,范围开始起作用,name可以根据范围的属性/函数评估插值表达式(例如属性).
link函数负责注册DOM侦听器以及更新DOM.它在克隆模板后执行.这是大多数指令逻辑的用武之地.
预链接功能
在链接子元素之前执行.由于编译器链接功能无法找到正确的链接元素,因此进行DOM转换是不安全的.链接后功能链接 子元素后执行.在链接后功能中进行DOM转换是安全的.
所以,在你的情况下,这是发生的事情:
该ngModel指令负责在其父表单上注册元素FormController,并formCtrl.$addControl(modelCtrl);在其后链接函数中调用.
在FormController使用指定的控制器的$name性能注册控件:
form[control.$name] = control;
在ngModel控制器是一个实例的情况下ngModelCntroller,它的$name属性定义如下:
function(..., $attr, ...) { ... this.$name = $attr.name;
由于控制器在预链接阶段之前被实例化,$attr.name因此绑定到非插值字符串(即"itemName {{$ index}}").
更新2
既然我们知道问题是什么,那么继续修复它似乎是合乎逻辑的:)
这是一个可以解决问题的实现:
不要设置name属性,因此没有注册任何内容myForm(我们将负责手动注册).
创建一个指令,FormController只有在根据元素的作用域计算表达式后才能使用父表单注册控件(让我们调用指令later-name).
由于控件是FormController通过它们注册的ngModelController,因此我们的指令必须能够访问这两个控制器(通过其require属性).
注册控制之前,我们的指令将更新ngModelController的$name属性(在元素上设置的名称).
我们的指令还必须"手动"删除控件(因为我们手动添加它).
非常简单:
<select later-name="itemName{{$index}}" <!-- (1) -->
app.directive('laterName', function () { // (2)
return {
restrict: 'A',
require: ['?ngModel', '^?form'], // (3)
link: function postLink(scope, elem, attrs, ctrls) {
attrs.$set('name', attrs.laterName);
var modelCtrl = ctrls[0]; // (3)
var formCtrl = ctrls[1]; // (3)
if (modelCtrl && formCtrl) {
modelCtrl.$name = attrs.name; // (4)
formCtrl.$addControl(modelCtrl); // (2)
scope.$on('$destroy', function () {
formCtrl.$removeControl(modelCtrl); // (5)
});
}
}
};
});
Run Code Online (Sandbox Code Playgroud)
另见这个简短的演示.
| 归档时间: |
|
| 查看次数: |
1239 次 |
| 最近记录: |