2017-01-09 2 views
0

Ich versuche, meinen Kopf um Fabriken und Dienstleistungen in AngularJS zu wickeln und bleibe stecken. Hier ist ein grundlegendes Beispiel ähnlich zu Problemen, die ich versuche zu lösen.Zählen von Daten innerhalb von Kind-Controllern in Angular JS

HTML

<div ng-controller="productGridController"> 

    <div ng-repeat="category in categories" ng-controller="productCategoryController"> 

     <input type="text" ng-model="category.name"> 

     <div ng-repeat="product in products"> 
      <input type="text" ng-model="product.name"> 
     </div> 

     <a class="btn btn-small" ng-click="addProduct()">Add Product</a> 

    </div> 

    <a class="btn" ng-click="addCategory()">Add Category</a> 
</div> 

Lassen Sie uns jetzt sagen, dass ich eine Gesamtzahl aller Produkte erhalten möchten, die derzeit innerhalb des Root-Controller instanziiert productGridController und speichern sie in einer Variablen kann ich Ausgang innerhalb des productGridController in ein Variable wie $scope.totalProducts

Da jeder productCategoryController hat seinen eigenen Umfang, ich bin mir nicht sicher, wie man globale Zähler und Summen so macht? Ich denke, ia Service oder Fabrik könnte so etwas tun, aber ich bin nicht sicher, wie man es einführt.

Ich habe versucht, einen Stammbereich Variable in der productGridController wie folgt setzen:

app.controller("productGridController", function($scope, $http, $rootScope, $timeout) { 
    $scope.totalProducts = 0; 

    $scope.categories = []; 
    $scope.addCategory = function() { 
     $scope.categories.push({name:''}); 
    } 
}); 

Und dann beobachten, wenn etwas in der Dies funktioniert

app.controller("productCategoryController", function($scope, $http, $rootScope, $timeout) { 
    $scope.products = []; 

    $scope.addProduct = function() { 
     $scope.products.push({name:''}); 
    } 

    $scope.$watch('products', function() { 
     $scope.totalProducts = $scope.products.length; 
    }, true); 
}); 
productCategoryController geändert, wenn es gibt nur eine Kategorie hinzugefügt, aber wenn es mehrere Kategorien gibt, berücksichtigt nur die letzte.

Denken Sie auch daran, dass ich in meiner realen Anwendung die Daten aus einer Datenbank einlese, damit diese auch in Echtzeit arbeiten können, so dass die Zählerfunktion an jedem beliebigen Punkt aufgerufen werden kann, um den aktuellen Status anzuzeigen wie viele Produkte es derzeit gibt.

Was wäre der einfachste Weg, dies in Angular JS zu tun?

+0

