7

I have a JSON object representing calendar dates. These are added through a CMS and I'd like to be able to filter them based on date. My schema set-up has made this more difficult than I thought. Is it possible to orderBy the day value in this JSON object or is there a filter workaround?

Here is my JSON object:

{
"_id" : ObjectId("53f252537d343a9ad862866c"),
"year" : {
    "December" : [],
    "November" : [],
    "October" : [],
    "September" : [],
    "August" : [],
    "July" : [ 
        {
            "day" : "21",
            "title" : "Event Title",
            "summary" : "Event Summary",
            "description" : "oEvent Description",
            "_id" : ObjectId("53f252537d343a9ad862866d")
        }
    ],
    "June" : [],
    "May" : [],
    "April" : [],
    "March" : [],
    "February" : [],
    "January" : []
},
"__v" : 0
}

Here is my view which already uses a custom filter to filter by month. The orderBy is not functioning but I've left it in as a placeholder to show where I'd like to set the functionality.

<div class="calDynamic" data-ng-repeat="n in [] | range:100">
<div ng-repeat="cal in calendar[n].year | filterKey:month">
  <div ng-if="cal != '' ">
    <div class="calendar">


    <div ng-repeat="item in cal | orderBy: 'key.day' ">

        <a href="/events/{{item.day}}">
          <article class="eventslist">
           <div class="numberedDate">
               <h3>{{item.day}}</h3>
            </div>
            <div class="calInfo">
               <h5>{{item.title}}</h5>
               <p>{{item.summary}}&nbsp;<a>more</a></p>
            </div>
           </article>


      </div><!-- ng-repeat val,key -->
</div><!-- calendar -->
</div><!-- ng-if cal -->
</div><!-- ng-repeat cal -->
</div><!-- calDynamic -->
byrdr
  • 5,197
  • 12
  • 48
  • 78

1 Answers1

16

You should be able to define a custom sort function that sorts by any item in your object. The key bit is to convert the object to an array in the filter function.

Here's an example:

app.filter('orderByDayNumber', function() {
  return function(items, field, reverse) {
    var filtered = [];
    angular.forEach(items, function(item) {
      filtered.push(item);
    });
    filtered.sort(function (a, b) {
      return (a[field] > b[field] ? 1 : -1);
    });
    if(reverse) filtered.reverse();
    return filtered;
  };
});

You would then call it like this:

<div ng-repeat="(key, val) in cal | orderByDayNumber: 'day' ">

Note, you shouldn't write val.day as that is assumed.

Look at this great blog post here for more info.

EDIT: In fact, it looks like your structure is actually already an array, so while this technique will still work, it may not be necessary - it might have just been the way you were adding the parameter to orderBy that was causing issues.

Vadim
  • 8,701
  • 4
  • 43
  • 50
Caspar Harmer
  • 8,097
  • 2
  • 42
  • 39
  • Did you mean to write `orderByDayNumber` in the filter instead of `orderBy`? – General_Twyckenham Aug 19 '14 at 03:13
  • It's not working with my app. The logic makes sense though, I'll post the answer when I figure out why it isn't working. – byrdr Aug 19 '14 at 03:26
  • it looks like I'm returning lines of objects. 'item' returns {"day":"21","title":"ok","summary":"ok","description":"ok","_id":"53ee9f0fc6aed109c6d33cfd"}. Would it be possible to push these into an array to filter from? – byrdr Aug 19 '14 at 03:55
  • If you could put up a plnkr or a jsfiddle up with the data, then I'll see if I can get it working. The easiest way to do this is to find a plnkr or jsfiddle with a working codebase and fork it and add your changes. Try this one: http://jsfiddle.net/rapsac/sfzt3562/ – Caspar Harmer Aug 19 '14 at 05:31
  • I've added a jsfiddle...my scope variables are not returning for some reason right now, but this is the gist of the app. http://jsfiddle.net/rtbyrd21/sfzt3562/21/ – byrdr Aug 19 '14 at 13:52
  • (The link to the blog post is the same as the link you provided) – Caspar Harmer Jun 24 '15 at 20:40
  • This removes the key, how can I still keep the key? – mXX Feb 06 '17 at 09:23