我有子组件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
答案 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()
仅用于调试。