* Was wäre der einfachste Weg, dies in Angular JS zu tun? * Ich denke, Sie machen das Leben kompliziert, indem Sie einen Controller für jedes Element in einer 'ng-Wiederholung' instanziieren. Im Allgemeinen sollte ein Controller nicht versuchen, zu viel zu tun. Es sollte nur die Geschäftslogik enthalten, die für eine einzelne Ansicht benötigt wird. Weitere Informationen finden Sie in [AngularJS Developer Guide - Korrekte Verwendung von Controllern] (https://docs.angularjs.org/guide/controller#using-controllers-correctly). – georgeawg

Antwort

0

Erste:

Sie überwachen "Produkte". Wenn Sie 'products.push()' in 'addProduct' aufrufen, ändert sich der Wert der Produkte nicht; Daher wird Ihre Uhr nicht aufgerufen. Wenn Sie hat gesagt, statt:

$scope.addProduct = function() { 
    $scope.products = $scope.products.concat([{name:''}]); 
} 

dann Ihre Uhr würde aufgerufen wurde wie erwartet (weil dann der Wert von ‚Produkten‘ geändert hat).

Zweitens:

Sie auch nicht vergessen Sie die funktionale Form von $ Uhr verwenden können:

$scope.$watch(function() {return $scope.products.length;}, function() { 
    $scope.totalProducts = $scope.products.length; 
}); 

Aber vor allem: warum überhaupt eine $ Uhr benutzen? Sie hätten sagen können:

$scope.addProduct = function() { 
    $scope.products.push({name:''}); 
    $scope.totalProducts = $scope.products.length; 
} 

da Sie wissen, dass dies die Art von Aktion ist, die eine Nebenwirkung hat.

Die Idee, einen Dienst zu verwenden, besteht darin, etwas weiter zu gehen und all diese datenspezifische Logik an einem Ort zu packen, an dem wir nicht darüber nachdenken müssen, wie und wann es gerendert wird. Dann injizieren Sie diesen Service in Ihren Controller und der Controller macht die relevanten Teile des Services (über den Bereich) verfügbar.

+0

Ich muss eine Uhr verwenden, da diese Daten aus einer Datenbank abgerufen werden können. In diesem Fall würde sie niemals eine 'addProduct' Methode aufrufen – Jordash

+0

Auch wenn' products' ein leeres Objekt hinzufügt, wird die 'watch' dennoch ausgelöst – Jordash

+0

Beachten Sie auch, dass '$ scope.products.length' die Länge der Produkte innerhalb dieser Produktkategorie ist, also höchstens die Gesamtzahl der Produkte für diesen spezifischen 'productCategoryController' angibt. Ich möchte die gesamten Produkte aller Produktkategorien zusammengefasst, nicht nur eine der Kategorien. – Jordash

0

Wenn ein persistenter oder gemeinsamer Status benötigt wird, implementieren Sie eine Factory oder einen Dienst, um diesen Status zu verwalten - hier ist eine gute SO Q/A über die Unterschiede (zusammen mit Anbietern).

$ Uhr ist toll, aber es ist nicht immer die beste Wahl. Wenn Sie beispielsweise das Produktdatenset nicht zwischenspeichern können (möglicherweise ist es sehr groß), können Sie Ereignisse über $broadcast ändern.

Hier ist ein plnkr demonstrating your scenario mit einem Produktdienst, der ein Ereignis für Add/Remove-Vorgänge sendet und eine Direktive, die auf dieses Änderungsereignis wartet und seinen Inhalt entsprechend aktualisiert.

Die wichtige Teile Product sind seine $ broadcast'ing ein Änderungsereignis, wenn Produkte hinzugefügt oder entfernt werden:

app.service('ProductService', function($rootScope) { 
    let self = { 
     PRODUCT_COUNT_DELTA: "PRODUCT_COUNT_DELTA", 
     $inject: ['$rootScope'] 
    } 
    // broadcast a PRODUCT_COUNT_DELTA event with the latest product count. 
    function changes(changeType) { 
    if (changeType == 0) 
     $rootScope.$broadcast(self.PRODUCT_COUNT_DELTA, self.getProductCount()); 
    } 

In der Demo, die Service-Methoden addProduct und removeProduct Aufruf Das interne ändert Funktion, wenn ein Produkt hinzugefügt oder entfernt wird.

Die Richtlinie Product macht die aktuelle Anzahl der Produkte und Updates, wenn die Produktanzahl Änderungen informiert:

app.directive("productCount", ['ProductService', function(productService) { 
    let render = function(count) { 
    count = count || productService.getProductCount(); 
    return "<span>" + count + "</span>"; 
    } 
    return { 
    restrict: 'E',  
    template: function(elem, attr) { 
     return render(); 
    }, 
    link: function($scope, elem, attrs) { 
     $scope.$on(productService.PRODUCT_COUNT_DELTA, function($event, productCount) { 
     elem.html(render(productCount)); 
     }); 
    } 
    } 
}]); 

Wieder $ Uhr ist praktisch, aber nicht immer die richtige Wahl.

+0

Danke, aber dieses Beispiel nicht Beantworten Sie die Frage, in der Frage, sie können mehrere Produktkategorie Controller, jeder mit ihrem eigenen Umfang, ich versuche, eine Summe der gesamten Produkte über alle Controller, nicht nur eine. Um dies zu tun, muss ich durchlaufen alle derzeit aktiven Controller eines bestimmten Typs – Jordash

+0

In der Tat - vielleicht [so etwas] (https://plnrkr.co/edit/VColYfxi9ZsTXfaIUWLh?p=preview)? – RamblinRose

Verwandte Themen