问题
Please, can someone explain me, why attrDir
's scope variable is visible, and oneWay
's not?
I thought that scope: {}
is isolated as well.
angular.module('test', []);
angular.module('test').directive('attrDir', attrDir);
function attrDir(){
return {
scope: true,
link: function(scope){
scope.hello = 'attrDir';
}
};
}
angular.module('test').directive('oneWay', oneWay);
function oneWay(){
return {
scope: {
data: '<?'
},
link: function(scope){
scope.hello = 'oneWay';
}
};
}
hello
will be rendered only in attr-dir
.
<attr-dir>
<span>{{hello}}</span>
</attr-dir>
<one-way>
<span>{{hello}}</span>
</one-way>
Here is a plunker: https://plnkr.co/edit/2CM4vVRshWuJvaBj2q8T?p=preview
Thx.
回答1:
First, what you're observing has nothing to do with <
binding.
The problem is that the expression {{hello}}
inside both directives are not part of the template of these directives. And for such elements the rules for bindings are different.
Angular automatically creates link functions for {{hello}}
expressions. But the scopes against which these link functions are evaluated are different in your cases.
What you probably expected is this:
rootScope
/ \
/ \
attr-dir-new-scope one-way-isoloate-scope
/ \
/ \
{{hello}} {{hello}}
However, according to this comment in source:
// We only pass the isolate scope, if the isolate directive has a template,
// otherwise the child elements do not belong to the isolate directive.
the real picture is this:
root scope
/ \ \
/ \ \
attr-dir-new-scope \ one-way-isoloate-scope
/ \
/ \
{{hello}} {{hello}}
So in your example, the first directive <attr-dir>
doesn't create isolate scope, but creates new scope, so when linking angular passes this new scope both to the linking function of your directive:
link: function(scope){
scope.hello = 'attrDir';
}
and to the linking function created for the {{hello}}
expression. That's why when you add a value in your linking function it's available in the expression linking function.
But your second directive <one-way>
creates isolate scope and according to the comment I mentioned above, the linking function of the directive gets isolated scope as it should, but the linking function of the expression receives different scope (root scope in your example). So you're adding hello
value on different scopes. That's why the value is undefined.
回答2:
Both scope: true and scope:{} will create a child scope for the directive. But,
scope:true will prototypically inherit the properties from the parent(say the controller where the directive comes under) where asscope:{} will not inherit the properties from the parent and hence called isolated
As oneWay is an isolated scope directive and you are not passing the hello, so it is undefined in the HTML.
回答3:
If scope is not specified, it is shared scope. If scope is specified as true, it is inherited scope. If scope is specified with curly braces, it is isolate scope.
The best way to visualize the scopes is by using console.log statements in your link functions like so,
link: function(scope) {
scope.hello = 'attrDir';
console.log('scope in attrDir: ', scope);
}
link: function(scope) {
scope.hello = 'oneWay';
console.log('scope in oneWay: ', scope);
}
If you open the developer tools, you will see that the first directive inherits its parent scope in its prototype
__proto__:Scope
whereas the second one is an object with its own scope (by using curly braces you gave it an isolate scope)
__proto__:Object
回答4:
Because you're implementing component bindings in directive.
The < symbol denotes one-way bindings which are available since 1.5.
If you want to show the hello
in one-way
component you should change the implementation like below:
HTML
<one-way hello="$ctrl.hello">
<span>{{$ctrl.hello}}</span>
</one-way>
JS
angular.module('test').component('oneWay', {
bindings:{
hello:'='
},
controller: function() {
this.hello = 'oneWay';
}
});
Demo
plnkr
来源:https://stackoverflow.com/questions/42728977/angularjs-directive-isolate-scope-scope-variable-undefined