AngularJS会覆盖隔离的指令范围

时间:2014-10-31 16:27:55

标签: angularjs scope directive

用法:

<my-directive my-var="true"></my-directive>

指令:

app.directive('myDirective', [
    function () {
        var definition = {
            restrict: "E",
            replace: false,
            transclude: false,
            scope: {
                myVar: '@',
            },
            controller: ['$scope', function($scope) {
                console.log($scope.myVar); // "true"
                $scope.myVar = "false";
                console.log($scope.myVar); // "false"

                setTimeout(function() {
                    console.log($scope.myVar); // "true" (!)
                }, 100);
            }]
        };

        return definition;
    }
]);

控制台输出

"true"
"false"
"true"

这里到底发生了什么?变量以字符串形式传递(“true”),我正在改变它,然后再次被替换?我想了解这里的循环。这是因为还有一些额外的编译或摘要周期,并再次重新计算所有隔离的范围值?我认为一旦设置,像这样传递的变量(@,只是指令中的字符串)将保持不变?

有没有办法在指令内连接一下,之后字符串变量没有被替换,或者它会像每个摘要或诸如此类的东西一样工作,我被迫使用$ watch?

1 个答案:

答案 0 :(得分:8)

@将父作用域绑定到隔离作用域,它是单向(非一次)绑定。因此,外部作用域的任何更改都将重置指令的隔离范围中的值。

Under the covers,Angular使用“@”在元素属性上调用attrs.$observe。这样做的是它在编译后为下一个$摘要周期排队一个观察者函数。每次分配给属性的内插值发生变化时,该观察者函数就会设置范围变量。

因此,高级步骤是:

1) for `@` scope variable, set an observer function and queue it for later
2) set `@` scope variable to the interpolated value
3) run the controller, pre- and post-link functions
...
N) observer runs against interpolated value and sets the scope value

所以,鉴于此,您现在可以看到为什么您的更改不会持续存在。如果你在所有这些步骤之后完成它 - 即超时或响应事件。如果属性插值没有改变,则

=”不是这样。

这是一个说明差异的plunker

如果您想要一次性传递变量,只需使用链接函数或控制器中的属性设置范围变量

scope.myVar = $attrs["my-var"];

并从范围中删除myVar