Full Calendar to remember selected view and date range - fullcalendar

I would like the Full calendar scheduler to remember the current view and date range. I've got the view working, but it always defaults to the current date.
Code snippet:
var defaultView = (localStorage.getItem("fcDefaultView") !== null ? localStorage.getItem("fcDefaultView") : "timelineFiveDays");
var defaultStartDate = (localStorage.getItem("fcDefaultStartDate") !== null ? localStorage.getItem("fcDefaultStartDate") : null);
var defaultEndDate = (localStorage.getItem("fcDefaultEndDate") !== null ? localStorage.getItem("fcDefaultEndDate") : null);
$('#calendar').fullCalendar(
{
defaultView: defaultView,
visibleRange:
{
start: defaultStartDate,
end: defaultEndDate
},
viewRender: function(view, element)
{
localStorage.setItem("fcDefaultView", view.name);
localStorage.setItem("fcDefaultStartDate", view.start);
localStorage.setItem("fcDefaultEndDate", view.end);
}
}
Many thanks for any help

I finally got it working by using the gotoDate
var defaultView = (localStorage.getItem("fcDefaultView") !== null ? localStorage.getItem("fcDefaultView") : "timelineFiveDays");
var defaultStartDate = (localStorage.getItem("fcDefaultStartDate") !== null ? localStorage.getItem("fcDefaultStartDate") : moment());
defaultView: defaultView,
$('#calendar').fullCalendar('gotoDate', defaultStartDate);
As mentioned by #ADyson I might try the defaultDate rather than using the goToDate method

Related

FullCalendar - Get Background event on dayClick

I'm currently trying to get an event (type of background) when the DayClick is trigger.
I can't use the EventClick trigger because of the background type (I don't know why but nothing happen in my case, something wrong from FullCalendar ?).
This is my code for the init :
$('#calendarRoomUnavailable').fullCalendar({
height: 'auto',
header: {
left : '',
center: 'title',
right: ''
},
defaultView: 'year',
defaultDate: getDateFilterRoomAvailable(),
lang: 'fr',
firstDay: 1,
columnFormat: 'ddd D/M',
selectable : false,
weekends: false,
navLinks : false,
events: basePath + '/agenda/datalist/room_available',
viewRender: function (view, element) {
},
eventRender: function(event,element){
if(event.rendering === "background"){
element.data(event); //store the event data inside the element
}
},
dayClick: function (date, jsEvent, view) {
console.log(jsEvent)
},
editable:false,
});
Quick look
What I want:
When I click on a day, I want the get the event(background) related to the day (I've got only one event per day in my calendar).
Currently I'm working with the eventRender + dayClick :
eventRender: function(event,element){
if(event.rendering === "background"){
element.data(event); //store the event data inside the element
}
},
dayClick: function (date, jsEvent, view) {
console.log(jsEvent)
[...]
}
With the console.log JSEvent on the DayClick, I know it get me the wrong <td> :
Img
Because, when I try to get the target <td> with the class fc-bgevent, nothing happens :
dayClick: function (date, jsEvent, view) {
console.log(jsEvent)
if (jsEvent.target.classList.contains('fc-bgevent')) {
console.log($(jsEvent.target).data());
}
If I try to go to the HTML element target getted by the jsEvent, it shows me the wrong <td> and I can't do anything with that ...
HTML Debug
Does someone know how to bypass that ?
Thanks !
Code to get one event from a date :
function getEventFromDate(date) {
var allEvents = [];
allEvents = $('#calendarRoomUnavailable').fullCalendar('clientEvents');
var event = $.grep(allEvents, function (v) {
return +v.start === +date;
});
if (event.length > 0) {
return event[0];
} else {
return null;
}
}
After the #ADyson comments, my final function look like this :
function getEventFromDate(date) {
var eventToReturn = null;
$('#calendarRoomUnavailable').fullCalendar('clientEvents', function(event) {
var event_start = formatDateYmd(new Date(date),'-');
var date_formated = formatDateYmd(new Date(event.start),'-');
if(event_start === date_formated) {
eventToReturn = event;
}
});
return eventToReturn;
}
with a small function to get a formated date without library like Moment.js or Date.js:
function formatDateYmd(value,$delimiter)
{
var year = value.getFullYear();
var month = (value.getMonth()+1) < 10 ? '0'+(value.getMonth()+1) : (value.getMonth()+1);
var day = value.getDate() < 10 ? '0'+value.getDate() : value.getDate();
return year + $delimiter +
month + $delimiter +
day;
}
I hope to find something more performant, but this one divide the execution time by two.
Keep an eye on it
Thanks again.

fullCalendar only display events on agendaView

I'm trying to get the fullCalendar JS application to display events only when on the agendaView view, not on the month view.
This is my current code. The problem is the events function is only called once, on the initial page load. According to documentation (and another site I have with fullCalendar) this function should call every time I change view, or date range. It does not.
$('#calendar').fullCalendar({
events: function ( start, end, timezone, callback ) {
var view = $('#calendar').fullCalendar('getView');
console.log(view.name);
if(view.name == 'agendaDay') {
$.ajax({
type: 'POST',
url: 'index.php?events=true',
data: {
start: start,
end: end
},
async: true,
success: function ( data ) {
callback(data);
}
});
}
},
dayClick: function ( date, jsEvent, view ) {
if(view.name == 'month' && jsEvent.currentTarget.className.indexOf('date-disabled') <= -1) {
$('#calendar').fullCalendar('changeView', 'agendaDay');
$('#calendar').fullCalendar('gotoDate', date);
} else if(view.name == 'agendaDay') {
var check = moment(date).format('YYYY-MM-DD');
var today = moment(new Date()).format('YYYY-MM-DD');
if(check > today) {
alert(date);
}
}
},
header: {
left: 'title',
center: '',
right: 'today month,agendaDay prev,next'
},
dayRender: function ( date, cell ) {
var check = moment(date).format('YYYY-MM-DD');
var today = moment(new Date()).format('YYYY-MM-DD');
if(check <= today) cell[0].className += ' date-disabled';
}
});
I know this for fact as the console.log only logs once, the word month. So it's only called when I refresh the page, first load it. Not when changing views which it should.
I was missing the lazyFetching option. This must be a new option in v2 as I was not expecting it.
http://arshaw.com/fullcalendar/docs/event_data/lazyFetching/
My code was correct. I simply needed to tell fullCalendar to get the events at EVERY change of the view and anything else that happened event wise.
lazyFetching: false,
This now works with my code.

Persisting dates between FullCalendar and an index view

I'm working on a website, asp.net MVC kind of thing. On the home page, I have two alternate views. One is a jquery FullCalendar, and one is an index view, both displaying events from a database.
I can currently change the month being viewed in either, but I want to be able to link them up, so that for example changing to view april 2013 in the calendar and then clicking "index view" will take me to april 2013 in the index view, rather than the default.
My "GetEventsForCalendar" method is as follows:
[HttpPost]
public virtual ActionResult GetEventsForCalendar(long start, long end)
{
var startDateTime = start.ToDateTime();
var endDateTime = end.ToDateTime();
var listOfEvents = eventRepository.List.Where(e => e.ToDate >= startDateTime
&& e.FromDate <= endDateTime).ToList() .Select(eventSerialiser.SerialiseForFullCalendarJS);
return Json(listOfEvents);
}
But I can't find anywhere in the codebase where it is given these parameters. The only place the function is specified is in the calendar partial view scrips section:
#section scripts {
#Scripts.Render(Links.Bundles.Scripts.calendar)
#Scripts.Render(Links.Bundles.Scripts.events_calendar)
<script type="text/javascript">
$(document).ready(function() {
SohoHouse.EventsCalendar.setup("#Url.Action(MVC.Events.GetEventsForCalendar())");
})
</script>
}
I think the details of the month being viewed are persisted in a cookie, but I'm not sure how to access this from my index view.
If you need any other code then please ask, I'm very new to programming and stack overflow so I'm still not sure how to ask questions well :)
Managed to get this working in the end: abandoned the idea of a seperate view for the index, and instead used the jquery to create a table with a list view of the events. Then used a button to toggle between the two. For reference, the calander.js looked something like this:
var report = $("#report");
var calendar = $("#calendar .fc-content");
report.hide();
$("#toggle-view").click(function() {
calendar.toggle();
report.toggle();
$("#calendar").fullCalendar("refetchEvents");
$("#calendar").fullCalendar("render");
updateToggleButtonText();
});
function updateToggleButtonText() {
$("#toggle-view").text(report.is(":visible") ? "View Calendar" : "View List");
}
function setUpCalendar() {
$("#calendar").fullCalendar({
events: {
url: getEventsUrl,
type: "POST",
eventDataTransform: addReportRow
},
timeFormat: "H:mm{ - H:mm}",
allDayDefault: false,
eventBorderColor: "gray",
header: {
left: "prev,next",
center: "title",
right: null
},
weekMode: "variable",
loading: function(isLoading) {
if (isLoading) {
$("table#report > tbody:last").empty();
}
},
allDaySlot: false
});
}
function addReportRow(data) {
var calendarMonth = $("#calendar").fullCalendar("getDate").getMonth();
var startDate = new Date(data.start);
var endDate = new Date(data.end);
if (startDate.getMonth() > calendarMonth || endDate.getMonth() < calendarMonth) {
return null;
}
var tableDetails = [
data.title,
$.fullCalendar.formatDate(startDate, "dd MMMM yyyy"),
$.fullCalendar.formatDate(endDate, "dd MMMM yyyy"),
data.published ? "Published" : "Not Published"
];
var row = $("<tr></tr>");
for (var i = 0; i < tableDetails.length; i++) {
row.append($("<td></td>").text(tableDetails[i]));
}
$("table#report > tbody:last").append(row);
return data;
}
function gotoDateFromCookie() {
var calendarDate = $.cookie("calendarDate");
if (calendarDate !== null && calendarDate !== "Invalid Date") {
$("#calendar").fullCalendar("gotoDate", new Date(calendarDate));
$.cookie("calendarDate", null);
}
}
function storeDateAsCookie() {
var calendarDate = $("#calendar").fullCalendar("getDate");
$.cookie("calendarDate", calendarDate);
}
window.eventDropdownChanged = function() {
location.reload();
};
};

