Why I can't access the right scope?

2019-01-26 17:22发布

问题:

html:

<!doctype html>
<html>
<head>
</head>
<body>
<div ng-app="project">
   <div ng-controller="mainCtrl">
    {{ property1 }}
    <br />
    {{ property2 }}
    <div class="ts" d-child property1="{{ property1 }}cloud" property2="property2">
        property1: {{ property1 }}
        <br />
        property2: {{ property2 }}
    </div>

    </div>
    </div>
    </body>
</html>

js:

angular.module('project', [])
.controller('mainCtrl', function($scope) {
    $scope.property1 = 'ss';
    $scope.property2 = 'dd';
});

angular.module('project')
.directive('dChild', function() {
    return {
        restrict: 'A',
        scope: {
            property1: '@',
            property2: '='
        },
        link: function(scope, element, attrs) {

        }
//      template: '<input type="text" ng-model="property1" />'
    }
})

I thought the property1: {{ property1 }} would be "property1: sscloud",but it turns out to be "ss",as if it still refers to the scope of the mainCtrl controller, shouldn't it be refer the scope of the d-child directive?

if I use template in the directive,it does refer to the right scope and shows 'sscloud',anyone can tell me why?

回答1:

When angular compiles an element with isolated scope it has some rules:

  • If directives has no template property (or templateUrl), the inner content is attached to the parent scope. Actually before this commit, inner contents were getting the isolated scope. check your example to confirm it works on versions less than 1.2
  • If directives do have a template property then it would override the inner content (unless trancluded).
  • Only when you use a transclusion, then the inner content is attached to a sibling scope (non isolated).
  • The reason why angular works this way is to let reusable components be loosely coupled, and not have any side effects on your application.
  • Directives without isolate scope do not get the isolate scope from an isolate directive on the same element (see important commit).
  • Directive's template gets the isolated scope anyways.

If you want to alter this behavior you can pass the isolated scope to the tranclusion function like so:

angular.module('project')
.directive('dChild', function() {
    return {
        restrict: 'A',
        transclude: true,        
        scope: {
            property1: '@',
            property2: '='
        },
        link: function(scope, element, attrs, ctrl, linker) {
          linker(scope, function(clone, scope){
            element.append(clone)
          })
        }
    }
})

I highly recommend you to see these tutorials:

  • Angular.js - Transclusion basics
  • Angular.js - Components and containers

And to read more:

  • Access directive's isolate scope from within transcluded content
  • https://github.com/angular/angular.js/wiki/Understanding-Scopes


回答2:

I'm not quite sure about this, I'm pretty sure it all has to do with when each {{}} is evaluated, and when the scope of the directive becomes isolated. My suggestion is to place the content in a template, as it seems to be working when doing so.

If you want to read more about the difference of of "@" and "=" in directive scopes, here's the best text I've found about it.

What is the difference between '@' and '=' in directive scope in AngularJS?



回答3:

I think you have to use the transclude option. In fact, as AngularJS docs says :

What does this transclude option do, exactly? transclude makes the contents of 
a directive with this option have access to the scope outside of the directive 
rather than inside.

Because of the Directives isolated scope that you created

More docs at:

http://docs.angularjs.org/guide/directive