2016-09-17 5 views
2

Ich habe untergeordnete Komponente MyStats, die als Eingangsdaten mit Liste und zeigt Statistiken über diese Liste. Ich muss die Funktion rebuildStats in meiner Komponente aufrufen, wenn die Liste in myData aktualisiert wird. Da es keinen $ scope in Komponenten gibt, kann ich $ watch nicht hinzufügen. Gibt es Möglichkeit, rebuildStats von MainCtrl aufzurufen? Was ist der beste Weg, um es zu lösen?Zugriff auf Komponentenmethoden vom übergeordneten Controller in 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> 

Edit: Es gibt 2 Lösungen, die ich jetzt verwenden: 1) in dem Datenblock I zu 2-fach verändert Bindung und eingeführt setter Funktion, die von innerhalb Komponente erstellt wird, und dann kann Mutter nennt dies Funktion. Es verwendet $ scope aber immer noch nicht ... nicht sicher, ob das was angulare Schöpfer beabsichtigten.

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

Der zweite Ansatz besteht darin, über Element auf den Controller zuzugreifen. Wie so:

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

So, jetzt, wenn ich Controller mit MyTestController dem Stichwort "my-Test-Controller" und hat id = "id1" dann kann ich es gerne zugreifen:

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

Antwort

0

Wenn denke, dass die Verwendung der ES2015 Getter/Setter-Syntax die beste Lösung sein wird.

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

    ... 
} 


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

Oder nur $ Umfang auf Ihre contoller Funktion mit $ injiziert Syntax injizieren:

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

Ich muss in alten ES5-Bereich arbeiten. Ich kann $ injizieren, aber das klingt hackisch (es gibt einen Grund, warum $ aus der Komponente herausgenommen wird).Ich finde es sehr merkwürdig, dass ich von Komponente zu Eltern kommunizieren kann, indem ich Funktionsbindung wie "onUpdate": '&' benutze, aber es gibt keinen offensichtlichen Weg (von einem Elternteil zu einer Komponente). –

0

Es ist komisch, einen klassischen Controller + Umfang mit ‚modernen‘ Komponenten und Einweg-Daten gemischt haben, verbindlich.

Das erste, was in den Sinn kommt, ist, dass Sie Ihre Komponente benötigen, um den Dienst selbst aufzurufen. Sie benötigen keinen externen Controller und keine Bindungen.

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

Noch besser, legen Sie diese Logik in einen Dienst und rufen Sie den Dienst in $ onInit. Wenn das Versprechen gelöst ist und Ihre Daten bereit sind, rufen Sie Ihre Funktion auf.

Auf diese Weise haben Sie eine völlig unabhängige Komponente und Ihr Code wird leichter und besser.

Wenn Sie wirklich Notwendigkeit, die Daten innerhalb eines Attributs zu übergeben, können Sie $ onChanges verwenden für Modelländerungen überprüfen:

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

Diese Komponente wird für die Datenanalyse von verschiedenen Controllern verwendet: Statistiken für Benutzerrezensionen, für Kommentare und für Buchbesprechungen. Da es sehr generisch ist, kann ich es nicht an bestimmte Datenquellen binden. Insofern müssen Daten als Argument übergeben werden. Ich habe versucht $ onChanges, aber es nur während der Komponente cration aufgerufen und nicht aufgerufen, wenn ich Liste von $ http aktualisieren –

+1

Nein, es ist falsch, es heißt, wenn gebundene Daten ändert. https://toddmotto.com/angular-1-5-lifecycle-hooks#onchanges – gyc

0

Ich hatte ein ähnliches Problem, und so etwas wie dies für mich gearbeitet:

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

$('my-stats').scope() die „äußere“ Umfang Ihrer Komponente ist, haben Sie children() anrufen „innen“ zu bekommen (vorausgesetzt, es hat keine Kinder).

Ich denke nicht, dass dies ein richtiger Weg ist. Die Dokumentation sagt, dass nur zum Debuggen ist.

Verwandte Themen