Angular自定义指令模板中tr插值生效但ng-model插值失效的原因?
我有一个名为
budgetRow的自定义指令,其templateUrl指向一个存储在文件中的模板,代码如下:<tr class="item_row" id="{{rowId}}"> <td class="item_cell" id="description"> <input type="text" ng-model='budget.row({{rowId}}).description' > </td> </tr>当
$scope.rowId设置为10时,浏览器的渲染结果如下:<budget-row> <tr class="item_row" id="10"> <td class="item_cell" id="description"> <input type="text" ng-model="budget.row({{rowId}}).description" class="ng-pristine ng-untouched ng-valid"> </td> </tr> </budget-row>请问为何
tr元素中的{{rowId}}能被插值,而input的ng-model属性中的{{rowId}}却无法被插值?
这个问题其实是AngularJS处理属性的两种不同逻辑导致的,我给你拆解明白:
普通HTML属性和Angular指令属性的处理逻辑不一样
像id="{{rowId}}"这种普通HTML属性,Angular的处理顺序是先做插值替换,再把结果渲染到DOM里。所以这里的{{rowId}}会被顺利替换成10,完全符合预期。但
ng-model是Angular的内置指令属性,它的玩法就不同了:Angular不会对指令属性里的{{}}语法做插值,而是直接把整个内容当成表达式去解析。也就是说,它会尝试执行budget.row({{rowId}}).description这个表达式,但{{rowId}}在表达式语境里是无效语法,自然就不会被替换,原封不动保留了下来。正确的写法应该是这样的
在ng-model这类指令属性里,你根本不需要加{{}},直接把rowId当成作用域变量用就行:<input type="text" ng-model='budget.row(rowId).description' >这样Angular就会识别到
rowId是当前作用域里的变量,正确调用budget.row(10)获取对应对象,完成数据绑定。额外说句:为什么Angular要这么设计?
Angular的指令属性本身就是用来绑定表达式的,{{}}是专门给普通HTML属性准备的插值语法。如果在指令属性里硬加{{}},反而会打乱表达式的解析逻辑——Angular会把{{rowId}}当成字符串的一部分,而不是变量引用,自然就出问题了。
内容的提问来源于stack exchange,提问作者GGizmos

