如何在 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 编辑共享组件