简体   繁体   中英

How can I sort a firebase angularfire array into weeks and days?

I'm working on a todo list that groups tasks by week (based on added and completion dates) and groups tasks by the days of the week. The database structure looks like this:

users
  userA
    tasks
      taskobject1
      taskobject2
      ..
  userB
    tasks
      taskobject1
      task object2

I'm using an ng-repeat to display all the tasks to the view for each user. I would like to be able to sort them first by which week they fall into and then like this:

#week1
--monday--
task a
task b
--tuesday--
task c
task d
..
#week2
--monday--
task a
..

Even a conceptual answer would be helpful. I don't know where to start exactly.

Thanks.

See also this post, which provides a directive to do this grouping: Is it possible to .sort(compare) and .reverse an array in angularfire?

There are a few approaches you could take here.

Data Structured by Date

If the records will always be fetched by this structure, you can just store them that way;

/users/usera/tasks/week1/monday/taska/...

Then you can simply fetch them at the tasks level as an object, and you will obtain a pre-sorted JSON object with values nested at the appropriate levels.

This approach is not highly compatible with AngularFire, which is intended for binding objects or collections, not nested trees of data, but should work with some care.

Using Priorities

A second approach would be to add priorities on to the tasks, which would be an epoch timestamp. Now when you want to fetch them, you can startAt/endAt specific points in the tree, and get the records. Each will have a timestamp on it you can use to identify the week and day.

var ref = new Firebase(ref).startAt(twoWeeksAgo).endAt(nextThursday);
$scope.list = $fireabse(ref).$asArray();

However, this does not segment the entries. You would need to either examine each entry in the ng-repeat and add headers on the fly:

// in the controller
var last = null;
$scope.priorityChanged(priority) {
   /** 
    * here we would use a library like moment.js to parse the priority as a date
    * and then do a comparison to see if two elements are for the same day, such as 
    **/
   var current = moment(priority).startOf('day');
   var changed = last === null || !last.isSame(current);
   last = current;
   return changed;
};

$scope.getDayName = function($priority) {
   return moment($priority).format('dddd');
};

<!-- in the view -->
<li ng-repeat="item in list" ng-init="changed = priorityChanged(item.$priority)">
   <h3 ng-show="changed">{{getDayName(item.$priority)}}</h3>
   {{item|json}}
</li>

This approach is readily compatible with AngularFire.

Roll Your Own List

A last approach would be to cut out AngularFire and roll your own. For example, if we have the week and weekday stored on each task, we could do the following:

app.service('DatedList', function($timeout) {
   return function(pathToList) {
      var list = {};

      pathToList.on('child_added', function(snap) {
         $timeout(function() { // force Angular to run $digest when changes occur
            var data = snap.val();
            var week_number = data.week;
            var week_day = data.day;
            list[week_number][week_day] = data;
         });
      });

      //todo: write similar processing for child_changed and child_removed

      return list;
   }
});

app.controller('ctrl', function($scope, DatedList) {
   var listRef = new Firebase(URL).limit(500);
   $scope.weeks = DatedList(listRef);
});

<div controller="ctrl">
  <div ng-repeat="(week, days) in weeks">    
     <h1>{{week}}</h1>
     <div ng-repeat="(day, items) in days">
        <h2>{{day}}</h2>
        <div ng-repeat="item in items">
           {{item|json}}
        </div>
     </div>
  </div>
</div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM