更新:我遇到的问题是三件事的结合:
这是所有代码的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日期是唯一的,则标题似乎确实会出现,但是我仍然存在删除或移动关联列表项以删除连接的标题的问题。
使用指令
您可以通过嵌套客户端内容来创建指令以简化操作。 demo
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并转到源代码。
您确实想要一个更深层嵌套的数据结构,可以在多个层次上进行迭代,并且您可能需要自己在客户端或服务器上进行结构化,因为您已经了解了如何组织它们(基本上是按组周功能)。