当标记位于单个文件中时,为什么我的嵌套指令不起作用?

时间:2015-02-03 15:14:00

标签: angularjs angularjs-directive

我一直在研究isolateScope指令,以便更好地了解它们如何与其他嵌套的isolateScope指令进行交互,因此将plnkr放在一起测试一些东西。

http://plnkr.co/edit/7Tl7GbWIovDSmVeKKN26?p=preview

这按预期工作。正如您所看到的,每个指令都有自己独立的模板。

然后我决定将每个指令中的html移动到主html文件中,但是它已停止工作了?我可以看到e1Ctrl在指令的范围内,但在处理所附的标记时它似乎不可用。

http://plnkr.co/edit/33Zz1oO4q7BVFw0cMvYa?p=preview

有人可以告诉我为什么会这样吗?

-----------更新-----------

我已经简化了非工作人员以清楚地显示问题。该指令使用controllerAs语法,e1Ctrl明确设置$scope(参见控制台输出)。

http://plnkr.co/edit/g2U2XskJDwWKuK3gqips?p=preview

angular
  .module('app', [])
  .controller('AppCtrl', AppCtrl)
  .directive('elementOne', elementOne)
  .controller('E1Ctrl', E1Ctrl)


function AppCtrl() {

  var vm = this;

  vm.data = [
  {
    label: 'one'
  },
  {
    label: 'two'
  },
  {
    label: 'three'
  },
  {
    label: 'four'
  }
  ];

  vm.callback = function() {
    console.log('called app callback');
  };
}


function elementOne() {
  return {
    restrict: 'E',
    scope: {
      data: '=',
      handler: '&'
    },
    controller: 'E1Ctrl',
    controllerAs: 'e1Ctrl',
    bindToController: true
  }
}

function E1Ctrl($scope) {
  console.log('E1Ctrl', $scope);
  var vm = this;

  vm.click = function() {
    vm.handler();
  };

  vm.callback = function() {
    console.log('called e1 callback');
  };
}

标记:

<body ng-app="app" ng-controller="AppCtrl as appCtrl">
  <ul>
    <div ng-repeat='item in appCtrl.data'>

      <element-one data='item' handler='appCtrl.callback()'>
        <button ng-click='e1Ctrl.click()'>e1: {{e1Ctrl.data.label}}</button>
      </element-one>

    </div>
  </ul>
</body>

------翻译解决方案-----

http://plnkr.co/edit/l3YvnKOYoNANteNXqRrA?p=preview

function elementOne() {
  return {
    restrict: 'E',
    transclude: true,
    scope: {
      data: '=',
      handler: '&'
    },
    controller: 'E1Ctrl',
    link: function($scope, $element, $attr, ctrl, transclude) {

      transclude($scope, function(clone){
        $element.append(clone);
      });
    }
  }
}

1 个答案:

答案 0 :(得分:2)

指令的template中的HTML范围与指令子树中的HTML的范围有所不同。前者是在指令范围内进行评估的;后者 - 在视图范围内。

如果指令具有隔离范围 - scope: {},则子树不会看到它。如果它使用scope: true,那么它会为子树创建一个新的子范围,该子范围原型继承自View的范围。

请考虑以下事项:

// isolate scope
app.directive("foo", function(){
  return {
    scope: {},
    link: function(scope){
      scope.name = "foo";
    }
  }
});

// child scope
app.directive("bar", function(){
  return {
    scope: true,
    link: function(scope){
      scope.name = "bar";
    }
  }
});

app.controller("Main", function($scope){
  $scope.name = "main";
});

以下是视图的呈现方式:

<body ng-controller="MainCtrl">
  <pre>in main: {{name}} will render "main"</pre>
  <foo>
    <pre>in subtree of foo: {{name}} will render "main"</pre>
  </foo>
  <bar>
    <pre>in subtree of bar: {{name}} will render "bar"</pre>
  </bar>
</body>

在您的情况下,子树在View的范围内进行评估 - 而不是指令,这就是它无法按预期工作的原因。

plunker

修改

在某些情况下,在指令的隔离范围的上下文中评估子树是有意义的。我已经看到这与允许模板的指令一起使用。但要小心这一点,因为主视图的作者不应该(太多)知道指令的内部工作原理(即内部范围中暴露的内容)。这也很难阅读,因为你会看到在外部范围内没有意义的变量。

要评估指令的隔离范围中的子树,指令需要$compile子树并将其与其范围相关联。

这是一个允许用户为列表中的每个项目提供模板的指令。 item变量未在主范围中定义,仅在指令的隔离范围的上下文中有意义:

<list src="items">
  <item-template>
    {{item.a}} | {{item.b}}
  </item-template>
</list>

指令'list'如下:

app.directive("list", function($compile){
  return {
    scope: {
      src: "="
    },
    link: {
      pre: function(scope, element){
        var itemTemplate = element.find("item-template");
        element.empty();

        var template = angular.element('<div ng-repeat="item in src"></div>')
                              .append(itemTemplate.html());

        element.append(template);
        $compile(element.contents())(scope);
      }
    }
  }
});

plunker 2