Search code examples
javascriptangularjsfilterangularjs-ng-repeatgrouping

How to filter and group the data based on name using angularjs?


I have the following list of descriptions which belong to each name. Please let me know how can I group or list the descriptions per name.

html:

<body ng-app="app" ng-controller="MainCtrl">

    <div ng-repeat="nameGroup in loopData"> <!-- this ng-repeat should be available as per my requirement -->
        <div ng-repeat="loopData in nameGroup.values track by $index" ><!-- this ng-repeat should be available as per my requirement -->

    <!-- {{loopData}} -->
        <div class="text-center merged">{{loopData.name}}</div><!-- ng-if="$index === 0" -->
        <div class="text-center">{{loopData.description}}</div> 

     </div>
     </div>
</body>

controller:

var app = angular.module('app', ['angular.filter']);

app.controller('MainCtrl', function($scope) {
  $scope.finalLoopData = {};

  $scope.loopData = [{ "country":"Abc", "id":"001", "mynumbers":[], 
    "values": [
      {"description": "first desc", "name": "First Test Name"},
      {"description": "second desc", "name": "First Test Name"},
      {"description": "third desc", "name": "First Test Name"},
      {"description": "fourth desc", "name": "Second Test Name"},
      {"description": "fifth desc", "name": "Second Test Name"},
      {"description": "sixth desc", "name": "Third Test Name"},
      {"description": "seventh desc", "name": "Third Test Name"},
      {"description": "eighth desc", "name": "Third Test Name"},
      {"description": "ninth desc", "name": "Third Test Name"},
      {"description": "tenth desc", "name": "Third Test Name"},
      {"description": "eleventh desc", "name": "Fourth Test Name"},
      {"description": "twelfth desc", "name": "Fourth Test Name"}
    ]
  }];

  $scope.arrayToObject = function () {
    var finalLoopData = {};
    angular.forEach($scope.loopData[0].values, function (value, key) {
        //console.log(value);//gives all value objects
        if (!finalLoopData[value.name]) { 
             finalLoopData[value.name] = new Array();
             //console.log("name: "+value.name);//First Test Name //Second Test Name //Third Test Name //Fourth Test Name
        }
        finalLoopData[value.name].push(value);
    });
    $scope.finalLoopData = finalLoopData;
  }
  $scope.arrayToObject();
});

If I run this code, I am getting individual description with names, but not with group names, here is my expected output is similar to below:

First Test Name

  • first desc

  • second desc

  • third desc

Second Test Name

  • fourth desc

  • fifth desc

Third Test Name

  • sixth desc

  • seventh desc

  • eighth desc

  • ninth desc

  • tenth desc

Fourth Test Name

  • eleventh desc

  • twelfth desc

Created Filter:


Solution

  • Updated

    If you can not change the loops in the template, consider the following:

    Template

    <body ng-app="app" ng-controller="MainCtrl">
      <!-- Original loops -->
      <div ng-repeat="nameGroup in loopData">
        <div ng-repeat="loopData in nameGroup.values track by $index">
    
          <!-- Data name -->
          <strong>{{loopData.name}}</strong>
    
          <!-- Loop data descriptions -->
          <ul ng-repeat="description in loopData.descriptions">
            <li>{{description}}</li>
          </ul>
    
        </div>
      </div>
    </body>
    

    Controller

    var app = angular.module('app', ['angular.filter']);
    
    app.controller('MainCtrl', function($scope) {
    
      $scope.loopData = [
        {
          country: "Abc",
          id: "001",
          mynumbers: [],
          values: [
            { description: "first desc", name: "First Test Name" },
            { description: "second desc", name: "First Test Name" },
            { description: "third desc", name: "First Test Name" },
            { description: "fourth desc", name: "Second Test Name" },
            { description: "fifth desc", name: "Second Test Name" },
            { description: "sixth desc", name: "Third Test Name" },
            { description: "seventh desc", name: "Third Test Name" },
            { description: "eighth desc", name: "Third Test Name" },
            { description: "ninth desc", name: "Third Test Name" },
            { description: "tenth desc", name: "Third Test Name" },
            { description: "eleventh desc", name: "Fourth Test Name" },
            { description: "twelfth desc", name: "Fourth Test Name" }
          ]
        }
      ];
    
      this.$onInit = function() {
        $scope.loopData.forEach(function(data) {
          const groupedValues = {};
    
          // group values by name
          data.values.forEach(function(value) {
            // initialize name group
            if (!groupedValues[value.name]) {
              groupedValues[value.name] = {
                name: value.name,
                descriptions: []
              };
            }
    
            // add description to name group
            groupedValues[value.name].descriptions.push(value.description);
          });
    
          // update values
          data.values = Object.values(groupedValues);
        });
      };
    
    });
    

    Note that the $onInit function will convert $scope.loopData to the following:

    [
      {
        "country": "Abc",
        "id": "001",
        "mynumbers": [],
        "values": [
          {
            "name": "First Test Name",
            "descriptions": [
              "first desc",
              "second desc",
              "third desc"
            ]
          },
          {
            "name": "Second Test Name",
            "descriptions": [
              "fourth desc",
              "fifth desc"
            ]
          },
          {
            "name": "Third Test Name",
            "descriptions": [
              "sixth desc",
              "seventh desc",
              "eighth desc",
              "ninth desc",
              "tenth desc"
            ]
          },
          {
            "name": "Fourth Test Name",
            "descriptions": [
              "eleventh desc",
              "twelfth desc"
            ]
          }
        ]
      }
    ]
    

    Original answer

    In your html you're not looping on your processed finalLoopData variable. Also, to display the name of the group once, you need to have it in the first loop (not the second).

    Consider the following code:

    Template

    <body ng-app="app" ng-controller="MainCtrl">
      <!-- Loop final data -->
      <div ng-repeat="nameGroup in finalLoopData">
    
        <!-- Group name -->
        <strong>{{nameGroup.name}}</strong>
    
        <!-- Loop group descriptions -->
        <ul ng-repeat="description in nameGroup.descriptions track by $index">
          <li>{{description}}</li>
        </ul>
    
      </div>
    </body>
    

    Controller

    var app = angular.module('app', ['angular.filter']);
    
    app.controller('MainCtrl', function($scope) {
    
      $scope.finalLoopData = {};
    
      $scope.loopData = [
        {
          country: "Abc",
          id: "001",
          mynumbers: [],
          values: [
            { description: "first desc", name: "First Test Name" },
            { description: "second desc", name: "First Test Name" },
            { description: "third desc", name: "First Test Name" },
            { description: "fourth desc", name: "Second Test Name" },
            { description: "fifth desc", name: "Second Test Name" },
            { description: "sixth desc", name: "Third Test Name" },
            { description: "seventh desc", name: "Third Test Name" },
            { description: "eighth desc", name: "Third Test Name" },
            { description: "ninth desc", name: "Third Test Name" },
            { description: "tenth desc", name: "Third Test Name" },
            { description: "eleventh desc", name: "Fourth Test Name" },
            { description: "twelfth desc", name: "Fourth Test Name" }
          ]
        }
      ];
    
      this.$onInit = function() {
        const finalLoopData = {};
        $scope.loopData[0].values.forEach(function(item) {
          // initialize name group
          if (!finalLoopData[item.name]) {
            finalLoopData[item.name] = {
              name: item.name,
              descriptions: []
            };
          }
    
          // add description to name group
          finalLoopData[item.name].descriptions.push(item.description);
        });
    
        // apply results
        $scope.finalLoopData = finalLoopData;
      };
    
    });