使用KnockoutJS按日期对事件进行分组 [英] Group Events by Date using KnockoutJS

查看:78
本文介绍了使用KnockoutJS按日期对事件进行分组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新:我为我的问题提供了最佳答案.随时提高可读性和/或效率.

Update: I provided a best answer to my problem. Feel free to improve the readability and/or efficiency.


问题:在我的requireJS设置中使用fullcalendar.io,每次下一个/上一个/视图更改时,都会在日历上填充事件对象(从AJAX调用.ashx处理程序接收).我想在回调中使用该JSON对象来创建按startDate属性分组的事件列表.


Problem: Using fullcalendar.io in my requireJS set up, Event objects (received from an AJAX call to a .ashx handler) are populated on the calendar on every next/prev/view change. I would like to use that JSON object on callback to create a list of Events grouped by the startDate property.

我做了什么
在日历更新(例如新月)上,我能够设置基本的ViewModel,以可观察数组填充事件的新列表.唯一缺少的部分是分组依据,例如示例.由于我希望按事件对象的开始日期进行分组,然后按开始日期升序对每个组进行排序,因此我不确定应该采用的最佳做法,例如是否有必要将JSON数据转换为对象.当我了解更多信息时,我将继续更新此帖子.我之所以不使用链接的示例,是因为我不了解处理程序背后的完整术语,但此时确实了解了诸如$ root之类的一些关键字.

What I've done
On Calendar update, such as new month, I was able to set up a basic ViewModel to populate a new list of events with the observable array. The only part that is missing is the group by, such as this example. Since I'm looking to group by an Event object's start date and then sort each group ascending by start date, I'm not sure of the best practices I should take, such as if it is necessary to transform my JSON data into objects. I will continue to update this post as I learn more. The reason that I am not using the linked example is because I do not understand the complete terminology behind the handler, but do understand some keywords like $root at this point.

AJAX调用并要求JS模块加载:fullcalendar

AJAX call and requireJS module load: fullcalendar

var fullCalendar = ".calendar-module",
    viewModel;

function initFullCalendar() {
    $(fullCalendar).fullCalendar({
            events: {
                url: '/Presentation/DotGov/test/fullcalendar/GetEvents.ashx',
                type: 'POST',
                success: function (data) {

                    // bind events to KO ViewModel object
                    viewModel.events(data);
                }
            },
    });
}

// requireJS module load
return {
    load: function () {

        viewModel = new ViewModel();
        ko.applyBindings(viewModel);

        initFullCalendar();
    }
};

ViewModel

// Day constructor that holds the day title and an array of event objects
var Day = function() {
    dayTitle = null,
    events = []
}

function ViewModel() {
    var self = this;

    self.dates = ko.observableArray();
    self.events = ko.observableArray();

    self.uniqueDates = ko.computed(function () {
        var allDates = ko.utils.arrayMap(self.events(), function (event) {
            return new XDate(event.start).toDateString();
        });
        return ko.utils.arrayGetDistinctValues(allDates);
    }, ViewModel);

    // TODO: groupedEvents { date: /.., events: [..]}
    self.groupedEvents = ko.computed(function () {

        var groupedEvents = [];
        var uniqueDates = self.uniqueDates();

        for (var i = 0; i < uniqueDates.length; i++) {
            // create new day object
            var day = new Day();
            day.dayTitle = uniqueDates[i];
            day.events = [];

            // get all events within that day
            ko.utils.arrayForEach(self.events(), function (event) {
                var eventDate = new XDate(event.start).toDateString();
                if (eventDate == uniqueDates[i]) {
                    day.events[day.events.length] = event;
                }
            });
            groupedEvents[groupedEvents.length] = day;
        }
        return groupedEvents;
    });
}

查看

<div class="calendar-module-mobile">
    <div class="day-wrapper">
        <p class="day-title">Monday, April 16, 2014</p>   <%--the event startDate--%>
        <div class="mobile-block">
            <ul data-bind="foreach: events">
                <li>
                    <a data-bind="attr: { href: eventUrl }">
                        <p data-bind="text: title"></p>
                        <span class="icon-chevron-right turquoise-icon"></span>
                    </a>
                </li>
            </ul>
        </div>
    </div>
</div>

更新 我已经用一些计算得到的可观察函数更新了ViewModel. self.groupedEvents 遍历唯一日期列表,并返回一个Day对象数组,其中的每个Day对象都包含唯一的日期标题和一个Event对象数组(不是从JSON转换).我现在必须更新视图以查看其是否有效.

Update I've updated the ViewModel with some computed observable functions. self.groupedEvents goes through the list of unique dates and returns an array of Day objects, in which each Day object contains the unique dates title and an array of Event objects (not transformed from JSON). I have to now update the View to see if it worked.

