是否可以在 angularfire 中对数组进行 .sort(compare) 和 .reverse? [英] Is it possible to .sort(compare) and .reverse an array in angularfire?

查看:19
本文介绍了是否可以在 angularfire 中对数组进行 .sort(compare) 和 .reverse?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Update: The problem I'm having is doing a combination of three things:

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

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

Here is a plnkr of all the code: http://plnkr.co/edit/A8lDKbNvhcSzbWVrysVm

我正在使用 priorityChanged 函数根据比较任务的日期添加标题://控制器var last = null;$scope.priorityChanged = 函数(优先级){var current = moment(priority).startOf('day');var 已更改 = 最后一次 === null ||!last.isSame(当前);最后=当前;退货变了;};

I'm using a priorityChanged function to add a header based on comparing the dates on a task: //controller var last = null; $scope.priorityChanged = function(priority) { var current = moment(priority).startOf('day'); var changed = last === null || !last.isSame(current); last = current; return changed; };

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

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

and to move a task to the bottom of the list when a task is completed I am using a .sort function when I populate the task list:

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 将再次运行任务并添加必要的标题?这是理想的解决方案吗?标题可以分开吗?

It seems as though these approaches will not work together. Is there a way of combining them so that when the list is re-sorted the ng-repeat will run through the tasks again and add the necessary headers? Is that the ideal solution? Can the header be separate?

更新:我将 ng-init 功能直接移到 h3 中以尝试让它再次运行,但在这种情况下它不显示标题.

Update: I moved the ng-init functionality directly into the h3 to try to get that to run again but it does not display the header in that case.

Update2:如果至少两个 $priority 日期是唯一的,则标题似乎确实显示,但我仍然遇到删除或移动关联列表项以删除连接标题的问题.

Update2: The header does seem to show up if at least two of the $priority dates are unique but I still have the problem of deleting or moving the associated list item removing the connected header.

推荐答案

使用指令

您可以创建指令以通过嵌套客户端内容来简化事情.演示

You can create a directive to simplify things by nesting your client contents. 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 模板:

The repeat.html template:

<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 中移出.我不认为当元素移动/移动时会重新运行.

Most likely, you just need to move your changed out of ng-init. I don't think that is re-run when elements move/resort.

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

由于您的列表可能会多次使用,您可能还可以通过 使用跟踪

Since your list may resort several times, you can probably also get a pretty significant speed boost by using track by

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

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

If that doesn't resolve the problem, it might be time to think about writing your own directive (these are more fun than they sound) and possibly to consider setting aside AngularFire and going right to the source.

您真的想要一个更深层嵌套的数据结构,您可以在多个级别迭代,并且您可能需要自己在客户端或服务器上构建它,现在您已经了解了如何组织它们(本质上是按周分组的功能).

You really want a more deeply nested data structure here you can iterate at multiple levels, and you may need to structure that yourself either on the client or the server, now that you have a sense of how you want them organized (essentially a group by week functionality).

这篇关于是否可以在 angularfire 中对数组进行 .sort(compare) 和 .reverse?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