如何在 Angular 1.5 中从父控制器访问组件方法

Posted

技术标签:

【中文标题】如何在 Angular 1.5 中从父控制器访问组件方法【英文标题】:How to access component methods from parent controller in Angular1.5 【发布时间】:2017-01-25 18:16:09 【问题描述】:

我有子组件 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)在数据块中,我更改为 2-way binding 并引入了从组件内部创建的 setter 函数,然后父级可以调用此函数。它不使用 $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;
    ;

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

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

【问题讨论】:

【参考方案1】:

如果认为使用 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) 
  ...

【讨论】:

我必须在旧的 ES5 领域进行操作。我可以 $inject 但这听起来很骇人(因为从组件中取出 $scope 是有原因的)。我觉得很奇怪,我可以使用像 'onUpdate': '&' 这样的函数绑定从组件到父级进行通信,但是没有明显的方法(如果甚至存在的话)从父级调用到组件。【参考方案2】:

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

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

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

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

这样您就拥有了一个完全独立的组件,并且您的代码变得更轻巧更好。

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

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

【讨论】:

该组件将用于来自不同控制器的数据分析:用户评论、cmets 和书评的统计数据。由于它非常通用,我无法将其绑定到特定的数据源。所以在这方面数据必须作为参数传递。我尝试了 $onChanges 但它仅在组件创建期间调用,而不是在我从 $http 更新列表时调用 不,不对,是绑定数据变化时调用。 toddmotto.com/angular-1-5-lifecycle-hooks#onchanges【参考方案3】:

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

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

$('my-stats').scope() 是组件的“外部”范围,您必须调用 children() 才能进入“内部”(前提是它有任何子级)。

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

【讨论】:

以上是关于如何在 Angular 1.5 中从父控制器访问组件方法的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Angular 6 中从父级 HTML 编辑共享组件

如何在Angular 5中从父组件继承子组件中的css样式

Angular中从父组件到子组件的数据共享

如何在颤动中从父小部件访问所有孩子的状态?

Angular ui-router - 如何访问从父模板传递的嵌套命名视图中的参数?

在匿名 PHP 函数中从父范围访问变量