user3712353
user3712353

Reputation: 4201

AngularJS repeat dynamic array values

I have this array:

[
    {type:'a', value:'234'}, 
    {type:'a', value:'5566'}, 
    {type:'b', value:'778'}, 
    {type:'c', value:'899'}, 
    {type:'k', value:'5644'}
]

I want to do this iteration:

<div ng-repeat="obj in array">
    <h3 ng-bind="obj.type"></h3>
    <span ng-bind="obj.value"></span>
</div>

I want the result to be header for each type without duplicates, and under each type I want the values. How can I do it without iterating and creating new arrays?

Desired result:

<div>
    <h3>a</h3>
    <span>234</span>
    <span>234</span>
</div>... 

Thanks!

Upvotes: 1

Views: 514

Answers (4)

dvenkatsagar
dvenkatsagar

Reputation: 936

I think this should do the trick.

<div ng-repeat="obj in array | unique : 'type'">
  <h3 ng-bind="obj.type"></h3>
  <span ng-bind="obj.value"></span>
</div>

Check it out and see if it works.

Edit : You would need the angular.filter module for this

Update:

Looking at the updated question, I think it might be difficult for you to achieve the operation given(using a single iteration to list out all the values by unique type).

But you can do one thing, group the array by type using this pure JS function(similar to @Claies answer):

var custom_sort = function(arr){
  var a = arr.slice(0);
  var ret = [];
  var same_type = false;
  while (a.length != 0){
    var item = a.shift();
    if(ret.length > 0){
      for(var i = 0; i < ret.length; i++){
        if(ret[i].type == item.type){
          ret[i].value.push(item.value);
          same_type = true;
        }
      }
    }
    if(!same_type){
      ret.push({type : item.type, value : [item.value]});
    }
    same_type = false;
  }
  return ret;
}

The output array that you will get is like this:

[ 
  { type: 'a', value: [ '234', '5566' ] },
  { type: 'b', value: [ '778' ] },
  { type: 'c', value: [ '899' ] },
  { type: 'k', value: [ '5644' ] } 
]

And from there, do the iteration like this:

<div ng-repeat="obj in array">
  <h3 ng-bind="obj.type"></h3>
  <div ng-repeat="v in obj.value">
    <span ng-bind="v"></span>
  </div>
</div>

Hope it helps.

Upvotes: 1

Claies
Claies

Reputation: 22323

The easiest way to achieve the result you are looking for is to use underscore.js _.groupBy http://underscorejs.org/#groupBy. This will require changing the iterators slightly as well.

Using $scope.groups = _.groupBy($scope.array, "type");, we get:

{
  "a": [{
    "type": "a",
    "value": "234"
  }, {
    "type": "a",
    "value": "5566"
  }],
  "b": [{
    "type": "b",
    "value": "778"
  }],
  "c": [{
    "type": "c",
    "value": "899"
  }],
  "k": [{
    "type": "k",
    "value": "5644"
  }]
}

Using ng-repeat, we would not get the exact result expected. However, we can use the (key, value) variation of ng-repeat to achieve the result we are looking for, something like this:

<div ng-repeat="(type, values) in groups">
  <h3 ng-bind="type"></h3>
  <span ng-repeat="v in values">
        <span ng-bind="v.value"></span>
  </span>
</div>

Full Example:

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

app.controller('MainCtrl', function($scope) {
  $scope.array = [{
    type: 'a',
    value: '234'
  }, {
    type: 'a',
    value: '5566'
  }, {
    type: 'b',
    value: '778'
  }, {
    type: 'c',
    value: '899'
  }, {
    type: 'k',
    value: '5644'
  }];

  $scope.groups = _.groupBy($scope.array, "type");
  console.log($scope.groups);
});
<script data-require="[email protected]" src="https://code.angularjs.org/1.4.8/angular.js" data-semver="1.4.8"></script>
<script data-require="[email protected]" data-semver="1.8.3" src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>

<html ng-app="stackExample">

<body ng-controller="MainCtrl">
  <div ng-repeat="(type, values) in groups">
    <h3 ng-bind="type"></h3>
    <span ng-repeat="v in values">
        <span ng-bind="v.value"></span>
    </span>
  </div>
</body>

</html>

Upvotes: 2

MasoodRehman
MasoodRehman

Reputation: 715

I think you have to do some coding for it in your controller to provide a filtered dataSet to ngRepeat.

        var dataSet = [
            {type:'a', value:'234'}, 
            {type:'a', value:'5566'}, 
            {type:'b', value:'778'}, 
            {type:'c', value:'899'}, 
            {type:'k', value:'5644'}
        ];

        var filteredDataSet = new Array();
        dataSet.forEach(function(dataObj){
            var tempObject = {};
            tempObject.type  = dataObj.type;
            tempObject.value = new Array(dataObj.value);

            var duplicate_key = false;
            if (filteredDataSet.length){
                filteredDataSet.forEach(function(iObj){
                    // Push value into a value array of filteredDataSet 
                    // and make the flag duplicate_key value to true to 
                    // prevent the insertion of duplicate object into a 
                    // filteredDataSet array.
                    if (dataObj.type == iObj.type){
                        iObj.value.push(dataObj.value);
                        duplicate_key = true;
                    }
                });
            }
            // Push non duplicate object by key into a filteredDataSet array
            if (duplicate_key == false){
                filteredDataSet.push(tempObject);
            }
        });

        $scope.dataSet = filteredDataSet;

And here is your HTML

<div ng-repeat="dataObj in dataSet">
    <h1>{{dataObj.type}}</h1> 
    <div ng-repeat="val in dataObj.value">
        <h3>{{val}}</h3>
    </div>
</div>

I hope it solve your problem, modification into this code will be highly appreciated thanks.

Upvotes: 0

RIYAJ KHAN
RIYAJ KHAN

Reputation: 15292

You need angular-filter.

You can do like this

<div ng-repeat="obj in array | unique:'type' ">
    <h3 ng-bind="obj.type"></h3>
    <span ng-bind="obj.name"></span>
</div>

Define your app module like this.

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

I have used angular-filter.min.js

Upvotes: 0

Related Questions