Angular 绑定在使用传递的数据计算的局部范围变量的自定义指令中不起作用

Angular binding is not working in custom directive for local scope variables calculated using passed data

在上面的示例中,当我更改从控制器传递给指令的值数组时,所有更改都会反映在指令中 html。我的意思是我可以看到 UI.

中的变化

但是 $scope.message 变量值的变化没有得到反映,即使 $scope.message 的值是根据 $scope.myData 的值计算的,$scope.myData 的值正在获取在父控制器中使用 $timeout 更改 要查看 $scope.message 中的这些更改,您需要使用 $watchCollection 观察数组。我的问题是,

  1. 为什么 angular 的绑定不能正常用于 $scope.myData
  2. angular 的绑定不起作用的其他“已知”极端情况是什么?

下面是代码片段

(function(){
    angular.module("csjoshi04.2waybinding",[])
            .controller("ParentCtrl",["$scope", "$timeout", function($scope, $timeout){
                $scope.myCars = ["Ford", "BMW", "Toyata"];
                $timeout(function(){
                    $scope.myCars.push("Honda");
                }, 3000);
            }])
            .directive("showMyData",function(){
                return {
                    restrict: "E",
                    scope: {
                        myData : "="
                    },
                    controller : ["$scope", function($scope){
                        $scope.message = ($scope.myData.indexOf("Honda") > -1 && $scope.myData.length >= 4) ? "1 out of 4 cars is always Honda": "OOPS, no honda cars";
                    }],
                    template : '<div>{{message}}</div><ul ng-repeat="data in myData"><li>{{data}}</li></ul>'
                }
            })
})()

下面是html

<body ng-controller="ParentCtrl"><show-my-data my-data="myCars" ></show-my-data></body>

为了使上述指令生效,我进行了以下更改

directive("showMyData",function(){
                return {
                    restrict: "E",
                    scope: {
                        myData : "="
                    },
                    controller : ["$scope", function($scope){
                        $scope.message = ($scope.myData.indexOf("Honda") > -1 && $scope.myData.length >= 4) ? "1 out of 4 cars is always Honda": "OOPS, no honda cars";
                        $scope.$watchCollection(function(){
                            return $scope.myData;
                        }, function(new1, old){
                            $scope.message = ($scope.myData.indexOf("Honda") > -1 && $scope.myData.length >= 4) ? "1 out of 4 cars is always Honda": "OOPS, no honda cars";
                        });
                    }],
                    template : '<div>{{message}}</div><ul ng-repeat="data in myData"><li>{{data}}</li></ul>'
                }
            })

这里是 link plunkr。

plunker

我不会将其称为 angular.

中数据绑定的 "corner case"

Angular 的数据绑定通过不断检查附加到 $scope 的值来工作。这很酷,但并不神奇,在像 JavaScript 语句这样的命令式语言中 $scope.message = condition ? "message": "another message"; 本身并不表示将再次重新评估该表达式。 Angular 每个模板附件仅初始化控制器一次,这正是上面示例中的语句将被评估的次数。 一次。 之后它只是另一个 $scope 变量,其值是 "message" 或 "another message" 如果我们不这样做,它将保持不变自己改。

你自己发现了问题。 $scope.message 的值取决于 $scope.myData,但如果没有 $watchCollection,则无法使此链接保持最新。另一方面,$watchCollection 将首先重新评估 $scope.myData;,然后再评估 $scope.message = ... 函数,因为这就是 angular 要做的事情。

不过,就我个人而言,我会使用函数 getter 来完成此操作,而不是将值分配给 $scope 并手动使其保持最新状态。无论如何,这更接近您最初尝试做的事情。

.directive("showMyData",function(){
    return {
        restrict: "E",
        scope: {
           myData : "="
        },
        controller : ["$scope", function($scope){
            $scope.getMessage = function(){
                return ($scope.myData.indexOf("Honda") > -1 && $scope.myData.length >= 4) ? "1 out of 4 cars is always Honda": "OOPS, no honda cars";
            };    
        }],
        template : '<div>{{getMessage()}}</div><ul ng-repeat="data in myData"><li>{{data}}</li></ul>'
     }
})

现在我们使用的是函数调用而不是简单的值,创建消息的表达式会一遍又一遍地重新计算,必要时更新视图。