使用controllerAs时,在指令中访问父范围

时间:2015-09-14 19:08:05

标签: javascript angularjs angularjs-directive angularjs-scope

我目前有一个指令,它使用来自父控制器范围的属性:

.controller('MainCtrl', function($scope) {
  $scope.name = 'My Name';
})

.directive('myDirective', function() {
  return {
    scope: true,
    controller: function($scope) {
      console.log($scope.name); // logs 'My Name'
    }
  };
})

现在我在我的控制器中转换为controllerAs语法,但我不知道如何在我的指令控制器中获得对控制器对象的引用。

.controller('MainCtrl', function() {
  var vm = this;
  vm.name = 'My Name';
})

.directive('myDirective', function() {
  return {
    scope: true,
    controller: function($scope) {
      console.log(vm.name); // logs 'Undefined'
    }
  };
})

此处的a plunkr说明了这个问题。

我还发现this article试图解释类似的东西,但在这种情况下,他只是重复使用完全相同的控制器。

2 个答案:

答案 0 :(得分:9)

使用ControllerAs语法时,会在$scope对象上创建属性,该对象是控制器的别名。例如,ng-controller="MainCtrl as vm"会为您提供$scope.vm。 HTML中隐含了$scope,因此访问HTML中的vm.name与在JavaScript中访问$scope.vm.name相同。

在控制器中,您可以访问this.name$scope.vm.name,它们在功能上是等效的。但是,在其他控制器中,this将引用该特定控制器,因此this.name将无效。

因此,在这种情况下,您可以使用$scope.vm.name访问指令控制器中所需的属性。 http://plnkr.co/edit/WTJy7LlB7VRJzwTGdFYs?p=preview

但是,您可能也希望在指令中也使用ControllerAs语法;在这种情况下,我建议您不要使用vm作为控制器名称,而是使用唯一的名称来帮助识别您所指的控制器。 MainCtrl as main,然后引用main.name会更清楚。

我建议尽可能使用隔离范围,因为它可以让您完全不需要将$scope注入到指令中,并允许您的指令自包含且可重用。

旁注,如果你没有使用隔离范围,bindToController: true,什么都不做;当 使用隔离范围时,它会在隔离控制器上创建属性以匹配传入的范围,从而允许您访问传入的值而无需$scope

答案 1 :(得分:3)

一种选择是遍历$scope链,直到找到vm。

app.directive('myDir', function() {
  return {
    restrict: 'E',
    scope: true,
    template: '<div>my directive</div>',
    bindToController: true,
    controller: function($scope) {
      console.log($scope.name2); // logs 'bound to the controller scope'
      console.log($scope.$parent.vm.name); // logs 'bound to the controller vm'
    }
  };  
});

然而,这可能非常脆弱,而且闻起来有点香气。

更复杂和深思熟虑的方法是通过传递的参数将控制器范围的属性绑定到指令。

HTML:

<my-dir name="vm.name" />

JS:

app.directive('myDir', function() {
  return {
    restrict: 'E',
    scope: {
      name: "="
    },
    template: '<div>my directive</div>',
    bindToController: true,
    controller: function($scope) {
      console.log($scope.name); // logs 'bound to the controller vm' 
    }
  };  
});

请参阅plunkr