使用三种有效的方法和不起作用的原始方法进行更新
我已经做了一个有角度的js指令,我正在尝试访问ctrl.$modelValue。它在主流中不起作用。
我有三个潜在的解决方案,所有这些都有缺点。
方法1不像我所希望的那样工作,并且在指令中找不到任何其他可用的属性可以通过这种方式直接访问。
方法2可以工作,因为它一直等到当前流完成,然后在下一刻执行。这恰好是在角形js生命周期完成之后,此时控制器似乎被连接到模型上。这在我看来并不理想,因为它正在等待所有的执行完成。如果可能的话,我宁愿在控制器链接到模型之后立即运行我的代码,而不是在当前流中的所有代码完成之后运行。
方法3运行良好,可以从$scope访问模型,并从在attrs对象上访问的字符串表示确定模型是什么。缺点是,这种方法是为了获取地址的值,而正如我们都知道的,eval是邪恶的。
方法4工作,但它似乎是一种访问简单属性的过于复杂的方法。我不敢相信没有比字符串操作和while循环更简单的方法了。我不相信访问属性的功能是100%健壮的。至少我可能希望将其更改为使用for循环。
我应该使用哪种方法,还是有第五种方法没有缺点?
演示:http://jsfiddle.net/billymoon/VE9dX/9/
HTML:
<div ng-app="myApp">
<div ng-controller="inControl">
I like to drink {{drink.type}}<br>
<input my-dir ng-model="drink.type"></input>
</div>
</div>Javascript:
var app = angular.module('myApp', []);
app.controller('inControl', function($scope) {
$scope.drink = {type:'water'};
});
app.directive('myDir', function(){
return {
restrict: 'A',
require: 'ngModel',
link: function($scope, element, attrs, ctrl) {
// Method 1
// logs NaN
console.log({"method-1": ctrl.$modelValue});
// Method 2
// on next tick it is ok
setTimeout(function(){
console.log({"method-2": ctrl.$modelValue});
},0);
// Method 3
// using eval to access model on scope is ok
// eval is necessary in case model is chained
// like `drink.type`
console.log({"method-3": eval("$scope."+attrs.ngModel)});
// Method 4
// using complex loop to access model on scope
// which does same thing as eval method, without eval
var getProperty = function(obj, prop) {
var parts = prop.split('.'),
last = parts.pop(),
l = parts.length,
i = 1,
current = parts[0];
while((obj = obj[current]) && i < l) {
current = parts[i];
i++;
}
if(obj) {
return obj[last];
}
}
console.log({"method-4": getProperty($scope,attrs.ngModel)});
}
};
});发布于 2014-02-05 22:22:35
有相当多的备选方案,其中一些比其他更好,取决于您的需求,例如,如果视图值或模型值发生变化,或者您对初始值满意,是否应该通知您。
要知道初始值,可以使用以下任一项:
console.log('$eval ' + $scope.$eval(attrs.ngModel));
console.log('$parse ' + $parse(attrs.ngModel)($scope));
$eval和$parse的最终结果都是相同的,但是$eval位于$scope之外,其中$parse是一个角服务,它将表达式转换为函数。然后可以调用返回的$parse函数并传递上下文(通常是作用域),以检索表达式的值。此外,如果表达式是可分配的,则返回的$parse函数将具有一个赋值属性。“赋值”属性是一个可用于更改给定上下文上表达式的值的函数。见$parse文档。
如果需要在模型值更改时通知您,可以使用$watch,但是在处理ngModel时有更好的方法。如果在模型本身(即代码中)发生更改时,需要跟踪对模型值的更改,则可以使用modelCtrl.$formatters
ctrl.$formatters.push(function(value){
console.log('Formatter ' + value);
});请注意,只有当模型值从代码中更改时才调用$formatters,而不是当模型从用户输入更改时才调用。您还可以使用$formatters更改模型视图值,例如,在不更改底层模型值的情况下将显示文本转换为大写。
当您需要了解从用户输入中发生的模型值更改时,可以使用modelCtrl.$parsers或modelCtrl.$viewChangeListeners。每当用户输入更改底层模型值时,都会调用它们:
ctrl.$viewChangeListeners.push(function(){
console.log('$viewChangeListener ' + ctrl.$modelValue, arguments);
});
ctrl.$parsers.push(function(value){
console.log('$parsers ' + value, arguments);
return value;
});如果需要,$parsers允许您将用户输入的值更改为模型,$viewChangeListeners只让您知道输入值何时更改。
总之,如果您只需要初始值,请使用$eval或$parse,如果您需要知道值何时更改,则需要将$formatters和$parsers/$viewChangeListeners组合起来。
下面的小提琴显示了基于原始小提琴的所有这些选项和更多选项:http://jsfiddle.net/VE9dX/6/
发布于 2014-02-05 22:25:32
不要使用本机eval,而是在$scope对象上使用$eval函数:
console.log($scope.$eval(attrs.ngModel))看这把小提琴:http://jsfiddle.net/VE9dX/7/
https://stackoverflow.com/questions/21587204
复制相似问题