Javascript Angular js访问指令主流程中的“ctrl.$modelView” 更新了三种有效的方法,而原来的方法不起作用

Javascript Angular js访问指令主流程中的“ctrl.$modelView” 更新了三种有效的方法,而原来的方法不起作用,javascript,angularjs,Javascript,Angularjs,我已经做了一个angular js指令,我正在尝试访问ctrl.$modelValue。它在主流程中不工作 我有三种可能的解决方案,它们都有缺点 方法1不能像我希望的那样工作,并且我在指令中找不到任何其他可用的属性可以通过这种方式直接访问 方法2之所以有效,是因为它等待当前流完成,然后在下一时刻执行。这恰好发生在angular js生命周期完成之后,此时控制器似乎已连接到模型。这在我看来并不理想,因为它正在等待所有的执行完成。如果可能的话,我更愿意在控制器链接到模型之后立即运行代码,而不是在当前

我已经做了一个angular js指令,我正在尝试访问
ctrl.$modelValue
。它在主流程中不工作

我有三种可能的解决方案,它们都有缺点

方法1不能像我希望的那样工作,并且我在指令中找不到任何其他可用的属性可以通过这种方式直接访问

方法2之所以有效,是因为它等待当前流完成,然后在下一时刻执行。这恰好发生在angular js生命周期完成之后,此时控制器似乎已连接到模型。这在我看来并不理想,因为它正在等待所有的执行完成。如果可能的话,我更愿意在控制器链接到模型之后立即运行代码,而不是在当前流中的所有代码完成之后

方法3运行良好,从
$scope
访问模型,并从
attrs
对象上访问的字符串表示确定模型是什么。缺点是,这种方法使用eval来获取寻址的值——我们都知道,eval是邪恶的

方法4有效,但访问简单属性似乎过于复杂。我不敢相信没有比字符串操作和while循环更简单的方法了。我不相信访问属性的函数是100%健壮的。至少我想把它改成使用for循环

我应该使用哪种方法,或者是否有第五种方法没有缺点

演示: HTML:


我喜欢喝{{drink.type}}
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)});

        }
    };
});
var-app=angular.module('myApp',[]);
应用控制器(“inControl智能驭享”,功能($范围){
$scope.drink={type:'water'};
});
app.directive('myDir',function(){
返回{
限制:“A”,
要求:'ngModel',
链接:函数($scope、element、attrs、ctrl){
//方法1
//圆木楠
log({“方法-1”:ctrl.$modelValue});
//方法2
//在下一个滴答声,它是好的
setTimeout(函数(){
log({“方法-2”:ctrl.$modelValue});
},0);
//方法3
//使用eval访问作用域上的模型是可以的
//在模型链接的情况下,评估是必要的
//比如“饮料,类型”`
log({“method-3”:eval($scope.+attrs.ngModel)});
//方法4
//使用复杂循环访问作用域上的模型
//它的作用与eval方法相同,没有eval
var getProperty=函数(对象、属性){
var parts=prop.split('.'),
last=parts.pop(),
l=零件长度,
i=1,
电流=零件[0];
而((obj=obj[当前])和&i
有很多备选方案,有些方案比其他方案好,具体取决于您的需求,例如,如果视图值或模型值发生变化,是否应通知您,或者您是否满意初始值

只需知道初始值,即可使用以下任一项:

console.log('$eval'+$scope.eval(attrs.ngModel))

console.log('$parse'+$parse(attrs.ngModel)($scope))

$eval
$parse
最终结果是相同的,但是
$eval
位于
$scope
之外,其中
$parse
是一个角度服务,它将表达式转换为函数。然后可以调用返回的
$parse
函数并传递上下文(通常是作用域),以便检索表达式的值。此外,如果表达式是可赋值的,则返回的
$parse
函数将具有assign属性。assign属性是一个函数,可用于更改给定上下文中表达式的值。看

如果需要在模型值更改时得到通知,可以使用$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
允许您根据需要将值从用户输入更改为模型,其中
$viewchangelisters
仅允许您知道输入值何时更改

总之,如果您只需要初始值,请使用
$eval
$parse
,如果您需要知道值何时更改,则需要组合使用
$formatters
$parsers/$viewchangelisters

以下显示了基于原始小提琴的所有这些和更多选项:

在$scope对象上使用
$eval
函数,而不是使用本机
eval

console.log($scope.$eval(attrs.ngModel))
看这把小提琴:

有什么原因吗
console.log($scope.$eval(attrs.ngModel))