2

The goal is to create this

<h3>11.4.2013</h3>
<ul>
 <li>entry 1</li>
 <li>entry 2</li> 
 <li>entry 3</li>
</ul>

<h3>10.4.2013</h3>
<ul>
 <li>entry 4</li>
 <li>entry 5</li> 
 <li>entry 6</li>
</ul>

from this

[
    {
        "name": "entry1",
        "date": "11.4.2013"
    },
    {
        "name": "entry2",
        "date": "11.4.2013"
    },
    {
        "name": "entry3",
        "date": "11.4.2013"
    },
    {
        "name": "entry4",
        "date": "10.4.2013"
    },
    {
        "name": "entry5",
        "date": "10.4.2013"
    },
    {
        "name": "entry6",
        "date": "10.4.2013"
    }
]

The problem is that ng-repeat would have to be on li so I wouldn't never be able to do this using ng-repeat, is that right? I found this http://jsfiddle.net/mrajcok/CvKNc/ example from Mark Rajnoc, but it's still pretty limiting..

What other choices do I have? Write my own ng-repeat like directive? Or is there another way to do it without writting one?

2
  • Lets look at this another way. If you werent using Angular, how would you do this? Is it possible to display it the way you want without transforming the data? Commented Apr 11, 2013 at 8:22
  • If I werent using angular, I'd do it like this jsfiddle.net/zNW54 or similar Commented Apr 11, 2013 at 8:42

2 Answers 2

7

You could write your own filter that filters out the unique dates for an outer ng-repeat, something like:

filter('unique',function(){
  return function(items,field){
    var ret = [], found={};
    for(var i in items){
      var item = items[i][field];
      if(!found[item]){
        found[item]=true;
        ret.push(items[i]);
      }
    }
    return ret;
  }
});

with the following markup:

<div ng-repeat="dateItem in items | unique:'date' | orderBy:'date'">
<h3>{{dateItem.date}}</h3>
<ul>
  <li ng-repeat="item in items | filter:dateItem.date">
    {{item.name}}
  </li>
</ul>  
</div>

Have a look at this working plnkr example -- or this updated example with adding items

However, if your going to have a lot of items (hundreds or thousands) this solution is not the most optimal. An alternative approach would be to create a more optimal data structure. You can even get this to work with your original data structure by adding a $watch - something like:

$scope.$watch('items',function(){
  var itemDateMap = {};

  for(var i=0; i<$scope.items.length; i++){
    var item = $scope.items[i], key = item.date;
    if(!itemDateMap[key]){
      itemDateMap[key] = [];
    }
    itemDateMap[key].push(item);
  }

  $scope.itemDateMap=itemDateMap;


},true);

Works with this markup:

<div ng-repeat="(date,subItems) in itemDateMap">
<h3>{{date}}</h3>
<ul>
  <li ng-repeat="item in subItems">
    {{item.name}}
  </li>
</ul>  
</div>

Here is an example where you can add lots of random items.

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

7 Comments

Wait, since when can you use ng-repeat as an element? Anyway how is this performace wise? Wouldn't it be better to to transform the data structure on init like this jsfiddle.net/x4sTr? Also one important thing is though, that I'm gonna be editing and adding new entries on the fly..
adding definitely works plnkr.co/edit/Bkgd4V7y3Eg1qhaeyVAN?p=preview I'm still a little bit concerned with performace though..
Sorry, you can't use ng-repeat as an element. But you can use it with any element, so it works - but it's a bad example. I've changed it to a div. Performance wise you should be fine, unless you have a very very large collection. If you don't mind a new data structure you can do a transformation in an init function. But with my approach you don't have to do that, and you can add more items to the original collection easily - see an updated example.
Ha :) well there's going to be possibly up to.. 400 entries.. each entry will have additional filters on them..
Also that date's also got time, so I won't be able to filter items as easily.. I'm just gonna accept your answer, it's not really gonna help me, but it's probably the right asnwer to what I asked.
|
1

When I have same needs like yours, I used Object instead of Array.

<div ng-repeat="item in data">
  <h1>{{item.date}}</h1>
  <ul ng-repeat="name in item.names">
    <li>{{name}}</li>
  </ul>
</div>

http://jsfiddle.net/shoma/DqDsE/1/

This question page would help you.

What are the nuances of scope prototypal / prototypical inheritance in AngularJS?

1 Comment

The problem is you a) can't order objects b) can't easily push() into them. Other than that it's similar to transformation I described here stackoverflow.com/questions/15943193/… but not sure it's gonna work as you edit or add new items(without having to rebuild the whole array/object again)..

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.