推荐答案

在这里回答我自己的问题,而不是继续更新问题.随时留下答案,如果我认为这是一个更好的解决方案,我将为它提供最佳答案.

Answering my own question here instead of continuing to update the question. Feel free to leave an answer, and if I think it is a better solution, I will give it best answer.

全日历:AJAX调用和事件

$(fullCalendar).fullCalendar({
    header: {
        left: '',
        center: 'month,agendaWeek,agendaDay',
        right: 'prev,title,next'
    },
    titleFormat: {
        agendaWeek: "(M/DD/YYYY)",
        agendaDay: "dddd MMMM D, YYYY"
    },
    minTime: "07:00:00",
    maxTime: "19:00:00",
    fixedWeekCount: false,
    allDaySlot: false,
    editable: false,
    eventLimit: {
        'month': 3,
        'default': true  // gives default value to other views
    },
    events: {
        url: '/Presentation/test/fullcalendar/GetEvents.ashx',
        type: 'POST',
        success: function (data) {

            // don't render event if not in month (sometimes events at end or beggining of prev/next month are rendered)
            for (var i = 0; i < data.length; i++) {
                if ((new Date(data[i].start).getUTCMonth()) != (new Date($(fullCalendar).fullCalendar('getView').start).getUTCMonth())) {
                    data.splice(i, 1);
                }
            }

            //var parsed = JSON.parse(data);
            viewModel.events(data);     // bind events to KO ViewModel
        }
    },
    /* event handlers */
    eventClick: function(calEvent, jsEvent, view) {

        // hide all overlays initially
        $('.fc-event').find('.overlay').fadeOut();

        var $overlay = $(jsEvent.currentTarget).find('.overlay');
        $overlay.show();

        jsEvent.stopPropagation();
        return false;
    },
    eventRender: function (event, element, view) {    // also fired on loading the eventLimit popup.. so check event

        // if initially loading event on view
        if (event.startDisplayDate == undefined) {
            // format start and end dates
            event.startDisplayDate = new XDate(event.start._i).toString("ddd, MMMM d, h(:mm)tt");
            event.endDisplayDate = new XDate(event.end._i).toString("ddd, MMMM d, h(:mm)tt");
        } else
        {
            // rendering event again, but inside limitclick popover (TODO: find better way)
            event.overlayClasses = "position-left";
        }

        element.append(popupTemplate(event));
    },
    viewRender: function (view, element) {
        $(fullCalendar).fullCalendar('refetchEvents');  // refetch events on view change
    }
});

ViewModel和对象

var Event = function (event) {
    this.eventID = event.id;
    this.eventTitle = event.title;
    this.startDate = event.start;
    this.startHour = new XDate(event.start).toString("(h:mm)t");
    this.endDate = event.end;
    this.eventUrl = event.eventUrl;
}

// Day constructor that holds the day title and an array of event objects
var Day = function() {
    dayTitle = null,
    events = []
}

function ViewModel() {
    var self = this;

    self.dates = ko.observableArray();
    self.events = ko.observableArray(); // TODO: sort by date

    self.uniqueDates = ko.computed(function () {
        var allDates = ko.utils.arrayMap(self.events(), function (event) {
            return new XDate(event.start).toDateString();
        });
        return ko.utils.arrayGetDistinctValues(allDates);
    }, ViewModel);

    // groupedEvents { date: /.., events: [..]}
    self.groupedEvents = ko.computed(function () {

        var groupedEvents = [];
        var uniqueDates = self.uniqueDates();

        for (var i = 0; i < uniqueDates.length; i++) {
            // create new day object
            var day = new Day();
            day.dayTitle = uniqueDates[i];
            day.events = [];

            // get all events within that day
            ko.utils.arrayForEach(self.events(), function (event) {
                var eventDate = new XDate(event.start).toDateString();
                if (eventDate == uniqueDates[i]) {
                    day.events[day.events.length] = new Event(event);
                }
            });
            groupedEvents[groupedEvents.length] = day;
        }
        return groupedEvents;
    });
}

查看

<div class="calendar-module-mobile">
    <div data-bind="foreach: groupedEvents">
        <div class="day-wrapper">
            <p data-bind="text: dayTitle" class="day-title"></p>
            <%--the event startDate--%>
            <div class="mobile-block">
                <ul data-bind="foreach: events">
                    <li>
                        <span data-bind="text: startHour"></span>
                        <a data-bind="attr: { href: eventUrl }">
                            <p data-bind="text: eventTitle"></p>
                            <span class="icon-chevron-right turquoise-icon"></span>
                        </a>
                    </li>
                </ul>
            </div>
        </div>
    </div>
</div>

这篇关于使用KnockoutJS按日期对事件进行分组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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