AngularJS: Directive isolate scope - scope variable undefined

不打扰是莪最后的温柔 提交于 2019-12-23 18:53:43

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!