17

SITUATION:

I am making an app in AngularJs that assign permissions. In order to do this i have three nested ng-repeat.

First loop: display PERMISSION GROUP

Second loop: For each permission group display CATEGORIES. Inside this loop execute a function that will get all the SUB CATEGORIES for each category

Third loop: display SUB CATEGORIES

ISSUE:

The problem is in the execution of the function inside the second loop.

ATTEMPT 1 - ng-init:

<div class="row" ng-repeat="permission_group in list_permission_groups">
  <div class="col-sm-3">
    <h3>
      {{permission_group.permission_group_name}} 
    </h3>
  </div>
  <div class="col-sm-9">
    <ul>
      <li ng-repeat="category in list_categories">
        <span>
          {{ category.name }} 
        </span>            
        <div class="checkbox">
          <label>                
            <div ng-init="temp_result = get_Sub_Categories(category.category_id)">                  
              <p ng-repeat="sub_category in temp_result">
                {{ sub_category.name }} 
              </p>                  
            </div>               
          </label>
        </div>           
      </li>
    </ul>
  </div>
</div>

In the controller:

$scope.get_Sub_Categories = function(category_id) {
    $http({

        url: base_url + 'main/json_get_list_sub_categories',
        data: {
            category_id: category_id
        },
        method: "POST"

    }).success(function(data) {

        return data;

    });

}

Te behavior is quite strange. Porbably due to dirty checking the page is loaded 682 times. No result is displayed.

ATTEMPT 2 - ng-click: (only for debug)

<div class="row" ng-repeat="permission_group in list_permission_groups">

  <div class="col-sm-3">

    <h3>
      {{permission_group.permission_group_name}} 
    </h3>

  </div>

  <div class="col-sm-9">
    <ul>
      <li ng-repeat="category in list_categories">
        <span>
          {{ category.name }} 
        </span>

        <div class="checkbox">
          <label>

            <button ng-click="get_Sub_Categories(category.category_id)">
              GET SUB-CATEGORIES
            </button>

            {{ list_sub_categories }} 

          </label>
        </div>

      </li>
    </ul>
  </div>
</div>

In the controller:

$scope.get_Sub_Categories = function(category_id) {
    $http({

        url: base_url + 'main/json_get_list_sub_categories',
        data: {
            category_id: category_id
        },
        method: "POST"

    }).success(function(data) {

        $scope.list_sub_categories = data;

    });

}

This time the page is loaded only once. If I press the button the proper sub-categories are displayed BUT of course not only for the corresponding category but FOR ALL, because i am modifying the var in the global scope.

THE AIM:

What I want to obtain is simply displaying all the proper sub-categories for each category. Without using a button, but simply see all the proper content as soon as the page load. But i don't understand how can this be done properly in AngularJs.

THE QUESTION:

How can i properly execute a function inside a ng-repeat that return and display different data for each loop?

EDIT - DUMP OF EXAMPLE OF SUB-CATEGORIES FOR ONE CATEGORY:

[{
    "sub_category_id": "1",
    "name": "SUB_CATEGORY_1",
    "category_id_parent": "1",
    "status": "VISIBLE"
}, {
    "sub_category_id": "2",
    "name": "SUB_CATEGORY_2",
    "category_id_parent": "1",
    "status": "VISIBLE"
}, {
    "sub_category_id": "3",
    "name": "SUB_CATEGORY_3",
    "category_id_parent": "1",
    "status": "VISIBLE"
}, {
    "sub_category_id": "4",
    "name": "SUB_CATEGORY_4",
    "category_id_parent": "1",
    "status": "VISIBLE"
}]
Gary
  • 13,303
  • 18
  • 49
  • 71
FrancescoMussi
  • 20,760
  • 39
  • 126
  • 178
  • Ok, I wasn't clear enough, sorry. Could you add a short dump of all the input data? That includes `list_permission_groups` and how these values relate to `list_categories`. – Yoshi Oct 16 '14 at 09:31
  • @johnnyfittizio very good question it explains very well and has some badda boo badda bee. Very well! – Herr Oct 16 '14 at 17:39
  • you could keep your question much shorter – Arash Apr 27 '16 at 13:12

