I'm using ExtJS 3.4 and fullcalendar#5.10.2 ( using jsdelivr CDN ).
My config Object :
var config = {
events : eventsLoader,
initialView: 'dayGridMonth',
height : 500,
nowIndicator : true ,
editable: false,
locale : "fr",
showNonCurrentDates: false,
headerToolbar: {
right: 'dayGridMonth,timeGridWeek,timeGridDay list',
center: 'title',
left: 'today prev,next'
},
footerToolbar: {
right: "prevYear,nextYear"
},
buttonText : {
today: "Aujourd'hui",
month: 'Mois',
week: 'Semaine',
day: 'Jour',
list: 'Liste'
}
}
The eventsLoader function :
var eventsLoader = function(fetchInfo, successCallback, failureCallback) {
Ext.Ajax.request({
url : gpao.OF.url,
method : "POST",
params : {
action : 'getEvents',
idCentreDeCharge : id,
},
success : function(result,response) {
var jsonData = Ext.util.JSON.decode(result.responseText);
var jsonRes = jsonData.results;
var events = jsonRes.map(function(eventEl) {
return {
title : eventEl.title,
start : eventEl.start,
end : eventEl.end
}
})
console.log("events : ",events);
successCallback(events);
},
failure : function() {
console.error('there was an error with the Ajax request to '+gpao.CentreCharge.url);
failureCallback("failed");
}
});
}
The fetchInfo object :
var now = new Date();
var startDate = new Date();
startDate.setYear(now.getFullYear() - 3);
var endDate = new Date();
endDate.setYear(now.getFullYear() + 3);
var fetchInfo = {
start : startDate.toISOString().split('T')[0],
end : endDate.toISOString().split('T')[0]
}
console.log("fetchInfo : ",fetchInfo);
Example of the events array passed to successCallback(events) looks like this :
I used a dummy events array just to test, and my calendar renders with no errors.
The Problem :
I'm rendering the calendar on a Tab Panel, this time using a function instead of a dummy array, the first time a user selects it the calendar looks all messed up ( week days all clummed up in the top left corner on top of each other ), untill i either resize the page CTRL + MouseWheel, switch views, or click any button like prev,next,prevYear,nextYear,today, i'm stuck on this, any help appreciated.
If you are hiding the container in which the calendar element belongs, then you need to call the calendar's render() method when you re-display it, otherwise it can be messed up by being in a hidden container.
Related
We are using Fullcalendar V5 in Asp.net Core.
We are also using Kendo UI. Our fullcalendar is inside of a "kendo-tabstrip" -> "tabstrip-item" control, if that matters.
Our fullcalendar events are fetched from a controller using Axios(), then the callback renders the events etc...
The problem we have is that when the page loads the first time, the calendar renders in a 1x1mm area in the top left of the calendar div. Instead of full screen as it should.
If I click the previous month button or have a button that does a "calendar.render()", then the calendar renders correctly in a full screen and it renders correctly when going to next or previous months.
Basically, the calendar renders fine after I do a manual "calendar.render()".
What causes this? How can I fix or work around?
I have included my fullcalendar code and an image of how my fullcalendar renders when the page loads.
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function () {
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
height: 'auto',
expandRows: true,
headerToolbar: {
right: "today",
center: "title",
left: "prevYear,prev,next,nextYear customButton1,customButton2"
},
customButtons: {
customButton1: {
text: 'customButton1'
},
customButton2: {
text: 'customButton2',
click: function() {
calendar.render();
}
}
},
initialView: 'dayGridMonth',
events: function (info, successCallback, failureCallback) {
var urlString = myapp.url.build("GetFCEvents", "MyController", id)
axios.get(urlString + "?Id=" + Id)
.then(function (response) {
successCallback(response.data);
})
},
eventContent: function (info) {
let idname = `chart-${info.event.id}`
const chartTag = `<div id="${idname}"></div>`;
return {html: chartTag};
},
eventDidMount: function(info) {
let idname = `chart-${info.event.id}`
const chartTag = `<div id="${idname}"></div>`;
generateMyChart(idname);
}
});
calendar.render();
});
......other functions......
</script>
I am going to add remove cross sign with each event of calendar which are getting from database. But how to add this and i want when click on cross sign(delete) then specific url will be triggered and i want to delete event from database. Please let me know how can i do this? How to add delete event with cross sign.
call-init.js
!function($) {
"use strict";
var CalendarApp = function() {
this.$body = $("body")
this.$calendar = $('#calendar'),
this.$event = ('#calendar-events div.calendar-events'),
this.$categoryForm = $('#add-new-event form'),
this.$extEvents = $('#calendar-events'),
this.$modal = $('#my-event'),
this.$saveCategoryBtn = $('.save-category'),
this.$calendarObj = null
};
/* Initializing */
CalendarApp.prototype.init = function() {
this.enableDrag();
/* Initialize the calendar */
var events = [];
$.ajax({
type: 'POST',
async: false,
url: '/Booking/GetBookings',
success: function (mems) {
//states contains the JSON formatted list
//of states passed from the controller
$.each(mems, function (_, member) {
debugger;
events.push({
title: member.guestname,
start: new Date(member.checkindatetime),
end: new Date(member.checkoutdatetime),
allDay: true,
url: '/Booking/Booking/' + member.encryptedId,
className: member.classnamecolor
});
});
},
error: function (ex) {
alert('Buchungen konnten nicht geladen werden.');
}
});
var $this = this;
$this.$calendarObj = $this.$calendar.fullCalendar({
defaultView: 'month',
handleWindowResize: true,
header: {
left: 'prev,next today',
center: 'title',
right: ''
},
navLinks: false, // can click day/week names to navigate views
events: events
//eventStartEditable: false // disable drag&drop of events
});
},
//init CalendarApp
$.CalendarApp = new CalendarApp, $.CalendarApp.Constructor = CalendarApp
}(window.jQuery),
//initializing CalendarApp
function($) {
"use strict";
$.CalendarApp.init()
}(window.jQuery);
other calendar view is
#model FewoVerwaltung.Models.Booking.BookingListModel
<div id="calendar"></div>
<!-- Calendar JavaScript -->
<script src="~/plugins/calendar/dist/locale/de.js"></script>
<script src="~/plugins/calendar/dist/fullcalendar.min.js"></script>
<script src="~/plugins/calendar/dist/cal-init.js"></script>
I need to get the start time and the end time of the even I have saved in the database,
I was able to get the start date and end date from the start_date & end_date fields from the database and display it in the full calendar as shown in the below image
But I need to get the times too from the database from the fields start_time & end_time
Here's how my database fields looks like
I just need to know how can I display the time range as the date range here
Here's my scripts
<script>
$(document).ready(function() {
$(".dashbord-body").removeClass("bg-white");
});
$(function() {
$('#calendar').fullCalendar({
selectable:true,
height:650,
showNonCurrentDates:false,
editable:false,
defaultView:'month',
yearColumns: 3,
header: {
left: 'prev,next', //note no "buttons
center: 'title',
right: 'year,agendaDay,agendaWeek,month,timelineCustom'
},
eventSources: [
{
url: '/calendar', // use the `url` property
color: 'red', // an option!
textColor: 'white', // an option!
}
],
eventDataTransform: function(eventData) {
return {
title: eventData.name,
start: eventData.start_date,
end: eventData.end_date
}
},
});
});
</script>
HTML
<div id='calendar'></div>
Controller function
public function calendar()
{
$calendar= Event::latest()->get();
return response()->json($calendar);
}
I was able to fix the issue I faced here by below codes in my controller function
public function calendar(Job $job)
{
$user = auth()->user();
$calendar = $job->where('user_id',$user->id)->get();
$calendar = $calendar->map(function ($post) {
$post['start'] = $post->start_date . ' ' . $post->start_time;
$post['end'] = $post->end_date . ' ' . $post->end_time;
// unset($post['name']);
return $post;
});
return response()->json($calendar);
}
And added the extra field name to the Model as below code
protected $visible = ['start','end'];
As the title says, I have a question regarding EventSource in the fullcalendar.
At the moment I can load 1 google calendar in the fullcalendar. And know how to add multiple google calendars.
However, I want to use checkboxes (linked to their own google calendar), I dynamically create an array with the googleCalendarIds, all this works, but I can't get the calendar to "refetch" all the event from the google calendars in the array.
At the moment, this is the code I use to populate the calendar:
document.addEventListener('DOMContentLoaded', function() {
var selected = [];
$('.badgebox:checked').each(function() {
selected.push({
'googleCalendarId' : $(this).val(),
'className' : $(this).data('color')
});
});
$('.badgebox').on('click', function() {
if($(this).prop('checked')) {
selected.push({
'googleCalendarId' : $(this).val(),
'className' : $(this).data('color')
});
$('#calendar').fullCalendar('refetchResources');
}else{
index = selected.findIndex(obj => obj.googleCalendarId === $(this).val());
selected.splice(index, 1);
$('#calendar').fullCalendar('refetchResources');
}
});
var calendarEl = document.getElementById('calendar');
calendar = new FullCalendar.Calendar(calendarEl, {
header: {
center: 'dayGridMonth,timeGridWeek'
},
views: {
dayGridMonth: {
titleFormat: { year: 'numeric', month: '2-digit', day: '2-digit' }
}
},
plugins: [ 'dayGrid', 'timeGrid', 'bootstrap', 'googleCalendar' ],
googleCalendarApiKey: 'api key',
eventSources: selected,
eventClick: function(info) {
info.jsEvent.preventDefault();
},
defaultView: 'timeGridWeek',
weekNumbers: true,
locale: 'nl',
themeSystem: 'bootstrap',
nowIndicator: true
});
calendar.render();
});
But what I am getting is an error:
TypeError: $(...).fullCalendar is not a function
I have loaded all the files needed (and can see they are loaded).
Edit current code
This is the code I use now, but still not sure how to fix the resources part (refreshing):
document.addEventListener('DOMContentLoaded', function() {
var curSource = [];
$('.badgebox:checked').each(function() {
curSource.push({
'googleCalendarId' : $(this).val(),
'className' : $(this).data('color')
});
});
var newSource = [];
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
schedulerLicenseKey: 'key',
header: {
center: 'dayGridMonth,timeGridWeek'
},
views: {
dayGridMonth: {
titleFormat: { year: 'numeric', month: '2-digit', day: '2-digit' }
}
},
plugins: [ 'dayGrid', 'timeGrid', 'bootstrap', 'googleCalendar', 'resourceTimeGrid', 'resourceDayGrid' ],
googleCalendarApiKey: 'apikey',
eventSources: curSource,
eventClick: function(info) {
info.jsEvent.preventDefault();
},
defaultView: 'timeGridWeek',
weekNumbers: true,
locale: 'nl',
themeSystem: 'bootstrap',
nowIndicator: true
});
$('.badgebox').on('change', function() {
if($(this).prop('checked')) {
newSource.push({
'googleCalendarId' : $(this).val(),
'className' : $(this).data('color')
});
}else{
index = newSource.findIndex(obj => obj.googleCalendarId === $(this).val());
newSource.splice(index, 1);
}
curSource = newSource;
calendar.getEventSources().forEach(eventSource => {
eventSource.remove()
});
calendar.addEventSource(curSource);
});
calendar.render();
});
Any idea?
Your logic for adding and removing event sources is flawed - it'll remove all the previous sources, but only ever add the currently selected one (well, except that you never clear newSource so it'll contain all sorts of duplication after a while). The other problem is that when you write calendar.addEventSource(curSource); you're adding an array of event sources (even though it only ever contains one item) but adding it as if it was a single event source object. Therefore it's not in the format fullCalendar expects, so it doesn't add anything.
Instead you can just use the same logic you use when you first declare the calendar, to loop through all the currently selected checkboxes and set all of them as the current sources. This is the simplest way to do it. Just move that logic into a function so you can re-use it. It also removes the necessity for global objects containing the list of sources. Something like this:
function getEventSources() {
var sources = [];
$(".badgebox:checked").each(function() {
sources.push({
id: $(this).val(),
'googleCalendarId' : $(this).val(),
className: $(this).data("color")
});
});
return sources;
}
Then in the calendar config, set the initial event sources by calling the function:
eventSources: getEventSources(),
And handle the "change" event on the checkboxes like this:
$(".badgebox").on("change", function() {
//remove event sources
calendar.getEventSources().forEach(eventSource => {
eventSource.remove();
});
//get currently selected sources
var sources = getEventSources();
//add each new source to the calendar
sources.forEach(eventSource => {
calendar.addEventSource(eventSource);
});
});
I made a live demo here: https://codepen.io/ADyson82/pen/Jjoovym. I couldn't use google calendars for the demo obviously so I've done it with hard-coded lists of events, but the overall logic of the process is identical.
On the first load of the page, it shows a single event per day, but on the second load (or refresh of the page) it adds a duplicate event on the same day in the full calendar.
Here is my code:
var CalendarView = Backbone.View.extend({
el : '#calendar-box',
initialize : function() {
// TODO for instance: more instances, Event Bus bindings... only once.
this.calendarModel = new CalendarModel();
$('#calendar-box').hide();
var date = new Date();
var d = date.getDate();
var m = date.getMonth();
var y = date.getFullYear();
this.calendarModel.fetch({
success : function(model, response, options) {
$.unblockUI();
var count=0;
var eventsList=[];
model.attributes.result.forEach(function(){
eventsList.push({
id: model.attributes.result[count].eventId,
title:model.attributes.result[count].title,
start: new Date(model.attributes.result[count].startDate),
end: new Date(model.attributes.result[count].endDate),
attorneyName: model.attributes.result[count].attorneyName,
codeLitOrg: model.attributes.result[count].codeLitOrg,
balance: model.attributes.result[count].balance,
litCode: model.attributes.result[count].litCode
});
count++;
});
if (!_.isEmpty(eventsList)){
$('#calendar').fullCalendar({
editable: true,
events: eventsList,
eventMouseover: function(event, jsEvent, view) {
var info = event.title+'\nBK/LIT: '+event.codeLitOrg+'\nBalance: '+event.balance
+'\nAttorney: '+event.attorneyName+'\nLitCode: '+event.litCode;
$(jsEvent.target).attr('title', info);
},
theme: false,
height:575,
weekMode:'liquid',
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
});
}
},
error : function(model, xhr, options) {
$.unblockUI();
}
});
$.eventBus.on('calendarModalLoaded',function(){
if (!($('.fc-border-separate').html())){
$('#calendar').fullCalendar('today');
}
});
},
render : function() {
// TODO for instance, bindings elements after ready in DOM.
$('#calendar').fullCalendar('today');
return this;
},
events : {
'click a.op-attorney-info' : 'onAttorneyInfo',
'click .go-back-link' : 'goBack'
},
goBack: function(){
$('#calendar-box, .content-box').toggle();
//$('.content-box').toggle();
//$('.go-back-link').hide();
},
onAttorneyInfo : function(ev) {
// TODO for instance, fetch attorney's model
}
});
return CalendarView;
});
I have tried $('#calendar').fullCalendar('removeEvents'), but it is also not working.
Please help me out.