隔离范围何时绑定到 AngularJs 中的父范围?
When is Isolated scope bound to parent scope in AngularJs?
在编译/link 过程的哪个阶段,指令的隔离作用域中的变量绑定到父(控制器)作用域?我有一个应用程序,我想在加载视图后立即自动调用指令 api。
我了解作用域绑定 happens in the directive linking phase,因此 post link 在独立作用域上公开的变量应该在父作用域上可用。
但是,我发现情况并非如此,如下面的代码所示 (plunker here)。
//plunker code
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.buttonClick = function() {
console.log("In buttonClick function, call is: " + this.call);
this.call();
}
$scope.$on("LinkComplete", function(event) {
console.log("In LinkComplete, call is: " + event.currentScope.call);
//event.currentScope.call();
});
console.log("In Constructor, call is: " + this.call);
})
.directive('myDirective', function(){
return {
scope: {
myMethod: '='
},
controller: function ($scope) {
$scope.myMethod = function() {
alert("method called");
};
},
link: function postLink(scope)
{
scope.$emit("LinkComplete");
}
};
});
<body ng-controller="MainCtrl">
<p>Hello {{name}}!</p>
<div my-directive my-method="call"></div>
<button ng-click="buttonClick()">Call</button>
</body>
请注意,代码在视图初始化期间两次尝试访问 linked 变量(它指向指令控制器上的一个方法),并且在这两种情况下,该变量都是未定义的。我不希望该变量在主控制器构造函数期间可用,但我希望它在 post-link 事件处理程序期间可用。加载视图后,绑定变量可用(单击调用按钮进行见证)。
如何在不要求用户单击按钮等的情况下从控制器访问绑定变量?
这是一个很好的问题,当你看到像'x is y in z stage'这样的词时,你需要注意准确性,总是深入研究源代码来证明它。
你的 plunker 使用的是 v1.2.27,检查这一行:
https://github.com/angular/angular.js/blob/v1.2.27/src/ng/compile.js#L1492
isolateScope.$watch(function parentValueWatch() {
var parentValue = parentGet(scope);
if (!compare(parentValue, isolateScope[scopeName])) {
// we are out of sync and need to copy
if (!compare(parentValue, lastValue)) {
// parent changed and it has precedence
isolateScope[scopeName] = parentValue;
} else {
// if the parent can be assigned then do so
parentSet(scope, parentValue = isolateScope[scopeName]);
}
}
return lastValue = parentValue;
}, null, parentGet.literal);
这将在下一个 $digest 周期中进行评估,然后 parentScope.call
将被分配。同时,postLink 函数在其下方同步执行:
https://github.com/angular/angular.js/blob/v1.2.27/src/ng/compile.js#L1575
// POSTLINKING
for (i = postLinkFns.length - 1; i >= 0; i--) {
try {
linkFn = postLinkFns[i];
linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), transcludeFn);
} catch (e) {
$exceptionHandler(e, startingTag($element));
}
}
执行 postLink 后,控制器收到事件,但 parentScope.call
尚未通过 $digest 初始化。
所以如果你添加一个setTimeout来检查,它看起来像你想要的:
$scope.$on("LinkComplete", function(event) {
setTimeout(function () {
console.log("In LinkComplete, call is: " + event.currentScope.call);
//event.currentScope.call();
});
});
在编译/link 过程的哪个阶段,指令的隔离作用域中的变量绑定到父(控制器)作用域?我有一个应用程序,我想在加载视图后立即自动调用指令 api。
我了解作用域绑定 happens in the directive linking phase,因此 post link 在独立作用域上公开的变量应该在父作用域上可用。
但是,我发现情况并非如此,如下面的代码所示 (plunker here)。
//plunker code
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.buttonClick = function() {
console.log("In buttonClick function, call is: " + this.call);
this.call();
}
$scope.$on("LinkComplete", function(event) {
console.log("In LinkComplete, call is: " + event.currentScope.call);
//event.currentScope.call();
});
console.log("In Constructor, call is: " + this.call);
})
.directive('myDirective', function(){
return {
scope: {
myMethod: '='
},
controller: function ($scope) {
$scope.myMethod = function() {
alert("method called");
};
},
link: function postLink(scope)
{
scope.$emit("LinkComplete");
}
};
});
<body ng-controller="MainCtrl">
<p>Hello {{name}}!</p>
<div my-directive my-method="call"></div>
<button ng-click="buttonClick()">Call</button>
</body>
请注意,代码在视图初始化期间两次尝试访问 linked 变量(它指向指令控制器上的一个方法),并且在这两种情况下,该变量都是未定义的。我不希望该变量在主控制器构造函数期间可用,但我希望它在 post-link 事件处理程序期间可用。加载视图后,绑定变量可用(单击调用按钮进行见证)。
如何在不要求用户单击按钮等的情况下从控制器访问绑定变量?
这是一个很好的问题,当你看到像'x is y in z stage'这样的词时,你需要注意准确性,总是深入研究源代码来证明它。
你的 plunker 使用的是 v1.2.27,检查这一行: https://github.com/angular/angular.js/blob/v1.2.27/src/ng/compile.js#L1492
isolateScope.$watch(function parentValueWatch() {
var parentValue = parentGet(scope);
if (!compare(parentValue, isolateScope[scopeName])) {
// we are out of sync and need to copy
if (!compare(parentValue, lastValue)) {
// parent changed and it has precedence
isolateScope[scopeName] = parentValue;
} else {
// if the parent can be assigned then do so
parentSet(scope, parentValue = isolateScope[scopeName]);
}
}
return lastValue = parentValue;
}, null, parentGet.literal);
这将在下一个 $digest 周期中进行评估,然后 parentScope.call
将被分配。同时,postLink 函数在其下方同步执行:
https://github.com/angular/angular.js/blob/v1.2.27/src/ng/compile.js#L1575
// POSTLINKING
for (i = postLinkFns.length - 1; i >= 0; i--) {
try {
linkFn = postLinkFns[i];
linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), transcludeFn);
} catch (e) {
$exceptionHandler(e, startingTag($element));
}
}
执行 postLink 后,控制器收到事件,但 parentScope.call
尚未通过 $digest 初始化。
所以如果你添加一个setTimeout来检查,它看起来像你想要的:
$scope.$on("LinkComplete", function(event) {
setTimeout(function () {
console.log("In LinkComplete, call is: " + event.currentScope.call);
//event.currentScope.call();
});
});