4 Answers4

11

Calling a function inside ng-repeat is same as normal one. Since you need to display the sub categories at the time of page loading its better to get these data beforehand. Asynchronously loading sub categories will not fit into this scenario.

Here is a minimal snippet achieving this (JS Fiddle)

<div ng-app="app" ng-controller="ctrl">
    <div ng-repeat="category in model.categories"> <span> Category: {{ category.name }} </span>

      <p ng-repeat="subCategory in getSubCategories(category.Id)">{{ subCategory.name }}</p>
   </div>
</div>

Controller

angular.module("app", [])
.controller('ctrl', ['$scope', function ($scope) {
$scope.model = {
    categories: [{
        "Id": 1,
        name: '1'
    }, {
        "Id": 2,
        name: '2'
    }],
    subCategories: [{
        "parentId": 1,
        name: 'a1'
    }, {
        "parentId": 1,
        name: 'a2'
    },
                   {
        "parentId": 2,
        name: 'a3'
    }]
}
$scope.getSubCategories = function(parentId){
    var result = [];
    for(var i = 0 ; i < $scope.model.subCategories.length ; i++){
        if(parentId === $scope.model.subCategories[i].parentId){
            result.push($scope.model.subCategories[i]);               
        }
    }
    console.log(parentId)
    return result;
}}])
Amitesh
  • 1,507
  • 1
  • 11
  • 19
  • Thank you Amitesh, it seems the proper way to do it. I am working on it. Can i make a litte question. According to this solution, how can i assign to the model the data retrieved from the server? I have tried $scope.model = { categories: $scope.list_categories } but is not working (return null) Thank you very much! – FrancescoMussi Oct 16 '14 at 11:15
  • You can initialise your model to blank. $scope.model = {categories:[],subCategories: []}. Once you get the data from server which i assume, would be a http call/promise object, assign the value in below manner: $scope.model.categories = data...,$scope.model.subCategories= data... – Amitesh Oct 16 '14 at 11:30
  • This seems to call getSubCategories(category.Id) every digest cycle. I do not see the same behavior using the ng-init method discussed below. – Larry Flewwelling Sep 05 '17 at 16:50
6

The subcategory example did not work for my case and it took my code into an infinte loop for some reason. may be because i was using an accordion.

I achieved this function call inside ng-repeat by using ng-init

<td class="lectureClass" ng-repeat="s in sessions" ng-init='presenters=getPresenters(s.id)'>
      {{s.name}}
      <div class="presenterClass" ng-repeat="p in presenters">
          {{p.name}}
      </div>
</td> 

The code on the controller side should look like below

$scope.getPresenters = function(id) {
    return SessionPresenters.get({id: id});
};

While the API factory is as follows:

angular.module('tryme3App').factory('SessionPresenters', function ($resource, DateUtils) {

        return $resource('api/session.Presenters/:id', {}, {
            'query': { method: 'GET', isArray: true},
            'get': {
                method: 'GET', isArray: true
            },
            'update': { method:'PUT' }
        });
    });
Sacky San
  • 1,535
  • 21
  • 26
  • 2
    You're posting the same code in answers to several questions. If the questions are actually duplicates, please flag them as such instead of answering. – Jeffrey Bosboom Feb 15 '16 at 03:21
  • I also faced infinite loop problem according to correct answer. So I use your answer but 'presenters' is empty array and nothing show in {{p.name}}. So if you have any idea, please help me. Thanks a lot. – Kyaw Zin Htun Jul 04 '17 at 08:12
  • Make sure your $scope.getPresenters = function(id) {} works correctly to set value in presenters – Sacky San Jul 14 '17 at 00:58
0

I think that the good solution here is to use Angular Directive.

You can see an example of directive used in a ng-repeat here : Angular Directive Does Not Evaluate Inside ng-repeat

For more information on directives, you can check the official documentation : https://docs.angularjs.org/guide/directive

Community
  • 1
  • 1
0

I would create a factory for category then move your get_sub_categories function into this new factory.

JayMc
  • 124
  • 6