一尘不染

是否可以在angularfire中对数组进行.sort(compare)和.reverse吗?

angularjs

更新:我遇到的问题是三件事的结合:

  1. 当$ priority(设置为创建日期)更改时,向数组添加标头。这样一来,我就可以按ng-repeat按周和日对任务进行分组。
  2. 检查任务时重新使用该列表。已检查的任务应转到底部。
  3. 创建新任务时,我需要将它们添加到列表的顶部而不是底部。

这是所有代码的plnkr:http
://plnkr.co/edit/A8lDKbNvhcSzbWVrysVm

我正在使用priorityChanged函数基于比较任务上的日期来添加标头:// controller var last = null; $
scope.priorityChanged = function(priority){var current =
moment(priority).startOf(’day’); varchanged = last === null ||
!last.isSame(current); 最后=当前;返回更改;};

//view
<li ng-repeat="task in list track by task.$id">
  <h3 ng-show="priorityChanged(task.$priority)">{{getDayName(task.$priority)}}</h3>

并在完成任务时将任务移到列表的底部,当我填充任务列表时,我正在使用.sort函数:

var populateTasks = function(start, end) {
    $scope.start = start;
    $scope.end = end;
    var ref = new Firebase('https://plnkr.firebaseio.com/tasks').startAt(start).endAt(end);
    var list = $firebase(ref).$asArray();

    list.sort(compare);

    list.$watch(function() {
      list.sort(compare);
    });

    function compare(a, b) {
      return a.completeTime - b.completeTime;
    }

    $scope.list = list;

  };

这些方法似乎无法一起使用。有没有一种将它们组合在一起的方法,以便当列表重新排序时,ng-
repeat将再次运行任务并添加必要的标头?那是理想的解决方案吗?标头可以分开吗?

更新:我将ng-init功能直接移到了h3中,试图使其再次运行,但是在这种情况下,它不显示标题。

Update2:如果至少两个$ priority日期是唯一的,则标题似乎确实会出现,但是我仍然存在删除或移动关联列表项以删除连接的标题的问题。


阅读 217

收藏
2020-07-04

共1个答案

一尘不染

使用指令

您可以通过嵌套客户端内容来创建指令以简化操作。
demo

app.directive('repeatByWeek', function($parse, $window) {
  return {
    // must be an element called <repeat-by-week />
    restrict: 'E',
    // replace the element with template's contents
    replace: true,
    templateUrl: 'repeat.html',
    // create an isolate scope so we don't interfere with page
    scope: {
      // an attribute collection="nameOfScopeVariable" must exist
      'master': '=collection'
    },
    link: function(scope, el, attrs) {
      // get the global moment lib
      var moment = $window.moment;
      scope.weeks = [];
      updateList();

      // whenever the source collection changes, update our nested list
      scope.master.$watch(updateList);

      function updateList() {
         scope.weeks = sortItems(parseItems(scope.master));
      }

      function sortItems(sets) {
        var items = [];
        // get a list of weeks and sort them
        var weeks = sortDescending(Object.keys(sets));
         for(var i=0, wlen=weeks.length; i < wlen; i++) {
           var w = weeks[i];
           // get a list of days and sort them
           var days = sortDescending(Object.keys(sets[w]));
           var weekEntry = { 
             time: w, 
             days: []
           };
           items.push(weekEntry);
           // now iterate the days and add entries
           for(var j=0, dlen=days.length; j < dlen; j++) {
             var d = days[j];
             weekEntry.days.push({
               time: d,
               // here is the list of tasks from parseItems
               items: sets[w][d]
             });
           }
         }
         console.log('sortItems', items);
         return items;
      }

      // take the array and nest it in an object by week and then day
      function parseItems(master) {
        var sets = {};
        angular.forEach(master, function(item) {
           var week = moment(item.$priority).startOf('week').valueOf()
           var day = moment(item.$priority).startOf('day').valueOf();
           if( !sets.hasOwnProperty(week) ) {
             sets[week] = {};
           }
           if( !sets[week].hasOwnProperty(day) ) {
             sets[week][day] = [];

           }
           sets[week][day].push(item);
         });
         console.log('parseItems', sets);
         return sets;
      }

      function sortDescending(list) {
        return list.sort().reverse();
      }
    }
  }
});

repeat.html模板:

<ul>
    <!-- 
      it would actually be more elegant to put this content directly in index.html
      so that the view can render it, rather than needing a new directive for
      each variant on this layout; transclude should take care of this but I
      left it out for simplicity (let's slay one dragon at a time)
    -->
    <li ng-repeat="week in weeks">
    <h3>{{week.time | date:"MMMM dd'th'" }}</h3>
    <ul>
      <li ng-repeat="day in week.days">
        <h4>{{day.time | date:"MMMM dd'th'" }}</h4>
        <ul>
          <li ng-repeat="task in day.items">
            <input type="checkbox" ng-model="task.complete" ng-change="isCompleteTask(task)">
            <input ng-model="task.title" ng-change="updateTask(task)">
            <span ng-click="deleteTask(task)">x</span>
          </li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

其他想法

最有可能的是,您只需要将所做的更改从ng-init中移出即可。我认为元素移动/重新排序时不会重新运行。

<li ng-repeat="task in list">
  <h3 ng-show="priorityChanged(task.$priority)">{{getDayName(task.$priority)}}</h3>
  <!-- ... -->
</li>

由于您的列表可能会重复几次,因此通过使用track by可能也可以大大提高速度

<li ng-repeat="task in list track by task.$id">

如果那不能解决问题,那么可能是时候考虑编写自己的指令了(这些指令听起来比听起来更有趣),并可能考虑搁置AngularFire并转到源代码。

您确实想要一个更深层嵌套的数据结构,可以在多个层次上进行迭代,并且您可能需要自己在客户端或服务器上进行结构化,因为您已经了解了如何组织它们(基本上是按组周功能)。

2020-07-04