How to keep data "reactive" when creating an array from a collection
I am integrating fullCalendar in my meteor app. fullCalendar expects a special data format . I can create this data from my collection. However, the data is no longer reactive.
How can I make the data that I have translated from my collection into an array "reactive"?
Thank.
Html client:
<template name="carpool_calendar">
<div id="calendar"></div>
</template>
JS client:
Template.carpool_calendar.rendered = function () {
//initialize the calendar in this template
$('#calendar').fullCalendar({
events: function(start, end, callback) {
var events = [];
var calendarEvents = Carpool_Events.find();
calendarEvents.forEach(function (carpool_event) {
events.push({
title: carpool_event.owner,
start: carpool_event.eventDate
});
console.log("Event owner " + ": " + carpool_event.owner);
});
callback(events);
},
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay'
},
weekends: false, // will hide Saturdays and Sundays
editable: true
});
};
Updated client JS (this is not entirely true yet. Its recreating the calendar every time the data changes ... the page gets bigger and longer with new calendar instances):
Template.carpool_calendar.rendered = function () {
Meteor.autorun(function() {
//initialize the calendar in this template
$('#calendar').fullCalendar({
events: function(start, end, callback) {
var events = [];
var calendarEvents = Carpool_Events.find();
calendarEvents.forEach(function (carpool_event) {
events.push({
title: carpool_event.owner,
start: carpool_event.eventDate
});
console.log("Event owner " + ": " + carpool_event.owner);
});
callback(events);
},
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay'
},
weekends: false, // will hide Saturdays and Sundays
editable: true
});
})};
JS client Fully working "reactive" fullcalendar:
Template.carpool_calendar.rendered = function () {
//initialize the calendar in this template
$('#calendar').fullCalendar({
events: function(start, end, callback) {
var events = [];
var calendarEvents = Carpool_Events.find();
calendarEvents.forEach(function (carpool_event) {
events.push({
title: carpool_event.owner,
start: carpool_event.eventDate
});
console.log("Event owner " + ": " + carpool_event.owner);
});
callback(events);
},
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay'
},
weekends: false, // will hide Saturdays and Sundays
editable: true
});
Meteor.autorun(function() {
var calendarEvents = Carpool_Events.find();
$('#calendar').fullCalendar('refetchEvents');
});
};
source to share
Like TimDog, you cannot give a UI element a reactive array and let it take care of the rest. But another option is you can use Meteor.autorun
, so when your collection changes, it can call a JS function to create an updated array, thus making it somewhat reactive.
I'm not sure how to use this calendar exactly, but adding this client side code might help.
Meteor.autorun(function() {
calendarEvents = Carpool_Events.find();
$('#calendar').fullCalendar({
events: function(start, end, callback) {
var events = [];
calendarEvents.forEach(function (carpool_event) {
events.push({
title: carpool_event.owner,
start: carpool_event.eventDate
});
});
callback(events);
}
});
});
source to share
This is part of a larger question about how to properly create UI components for Meteor that provide reactive data contexts. This is a very good question and one that has been asked before .
The short answer is that there is no standardized framework yet - like the Meteor.UI smart package. In the meantime, your best bet is to hack the fullCalendar widget using the <{# each}} source helper as a guide. You want to pay attention to how the items are tagged with Spark :
'each': function (data, options) {
var parentData = this;
if (data && data.length > 0)
return _.map(data, function(x, i) {
// infer a branch key from the data
var branch = (x._id || (typeof x === 'string' ? x : null) ||
Spark.UNIQUE_LABEL);
return Spark.labelBranch(branch, function() {
return options.fn(x);
});
}).join('');
else
return Spark.labelBranch(
'else',
function () {
return options.inverse(parentData);
});
},
source to share