2016-09-17 78 views
2

我有一个子组件MyStats,它将输入数据作为列表并显示关于该列表的统计信息。当myData中的列表更新时,我需要在组件内调用rebuildStats函数。由于组件中没有$ scope,所以我不能添加$ watch。有没有办法从MainCtrl调用rebuildStats?什么是解决它的最好方法?如何访问Angular1.5中父控制器的组件方法

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> 

编辑:有2个解决方案,我现在使用: 1)在数据块I改变为2路结合和介绍了从组件内创建,然后父母可以调用此setter函数功能。它不使用$范围,但仍...不知道这是什么角度的创作者的意图。

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控制器,具有标签“我的测试控制器”和具有ID =“ID1”那么我可以访问它想:

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

回答

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 
}); 

或者只是注入$范围,以你的位指示功能与$注入语法:

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

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

0

这很奇怪有一个与“现代”的组件和单向数据绑定混合了经典控制器+范围。

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

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(); 
    } 
}; 
+0

该组件将用于来自不同控制器的数据分析:用户评论的统计数据,评论和书评。由于其非常通用,我不能将它绑定到特定的数据源。所以在这方面数据必须作为参数传递。我尝试了$ onChanges,但它只在组件合并期间调用,并且在从$ http更新列表时不会调用 –

+1

不,这是错误的,它在绑定数据更改时调用。 https://toddmotto.com/angular-1-5-lifecycle-hooks#onchanges – gyc

0

我也有类似的问题,这样的事情为我工作:

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

$('my-stats').scope()是组件的“外”的范围,你必须调用children()得到“内部”(只要有任何子女)。

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