Meteor:如何将结果分组到模板中?

时间:2015-12-04 16:55:09

标签: meteor meteor-blaze

我有一个应用程序,用户可以在不同的日期时间登记。我的目标是在不同的日期显示谁在那里。

类似的东西:

  

11/05:Mat,Lisa,Andrew

     14/05:丽莎

     

我看了一下$ groupby聚合,但是对于我的简单用法来说它似乎很重要。 我也可以在db.find()。fetch()上循环,但我觉得我会失去反应性。

我设法让它适用于一个简单的模板助手:

resultDate = null;

Template.result.helpers({
    date: function(){
        var date = moment(this.datetime).endOf("day").fromNow();

        if(date == resultDate)
            return false;

        resultDate = date;

        return date;
    }
}

但是正如你所看到的那样,如果我需要两次调用{{date}},那么它并不是真正的优雅方式,一切都会崩溃。

我已经找了几个小时的合适解决方案而一无所获。有什么想法吗?

谢谢!

2 个答案:

答案 0 :(得分:2)

以下是如何在您的收藏中使用此客户端并且不会失去反应性的示例。

关键问题是将一个反应数据源(集合)转换为一个对象数组,这些对象反映了所需的日期输出以及检入人员的名称。 这个数组看起来像:

[
  {date: '2015-05-11', names: ['Mat', 'Lisa', 'Andrew']},
  {date: '2015-05-14', names: ['Lisa']},
]

我假设你的收集名为Checkin,每个文档中有{2}个字段,datename

您的收藏是一个反应式数据源。您可以通过observeChanges收到有关集合更改的通知。 通过触发添加,更改和删除的事件,您可以每天通过签入重建阵列。这些事件都会调用构建实际数组的rebuildCheckinPerDay。 然后,每次重建时,该数组都会保存在ReactiveVar checkinPerDateVar中。并且因为ReactiveVar也是一个反应式数据源,每次更改reactiveVar时模板帮助器checkinPerDate都会重新运行。

构建数组由几个underscorejs函数完成。首先,集合按日期排序并以数组形式提取,然后按日期分组(时间由.endOf('day')删除),然后映射到最终结构。由于_.groupBy会将项目作为{id,name,date}返回,因此您必须使用_.pluck来提取名称。

为了转换日期和方便的模板助手来格式化日期,我使用了momentjs。要实际运行此示例,您必须包含包momentjs:momentreactive-var。 在示例中,显示完整日期。但如果您愿意,可以轻松将其转换为moment(this.datetime).endOf("day").fromNow()

完整示例:

检查-in.html。

<template name="checkinPerDate">
    {{#each checkinPerDate}}
        <div>
            {{formatDate date}} - {{names}}
        </div>
    {{/each}}
</template>

检查-in.js。

Template.registerHelper('formatDate', function(date) {
    return moment(date).format('DD-MM-YYYY');
});

// Reactive variable to hold the array with names per check-in day
var checkinPerDateVar = new ReactiveVar([]);

// Build the array with check-ins per day that mirror the final view in the template
var rebuildCheckinPerDay = function() {
    var checkinPerDateArray = _.map(
        _.groupBy(Checkin.find({}, {sort: {date : 1}}).fetch(), function(item) {
            return moment(item.date).endOf('day');
        }), function(dateItem, date) {
            return {date: date, names: _.pluck(dateItem, 'name')};
        });
    checkinPerDateVar.set(checkinPerDateArray);
}

Template.checkinPerDate.onCreated(function() {
    this.subscribe('checkin', function() {
        var cursor = Checkin.find();
        var handle = cursor.observeChanges({
            added: function (id, checkin) {
                console.log('added ', id, JSON.stringify(checkin));
                rebuildCheckinPerDay();
            },
            changed: function (id, checkin) {
                console.log('changed ', id, JSON.stringify(checkin));
                rebuildCheckinPerDay();
            },
            removed: function (id) {
                console.log('removed ', id);
                rebuildCheckinPerDay();
            }
        });
    });
});

Template.checkinPerDate.helpers({
    // This helper function is reactive because of the use of reactive variable checkinPerDateVar.
    // It gets rerun each time the variable was changed
    checkinPerDate: function () {
        var checkinPerDateArray = checkinPerDateVar.get();
        return checkinPerDateArray;
    }
});

答案 1 :(得分:0)

感谢Jos的回答,但对于我的简单需求,它看起来仍然很重要,这与HTML格式化相关,而不是对象操作。我认为你的答案很适合对请求的复杂处理,但在我的情况下,我只需要显示日期排序记录的日期,而不是在同一天重复。

所以,我制定了我的初始辅助函数,我想我找到了一个更好的方法:

var resultDateVar = [];

Template.result.helpers({
    date: function(){
        if(!resultDateVar[this._id]){
            var date = moment(this.datetime).endOf("day").fromNow();

            resultDateVar[this._id] = (resultDateVar.last == date)? false : date;
            resultDateVar.last = date;
        }

        return resultDateVar[this._id]
    }
});

我希望它会有所帮助:)