如何从Angular1.5中的父控制器访问组件方法

时间:2016-09-17 17:27:42

标签: angularjs components

我有子组件MyStats,它将列表作为输入数据,并显示有关该列表的统计信息。当myData中的列表更新时,我需要在我的组件中调用rebuildStats函数。由于组件中没有$ scope,我无法添加$ watch。有没有办法从MainCtrl调用rebuildStats?什么是解决它的最佳方法?

module.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
  $scope.statData = {};
  $http.get('..some url..').then(function(resp) {
    $scope.statData.list = resp.list;
  });
}]);

module.component('myStats', {
    'templateUrl': '...',
    'bindings': {
        'myData': '<ngModel'
    },
    'controller': function() {
      this.totalActive = 0;
      this.rebuildStats = function() {
        var cntr = 0;
        angular.forEach(this.myData.list, function (item) {
          if (item.isActive) {
            cntr++;
          }
        });
        this.totalActive = cntr;
      };

    }
});

<my-stats ng-model="statData"></my-stats>

编辑:我现在使用了两种解决方案:     1)在数据块中,我改为双向绑定,并引入了从组件内创建的setter函数,然后parent可以调用此函数。它不使用$ scope但仍然......不确定这是Angular创建者的意图。

module.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
  $scope.statData = {};
  $http.get('..some url..').then(function(resp) {
    $scope.statData.setList(resp.list);
  });
}]);

module.component('myStats', {
    'templateUrl': '...',
    'bindings': {
        'myData': '=ngModel'
    },
    'controller': function() {
      var ctrl = this;

      this.totalActive = 0;
      this.rebuildStats = function() {
        var cntr = 0;
        angular.forEach(ctrl.myData.list, function (item) {
          if (item.isActive) {
            cntr++;
          }
        });
        ctrl.totalActive = cntr;
      };
      this.myData.setList = function (list) {
        ctrl.myData.list = list;
        ctrl.rebuildStats();
      };
    }
});

第二种方法是通过元素访问控制器。像这样:

    var getController = function(elementSelector, controllerName) {
      var el = angular.element(document.querySelector(elementSelector));
      if (el) {
        return el.controller(controllerName);
      }
      return null;
    };

所以现在如果我的控制器MyTestController有标签“my-test-controller”并且id =“id1”那么我可以像下面那样访问它:

var ctrl = getController('my-test-controller#id1', 'MyTestController');
ctrl.MyTestControllerMethod(); // access any exposed method

3 个答案:

答案 0 :(得分:0)

如果认为使用ES2015 getter / setter语法将是最佳解决方案。

class MyStats{
    get myData() {
        return this.$value;
    }
    set myData(value) {
       this.$value = value;
       this.rebuildStats();
    }

    ...
}


module.component('myStats', {
    'templateUrl': '...',
    'bindings': {
        'myData': '<ngModel'
    },
    'controller': MyStats
});

或者只需使用$ inject语法将$ scope注入你的控制器函数:

MyStatsController.$inject = ['$scope'];
function MyStatsController($scope) {
  ...
}

答案 1 :(得分:0)

将经典的控制器+范围与现代&#39;混合在一起是很奇怪的。组件和单向数据绑定。

首先想到的是,您需要组件来调用服务本身。您不需要外部控制器和绑定。

var vm = this;
this.$onInit = function() {
  $http.get(...).then(function() { vm.rebuildStats(); })
}

更好的是,将该逻辑放在服务中并在$ onInit中调用该服务。 当承诺解决并且您的数据准备就绪时,请调用您的函数。

通过这种方式,您可以拥有完全独立的组件,并且您的代码变得更轻松,更好。

如果您确实需要传递属性中的数据,您可以使用$ onChanges来检查模型更改:

var vm = this;
this.$onChanges = function (changes) {
  if (changes.myData) {
    vm.myData= angular.copy(changes.myData.currentValue);
    vm.rebuilsStats();
  }
};

答案 2 :(得分:0)

我有类似的问题,这样的事情对我有用:

var scope = $('my-stats').children().scope();
scope.$ctrl.rebuildStats();

$('my-stats').scope()是您组件的“外部”范围,您必须致电children()以获取“内部”(如果它有任何子项)。

我不认为这是正确的方法。文档说scope()仅用于调试。