Can I prevent events with conflict time?

How can I prevent events with conflict time? Is there any variable to set up?
No, there is not a variable to set, but you can use something like clientEvents which retrieves events that fullcalendar has in memory. You can use the function below in the eventDrop. In the case below it uses a function to filter out whether the event will have have an overlap or not.
function checkOverlap(event) {
var start = new Date(event.start);
var end = new Date(event.end);
var overlap = $('#calendar').fullCalendar('clientEvents', function(ev) {
if( ev == event)
return false;
var estart = new Date(ev.start);
var eend = new Date(ev.end);
return (Math.round(estart)/1000 < Math.round(end)/1000 && Math.round(eend) > Math.round(start));
});
if (overlap.length){
//either move this event to available timeslot or remove it
}
}
you can add eventOverlap : false in the celendar config,
http://fullcalendar.io/docs/event_ui/eventOverlap/
Correct overlap checking.
eventDrop: function(event, dayDelta, minuteDelta, allDay, revertFunc, jsEvent, ui, view) {
/// deny overlap of event
var start = new Date(event.start);
var end = new Date(event.end);
var overlap = $('#calendar').fullCalendar('clientEvents', function(ev) {
if( ev == event) {
return false;
}
var estart = new Date(ev.start);
var eend = new Date(ev.end);
return (
( Math.round(start) > Math.round(estart) && Math.round(start) < Math.round(eend) )
||
( Math.round(end) > Math.round(estart) && Math.round(end) < Math.round(eend) )
||
( Math.round(start) < Math.round(estart) && Math.round(end) > Math.round(eend) )
);
});
if (overlap.length){
revertFunc();
return false;
}
}
Add custom property in the event object overlap:false for example your event object will be
`{
title:'Event',
start: '2017-01-04T16:30:00',
end: '2017-01-04T16:40:00',
overlap:false
}`
Now override selectOverlap function,
selectOverlap: function(event) {
if(event.ranges && event.ranges.length >0) {
return (event.ranges.filter(function(range){
return (event.start.isBefore(range.end) &&
event.end.isAfter(range.start));
}).length)>0;
}
else {
return !!event && event.overlap;
}
},
It will not let the another event to override the already placed event.
This does the trick. It also handles resizing overlapping events
var calendar = new Calendar(calendarEl, {
selectOverlap: false,
eventOverlap: false
}
});

