AngularJS自定义指令双向绑定
AngularJS自定义指令双向绑定
如果我有一个没有模板的AngularJS指令,并且我想在当前作用域上设置一个属性,最好的方法是什么?
例如,一个计算按钮点击次数的指令:
Click Count: {{ counter }}
使用一个指令将点击次数分配给双向绑定属性中的表达式:
.directive('twoway', [ '$parse', function($parse) { return { scope: false, link: function(scope, elem, attrs) { elem.on('click', function() { var current = scope.$eval(attrs.twoway) || 0; $parse(attrs.twoway).assign(scope, ++current); scope.$apply(); }); } }; } ])
有更好的方法吗?从我所了解的,独立作用域可能过于复杂,但是我需要一个子作用域吗?除了使用$parse
之外,有没有更简洁的方法来写回到指令属性中定义的作用域变量?我只是觉得我把这个问题搞得太复杂了。
完整的Plunker示例在这里。
AngularJS自定义指令的双向绑定问题的出现原因是因为在指令中使用了独立作用域(isolate scope)。独立作用域非常有用,特别适用于这种问题:
scope: { "twoway": "=" // 双向绑定 },
这是一个非常典型的Angular解决方案,所以我建议继续使用这种方法。
Doug T.根据这个Stack Overflow的帖子进行了解释,但是我可能只理解了四分之一。
这个答案的关键是,你传递给指令的变量,比如counter
,必须是一个对象,比如obj.counter
,否则你将无法正确引用更新父作用域的变量。
AngularJS自定义指令双向绑定的问题是因为作者想要模仿ngshow/nghide指令的语法,直接在属性值中使用模型属性,但是却没有找到类似的解决方案。然后作者尝试使用ng-model指令进行双向绑定,但是这个指令并不是很常见,所以没有被提及。
解决方法是使用ng-model指令的第四个参数,即ngModelController的API。ngModelController可以用于处理数据的解析和格式化,并在指令和作用域之间共享数据。
下面是使用ng-model指令和ngModelController的代码示例:
angular.module('directive-binding', []) .directive('twoway', function() { return { require: '?ngModel', link: function(scope, elem, attrs, ngModel) { elem.on('click', function() { var counter = ngModel.$viewValue ? ngModel.$viewValue : 0 ngModel.$setViewValue(++counter); scope.$apply(); }); } }; } );
Click Count: {{ counter }}
可以通过ngModelController的API在link函数中进行操作。
这是更新后的Plunker示例:http://plnkr.co/edit/bwTSfs?p=preview
如果ngModel不满足需求,可以尝试使用隔离作用域进行解决。详细信息请参考Doug的回答。
AngularJS自定义指令双向绑定问题的出现原因是,当在模型中使用“嵌套”对象时,上述简化版本的代码无法正常工作。例如,如果使用“counter.val”代替“counter”,则无法正常工作。这是因为在AngularJS中,我们需要对嵌套对象进行解析,而上述代码并没有处理这个问题。
解决这个问题的方法是,在控制器中对其进行初始化。例如,通过在控制器中添加以下代码来初始化“counter”对象:$scope.counter={}; $scope.counter.val = 0
。
如果你对如何访问“嵌套”对象的字符串键感兴趣,可以参考此链接:this。这是该解决方案的根本问题,即我们需要编写某种解析器来处理嵌套对象。在AngularJS中,$parser服务或嵌套作用域映射可以为我们处理这个问题。
需要注意的是,在提问时要确保问题清晰明了,没有提到要在原始问题中使用嵌套对象。