Search code examples
htmlangularjsangularjs-ng-repeatangular-ng-if

Build category menu with angularJS


I'm having problem with logic of building category menu with AngularJS

I wan't to print all categories with parent category id 0. Once this is done i wan't to print all sub categories which belong to its parent category. End category menu should look like this:
- Audio, video & photo
--- Music players
--- Musical instruments
--- ...
--- Rest
- Cars
--- Whole cars

This is how my categories object looks like

    0: Object
    alias: "audio-video-and-photo"
    category: "AUdio, video & photo"
    id_category: "1"
    parrent: "0"
    __proto__: Object
    1: Object
    alias: "music-players"
    category: "Music players"
    id_category: "2"
    parrent: "1"
    __proto__: Object
    2: Object
    alias: "musical-instruments"
    category: "Musical instruments"
    id_category: "3"
    parrent: "1"
    __proto__: Object
    3: Object
    alias: "music-accessories"
    category: "Music accessories"
    id_category: "4"
    parrent: "1"
    __proto__: Object
    4: Object
    alias: "hi-fi"
    category: "Hi-Fi"
    id_category: "5"
    parrent: "1"
    __proto__: Object
    5: Object
    alias: "home-cinema"
    category: "Home cinema"
    id_category: "6"
    parrent: "1"
    __proto__: Object
    6: Object
    alias: "tv"
    category: "TV's"
    id_category: "7"
    parrent: "1"
    __proto__: Object
    7: Object
    alias: "rest"
    category: "Rest"
    id_category: "8"
    parrent: "1"
    __proto__: Object
    8: Object
    alias: "cars"
    category: "Cars"
    id_category: "9"
    parrent: "0"
    __proto__: Object
    9: Object
    alias: "whole-cars"
    category: "Whole cars"
    id_category: "10"
    parrent: "9"
    __proto__: Object
....

And this is how my HTML looks like

<div ng-repeat="c in categories track by $index">
    <h4 ng-if="c.parrent == 0">{{c.category}}</h4>
        <ul>
            <li><a href="index.html">{{c.category}}</a></li>
        </ul>
</div>

End HTML should look similar to this

<div>
    <h4>Audio, video photo</h4>
        <ul>
            <li><a href="#">Music players</a></li>
            <li><a href="#">Music instruments</a></li>
            <li><a href="#">Music accessories</a></li>
            <li><a href="#">Hi-fi</a></li>
            <li><a href="#">Home cinema</a></li>
            <li><a href="#">Rest</a></li>
        </ul>
    <h4>Cars</h4>
        <ul>
            <li><a href="#">Whole cars</a></li>
            <li><a href="#">Car accessories</a></li>
            <li><a href="#">Car parts</a></li>
            <li><a href="#">Rest</a></li>
        </ul>
</div>

I hope you guys can help. Thanks in advance.


Solution

  • You can use ng-if to handle like this. Here is a solution with a nested ng-repeat.

    <div ng-repeat="c in categories track by $index">
        <h4 ng-if="c.parrent == 0">{{c.category}}</h4>
        <ul ng-if="c.parrent != 0"
            ng-repeat="sub_c in categories track by $index">
           <li ng-if="sub_c.parrent == c.id_category">
             <a href="#">{{sub_c.category}}</a>
           </li>
        </ul>
    </div>
    

    Note that it will be better to organize your data before rendering or using a helper method to filter sub-category items. This will be efficient than do ng-repeat twice.

    Update 1:

    As requested, I post the idea how to organize data before rendering. I'll use with the library underscore (or lodash).

    function build_category(categories) {
      var result = _.filter(categories, function(c) {
        return c.parrent == 0;
      });
      _.forEach(result, function(c) {
        c.sub_categories = _.filter(categories, function(c2) {
          return c2.parrent  == c.id_category;
        });
      });
      return result;
    }
    
    var grouped_categories = build_category(categories);
    
    <div ng-repeat="c in grouped_categories track by $index">
       <h4>{{c.category}}</h4>
       <ul ng-if="c.sub_categories"
           ng-repeat="sub_c in c.sub_categories track by $index">
         <li><a href="#">{{sub_c.category}}</a></li>
       </ul>
    </div>
    

    If you have a large category, you will see some performance difference.