input text return event in Meteor

I want to capture the event of a user pressing enter on an input of type="text" when they are filling out a form. This is done all over the web, yet the answer eludes me.
This is what I have so far:
In the html file, I have a text input like so:
<input type="text" size=50 class="newlink">
In the Javascript file, I am trying to capture the the user pressing enter to effectively submit the form. I am then grabbing the text from the input and going to stash it in the database:
Template.newLink.events = {
'submit input.newLink': function () {
var url = template.find(".newLink").value;
// add to database
}
};
The submit event is emitted from forms, not single input elements.
The built in event map for meteor is documented here: http://docs.meteor.com/#eventmaps.
You'll have to listen for a keyboard event (keydown, keypress, keyup). Within the event handler, check, if it's the return/enter key (Keycode 13), and proceed on success.
Template.newLink.events = {
'keypress input.newLink': function (evt, template) {
if (evt.which === 13) {
var url = template.find(".newLink").value;
// add to database
}
}
};
You could look into how this is achieved in the todos example (client/todos.js).
It uses a generic event handler for input fields (as seen below). You can browse the rest of the code for usage.
////////// Helpers for in-place editing //////////
// Returns an event map that handles the "escape" and "return" keys and
// "blur" events on a text input (given by selector) and interprets them
// as "ok" or "cancel".
var okCancelEvents = function (selector, callbacks) {
var ok = callbacks.ok || function () {};
var cancel = callbacks.cancel || function () {};
var events = {};
events['keyup '+selector+', keydown '+selector+', focusout '+selector] =
function (evt) {
if (evt.type === "keydown" && evt.which === 27) {
// escape = cancel
cancel.call(this, evt);
} else if (evt.type === "keyup" && evt.which === 13 ||
evt.type === "focusout") {
// blur/return/enter = ok/submit if non-empty
var value = String(evt.target.value || "");
if (value)
ok.call(this, value, evt);
else
cancel.call(this, evt);
}
};
return events;
};
I used this js function once to suppress the user using the return key in the text field to submit the form data. Perhaps you could modify it to suit the capture?
function stopRKey(evt) { // Stop return key functioning in text field.
var evt = (evt) ? evt : ((event) ? event : null);
var node = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : null);
if ((evt.keyCode == 13) && (node.type=="text")) { return false; }
}
document.onkeypress = stopRKey;
You can also use event.currentTarget.value
Template.newLink.events = {
'keypress input.newLink': function (evt) {
if (evt.which === 13) {
var url = event.currentTarget.value;
// add to database
}
}
};

Resources