1

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!

5
  • are you sure it is obj.name and not obj.value?? Commented Jan 31, 2016 at 18:04
  • And can you post the expected output that you need like in code? Commented Jan 31, 2016 at 18:06
  • If I understand what you are asking, your iteration doesn't match your described result. The iteration you are demonstrating will only ever show the first value to match a given type. It sounds more like you are wanting to group these together, which would require a second ng-repeat. Can you clarify which you are trying to achieve? Commented Jan 31, 2016 at 19:01
  • Hi. Updated my desired result. Commented Jan 31, 2016 at 19:22
  • 1
    I'm guessing that you want 234 and 5566, not 234 twice; still, it will take 2 <span> elements instead of one and another ng-repeat to accomplish something close to what you are expecting. also, it requires changing your data structure somewhat. My recommended solution is to use underscore.js to help us here; I'll work up a sample and post an answer soon. Commented Jan 31, 2016 at 20:12

4 Answers 4

2

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>

Sign up to request clarification or add additional context in comments.

4 Comments

But the OP has ask that he does not want to create another array. The answer is good but I think it can be optimized a little more.....
@dvenkatsagar quite frankly, there isn't a reasonable way to accomplish the output expected with the data in the original structure, without some intermediary data refactor. even your answer of using unique doesn't perfectly work, since it is only outputting one row for each type.
I agree, thats why Im trying to figure out how to achieve it without using any additional libraries. :)
He doesn't have to create an array that continues to exist. It can exist just for the one function. That is, instead of groups being a variable it can be a function: $scope.groups = function (array) {return _.groupBy($scope.array, "type");}; The HTML would then be: <div ng-repeat="(type, values) in groups(array)">
1

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.

2 Comments

The function is essentially what the underscorejs _.groupby function mentioned in the first answer does.
I'm just giving an approach that doesn't need the import of an entire library, just for one function
0

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

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.