AngularJS如何:指令的范围层次结构

时间:2014-04-16 15:33:10

标签: javascript angularjs inheritance scope

AngularJS中的指令:我发现带有指令的元素内的元素不会继承其"范围"。

例如:

app
.controller('xxx', function($scope) {})
.directive('yyy', function() {
  return {
    scope: {},
    link: function(scope,elem,attrs) {}
  };
});

当我们在HTML中使用它时:

<body ng-controller="xxx">
  <div id='withD' yyy>
    <div id='inside'>Inside the element with a directive</div>
  </div>
</body>

&#34;主体&#34;将具有$ id可能为003的范围; 然后&#34; #withD&#34;将有一个隔离范围$ id = 004; &#34;#inside&#34;将具有范围$ id = 003,这意味着&#34;#inside&#34;继承&#34; body&#34;的范围。

如果我使用&#34; transinclude&#34;指令&#34; yyy&#34 ;;然后&#34;身体&#34;范围。$ id = 003,&#34; #withD&#34;范围。$ id = 004,&#34;#inside&#34; 。范围的$ id = 005;此外,003有两个孩子004和005.但是,我想使用该指令的元素具有隔离范围,并且其子元素继承范围。

我读过&#34; ui.bootstrap.tabs&#34;源代码,但我不喜欢这种风格,因为它很奇怪,也没有让父元素与子元素共享其范围&#39 ;;它看起来像这样:

app
.directive('xitem', function() {
  scope: {},
  controller: function($scope) {
    $scope.subitem = [];
    return {
      add: function(xsubitem) {$scope.subitem.push(xsubitem);}
    }
  },
  link: function(scope,elem,attrs) {}
})
.directive('xsubitem', function() {
  require: '^xitem',
  link: function(scope,elem,attrs,ctrl) {ctrl.add(elem);}
});

我的期望是:

<div ng-controller="xxx">
  <div yyy>
    <button ng-click="sayHi()">Hi</button>
  <div>
</div>

当您点击&#34;嗨&#34;按钮,警告对话框将弹出消息&#34; Hello World&#34;不是&#34;错误:范围&#34;。

app
.controller('xxx', function($scope) {
  $scope.sayHi = function(){alert('Error: Scope');};
})
.directive('yyy', function() {
  return {
    scope: {},
    link: function(scope,elem,attrs) {
      scope.sayHi = function(){alert('Hello World');};
    }
  };
});

此外,我试过这个:

app
.controller('xxx', function($scope) {
  $scope.sayHi = function(){alert('Error: Scope');};
})
.directive('yyy', function() {
  return {
    scope: {},
    controller: function($scope, $compile) {$scope._compile = $compile;}
    link: function(scope,elem,attrs) {
      elem.children().forEach(function(one) {
        scope._compile(one)(scope);
      });
      scope.sayHi = function(){alert('Hello World');};
    }
  };
});

然后它将弹出两个警告对话框,其中包含消息&#34;错误:范围&#34;和#34; Hello World&#34;分别

2 个答案:

答案 0 :(得分:0)

要做你想做的事,你需要使用一个模板(作为字符串或templateUrl)。如果angularjs在这种情况下会如你所能地工作,那么许多角度指令将无法正常工作(例如ng-show,ng-click等)。

所以要按照你想要的方式工作,将你的html改为:

<script type="text/ng-template" id="zzz.html">
  <button ng-click="sayHi()">Hi 2</button>
</script>

<div ng-controller="xxx">

  <button ng-click="sayHi()">Hi 1</button>

  <div yyy></div>
</div>

更新指令定义以使用templateUrl(或者您可以将字符串作为模板属性提供)

app
  .controller('xxx', function($scope) {
    $scope.sayHi = function() {
      console.error('Error: Scope in xxx', new Date());
    };
  })
  .directive('yyy', function() {
    return {
      scope: {},
      templateUrl: 'zzz.html',

      link: function(scope, elem, attrs) {
        scope.sayHi = function() {
          console.log('Hello World in zzz', new Date());
        };
      }
    };
  });

以下是使用此代码的傻瓜:http://plnkr.co/edit/nDathkanbULyHHzuI2Rf?p=preview

更新以使用多个模板

您的最新评论是关于如果您想在同一页面上使用不同模板的内容的问题。在这种情况下,我们可以使用ng-include

HTML:

  <div yyy contents="template1.html"></div>
  <div yyy contents="template2.html"></div>
  <div yyy contents="template3.html"></div>

JS:

app
  .controller('xxx', ...)
  .directive('yyy', function() {
    return {
      scope: {
        theTemplateUrl: '@contents'
      },
      template: '<ng-include src="theTemplateUrl"></ng-include>',

      link: function(scope, elem, attrs) {
        scope.sayHi = function() {
          console.log('Hello World in yyy', new Date());
        };
      }
    };
  });

使用ng-include的好处是,它已经内置于angularjs中并且经过了充分测试。此外,它支持在脚本标记内嵌或从实际网址加载模板,甚至可以预先加载到角度模块缓存中。

同样,这是一个带有工作样本的傻瓜:http://plnkr.co/edit/uaC4Vcs3IgirChSOrfSL?p=preview

答案 1 :(得分:0)

现在我找到了解决方案 - 动态加载模板并使用$ compile指定范围:

.controller('main', function($scope) {
  $scope.sayHi = function() {alert('scope error');};}
)
.directive('scopeInherit', ['$http', '$compile', function($http, $compile) {
  return {
    scope: {},
    link: function(scope, elem, attrs) {
      scope.sayHi = function() {alert('hello world');};
      scope.contents = angular.element('<div>');
      $http.get(elem.attr('contentsURL'))
           .success(function (contents) {
             scope.contents.html(contents);
             $compile(scope.contents)(scope);
           });
    },
  };
}]);

然后我们写HTML:

<div ng-controller="main">
  <div scope-inherit contents="test.html"></div>
</div>

哪里有test.html:

<button ng-click="sayHi()">speak</button>

然后点击&#34;说&#34;按钮,它将弹出警告对话框&#34; hello world&#34;