使用KnockoutJS按日期对事件进行分组

本·塞沃斯(Ben Sewards)

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


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


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

AJAX调用和requireJS模块加载: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();
    }
};

视图模型

// 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转换)。我现在必须更新视图以查看其是否有效。

本·塞沃斯(Ben Sewards)

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

FullCalendar: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>

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章