wilson
wilson

Reputation: 657

Calling a function in every repeat by using ng-repeat

I have the following relationship: Categories <---> Products (with a 1-N cardinality)

This is the ng-repeat directive in the html table

<tr ng-repeat="category in categories">
    <td>{{category.name}}</td>
    <td>{{products[category.id]}}</td>
</tr>

So what I need to do is when every time the repeat list a category, this category will be send immediately to the getAllProductsByCategory() function and then the $http service will get all the products that belong to this specific category.

I tried to use the ng-init directive in order to execute the function but I think it's not the correct way to use it. Is there a better way to do it?

<tr ng-repeat="category in categories" ng-init="getAllProductsByCategory(category)">
    <td>{{category.name}}</td>
    <td>{{products[category.id]}}</td>
</tr>

And this is the function that will get all the products by category

$scope.getAllProductsByCategory = function(category){
$http("getAlProductsByCategory"+category.id){
    .success(function (data, status, headers, config) {
        $scope.products[category.id] = data;
    })
    .error(function (data, status, header, config){
        $log.error("Error");
    });
}

Upvotes: 0

Views: 758

Answers (2)

georgeawg
georgeawg

Reputation: 48948

I don't know how to split an array in the controller in order to pass every object to the getAllProductsByCategory(category)

I don't recommend using ng-init to make calls to asynchronous APIs. In a model-view-whatever architechure, the model should drive the view. The view should not drive the model. The view can collect user input events for the controller. The controller can then use those events to update the model, using asynchronous APIs if necessary.

In this case the list of categories probably came from an asynch API, then the products for each category need to come from an asynch API. This can accomplished be chaining promises.

First create a categories promise:

var categoriesPromise = $http.get(categoriesUrl)
  .then(function (response) {
    var categories = response.data;
    $scope.categories = categories;
    //return to chain categories
    return categories;
}).catch(function (error) {
    console.log("ERROR: ", error.status);
    //throw to chain rejection
    throw error;
});

Now chain from that promise:

$scope.products = {};

var productsPromise = categoriesPromise.then(function(categories) {
    var promiseHash = {};
    categories.foreach(function(c) {
        promiseHash[c.id] = getProductsByCategory(c)
          .then(function(products) {
             $scope.products[c.id] = products;
             //return data for chaining
             return products;
        });
    });
    //return $q.all promise for chaining
    return $q.all(promiseHash);
});

For more information, see

Upvotes: 1

TigOldBitties
TigOldBitties

Reputation: 1337

ng-init will be execute only once at the beginning not for every category. I think what you're trying to do is this:

<tr ng-repeat="category in categories">
    <td>{{category.name}}</td>
    <td>{{products[category.id]}}</td>
    <script type="text/javascript">
         getAllProductsByCategory({{category}});
    </script>
</tr>

but there are easier ways to do this, instead of calling once for each category, which is bad from a performance point of view, like creating an array of categories and calling them only once in the controller having them ready for whatever you want to use them.

Upvotes: 0

Related Questions