2017-01-09 4 views
0

私はAngularJSの工場とサービスの周りを頭で囲み、つづきを止めようとしています。ここで私が解決しようとしている問題に似た基本的な例があります。今、HTMLAngular JSの子コントローラの中のデータを集計する

<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> 

のは、私は現在、ルートコントローラproductGridControllerの内部でインスタンス化されるすべての製品の合計数を取得し、私はproductGridControllerの内部出力をすることができます変数に格納したいとしましょう

$scope.totalProducts

productCategoryControllerにはそれぞれ独自のスコープがありますので、どのようにグローバルカウンタとそのような合計を行うのかよく分かりません。私はサービスや工場がこれを何かすることができると思うが、それをどう実装するかは分からない。

私はこのようなproductGridControllerにルートスコープの変数を入れてみました:

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

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

そして何かがproductCategoryController

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

に変更したときにのみ、追加のカテゴリが存在していたときにこの作品を見、複数のカテゴリがある場合は、最新のカテゴリのみを考慮します。

また、実際のアプリケーションでは、データベースからデータを取得しているので、これもリアルタイムで機能する必要があるので、カウンタ機能を呼び出して現在のステータスを反映させることができます現在いくつの製品が存在しているかということです。

Angular JSでこれを行う最も簡単な方法は何ですか?

+0

* Angular JSでこれを行う最も簡単な方法は何ですか?*あなたは 'ng-repeat'で各項目のコントローラをインスタンス化することで人生を複雑にしていると思います。一般的に、コントローラはあまりにも多くをやってはいけません。単一のビューに必要なビジネスロジックのみを含める必要があります。詳細については、[AngularJS Developer Guide - コントローラを正しく使用する](https://docs.angularjs.org/guide/controller#using-controllers-correctly)を参照してください。 – georgeawg

答えて

0

最初に:

「製品」に時計を貼っています。 'addProduct'で 'products.push()'を呼び出すと、商品の価値は変化しません。あなたの時計は呼び出されません。あなたが代わりに言っていた場合:

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

をあなたが(当時の製品 'の値が変更されたため)予想通り、あなたの時計が呼び出されていたであろう。

第二:

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

しかし大抵:

あなたも$観の関数形式を使用することができます忘れてはいけない理由は全く$ウォッチを使いますか?あなたが言ったかもしれません:

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

あなたはこれが副作用を伴う行動の種類であることを知っているからです。

サービスを使用するという考えは、もう少し進んで、このデータ固有のロジックをすべて、どのようにいつレンダリングするかについて考える必要のない場所にパッケージ化することです。次に、そのサービスをコントローラに注入し、コントローラは関連するスコープを介してサービスの部分を公開します。

+0

このデータはデータベースから引き出される可能性があるので時計を使用する必要があります。その場合、 'addProduct'メソッドを呼び出すことはありません – Jordash

+0

' products'が空白オブジェクトを追加していても 'watch'がトリガされます – Jordash

+0

また、 '$ scope.products.length'は、その製品カテゴリの中の製品の長さですので、その特定の' productCategoryController'のための製品の総数を最大で与えることになります。すべての製品カテゴリカテゴリの1つだけではなく、合計されます。 – Jordash

0

永続または共有状態が必要な場合は、その状態を管理するためのファクトリまたはサービスを実装します。プロバイダとの相違点については、SO Q/Aとなります。

$ watchは素晴らしいですが、必ずしも最良の選択ではありません。たとえば、製品データセットをキャッシュできない場合は(おそらくそれは巨大です)、$broadcast経由の変更イベントを使用する方が良いかもしれません。

追加/削除操作のイベントをブロードキャストするプロダクトサービスと、その変更イベントをリッスンし、それに応じてコンテンツを更新する指示文を持つplnkr demonstrating your scenarioがあります。デモで

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

、サービスメソッドaddProductremoveProductコール:ProductService

重要な部分は、製品が追加または削除されている変更イベントのその$のbroadcast'ingです製品が追加または削除されたときに内部に変更されます。 、再び

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

$の時計は便利ですが、常に正しい選択ではありません。

ディレクティブproductCountは、製品数の変更の通知を受け、現在の製品の数と更新をレンダリングします。

+0

ありがとうございます。質問に答えてください。質問には、複数の製品カテゴリコントローラがあり、それぞれが独自のスコープを持つことができます。私は、すべてのコントローラで、1つだけでなく、すべての製品にわたって合計を取得しようとしています。 – Jordash

+0

確かに - おそらく[このような何か](https://plnkr.co/edit/VColYfxi9ZsTXfaIUWLh?p=preview)? – RamblinRose

関連する問題