I have a complex scenario in which i want to implement. I am using Full Calendar v4.4.0 and for showing recurring events i am using rrule plugin. I am loading events from mysql. I am succesfull in loading them and showing them on website. Its working perfectly fine but now the client has come up with another requirement.
As told earlier i am using rrule plugin to show recurring events. In my portal there are only 2 recurring events
Weekly
Monthly
Now client wants to delete an event e.g, an event which is occurring weekly he wants to delete it for one time. For example an event is added on 13th April and is repeated every week. That is he wants to delete the event for 27th April only and want to continue with the sequence as it is. How can i achieve it as the event id is same for all repeating events.
It needs to be mention that i am using Mysql from where the events are coming.
My Code for Loading events
$model = Event::find()->all(); // getting all events
foreach ($model as $mod)
{
$day=array();
if ($mod->event_frequency==2)
{
$start=date('N', strtotime($mod->start_time));
$end=date('N', strtotime($mod->end_time));
if($start==$end)
{
$day[]=$start;
}
else
{
$day[]=$start;
$day[]=$end;
}
$data[]=[
'id' =>$mod->id,
'title'=>$mod->event_name,
// 'start' => $mod->start_time,
// 'end' => $mod->end_time,
'backgroundColor' => $mod->event_tag_color,
'textColor' => '#FFF',
'rrule'=> [
'freq'=> 'WEEKLY',
'interval'=> 1,
'dtstart'=> $mod->start_time,
'until' => '2022-12-31',
],
];
}
else if($mod->event_frequency==3)
{
$start=date('N', strtotime($mod->start_time));
$end=date('N', strtotime($mod->end_time));
if($start==$end)
{
$day[]=$start;
}
else
{
$day[]=$start;
$day[]=$end;
}
$data[]=[
'id' =>$mod->id,
'title'=>$mod->event_name,
// 'start' => $mod->start_time,
// 'end' => $mod->end_time,
'backgroundColor' => $mod->event_tag_color,
'textColor' => '#FFF',
'rrule'=> [
'freq'=> 'MONTHLY',
'interval'=> 1,
'dtstart'=> $mod->start_time,
'until' => '2022-12-31',
],
];
}
else
{
$data[]=[
'id' =>$mod->id,
'title'=>$mod->event_name,
'start' => $mod->start_time,
'end' => $mod->end_time,
'backgroundColor' => $mod->event_tag_color,
'textColor' => '#FFF',
];
}
}
return JSON::encode($data);
the calender.js for loading is as follows
var calendarEl = document.getElementById('calendar-event');
var calendar = new FullCalendar.Calendar(calendarEl, {
plugins: ['interaction', 'dayGrid', 'timeGrid', 'list','rrule'],
header: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay,listMonth'
},
navLinks: true, // can click day/week names to navigate views
businessHours: true, // display business hours
editable: true,
//uncomment to have a default date
//defaultDate: '2020-04-07',
events: url+'calender/load', // loading events
}
Deleting an event on server
$event_id=Yii::$app->request->post('event_id');
$model= Event::findOne($event_id);
$model->delete();
$response= array();
$response['status']="ok";
return JSON::encode($response);
The js file calling the action delete action
$(".delete-event-calender").on("click",function(evt) {
$data=$('form').serialize();
$url=$(this).data('url');
$.ajax({
type: "POST",
url: $url,
data: $data,
dataType: "json",
traditional: true,
success: function (response) {
//alert(response.status);
if (response.status==="ok"){
calendar.refetchEvents();
$(".ajax_form").trigger("reset");
}
else
{
}
},
error: function (response) {
debugger;
alert(response.d);
}
});
});
If i try to delete the event for 27th April it will take the event id of main event (The day it was set) and will delete whole sequence? How can i prevent it.
How can i achieve it? Any suggestions please
Thanks
Related
Hello, everybody. I am using fullcalendar in my symfony project(Symfony + RiotJS). I want to load the events dynamically when I press 'prev' or 'next' button. So I make a new calendar when the page is mounted and set the calendar events as 'null'. As you can see on the code, I called the loadItems() function to load the events again when I press 'prev' or 'next' button. But I can't sure how to update the events of calendar in the loadItems() function. I'd really appreciate if someone knows how to fix it. I will wait for reply.Thanks.
onMounted() {
self = this;
let calendarEl = this.$('#calendar');
this.state.calendar = new Calendar(calendarEl, {
plugins: [ dayGridPlugin, timeGridPlugin, listPlugin ],
initialView: 'dayGridMonth',
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek'
},
buttonText: {
today: 'Heute',
month: 'Monat',
week: 'Woche',
day: 'Tag',
},
datesSet: function() {
let view = this.currentData.dateProfile.renderRange;
let start = view.start.toISOString().substring(0, 10);
let end = view.end.toISOString().substring(0, 10);
if (start != getSearchParam('begin')) {
updateSearchParam('begin', start);
updateSearchParam('end', end);
self.loadItems();
}
},
events: this.state.events,
initialDate: getSearchParam('date', '') ? getSearchParam('date', '') : this.moment().format('Y-MM-DD'),
});
this.state.calendar.setOption('locale', 'de');
this.state.calendar.render();
updateSearchParam('date', '');
this.update();
this.loadItems();
},
And this is the loadItems() function.
loadItems() {
this.state.loading = true;
this.update();
if (this.state.request) {
this.state.request.abort();
}
this.state.request = this.API.get('/events', this.getParams());
this.state.request.then(response => {
this.state.items = response.data.items;
this.state.filteredItems = null;
this.state.total = response.data.total;
this.state.events = [];
response.data.items.forEach( item => {
let event = {
id: item.id,
title: item.event.name,
start: this.moment(item.begin).format('Y-MM-DD'),
end: this.moment(item.end).format('Y-MM-DD'),
backgroundColor: item.event.type.bgColor,
borderColor: '#ffffff',
textColor: this.getTextColor(item.event.type.bgColor),
};
this.state.events.push(event);
});
this.state.loading = false;
this.update();
//after I gets the events I want to update the events of calendar here
//this.state.calendar.refetchEvents();
this.update();
this.state.request = null;
});
return this.state.request;
},
I just focused how to update events when I press the 'prev' and 'next' button.
I searched a lot about the method and there were many solutions.
For example:
$('#calendar').fullCalendar('updateEvents', events)
$('#calendar').fetchEvents()
But these methods are not working on my problem.
Finally, I found a simple method.
It is a setOption() method.
As you can see on my above code, there are options like 'datesSet' and 'events'.
The 'datesSet' option is called everytime when I press the buttons (prev, next, today, month, week and etc).
And the 'events' option is for events to show on the current calendar view.
I used setOption() method like this.
this.state.calendar.setOption('events', this.state.events);
It worked well for me.
I suggest the people who read my question and answer, to read the tutorials and documentations carefully.
Fullcalendar is really well-built javascript package and we can use it very simply.
I am trying the editable, drag and expand event on my FullCalendar.
First of all, I am using React.
To describe the problem:
If I have this 2 events on my calendar with same group:
before drag and drop
Event1 is Workshop#1pm, Event 2 is Date#5pm
When I drag and drop Workshop to 12 pm, the same will goes to Date and it will located at 4pm, at the same time.
after drag and drop
Same thing happen with changing duration.
I only want single event to be affected with the gesture, not all event on its group.
So far, I tried to read the documentation thoroughly but I could not find any settings related to it. I also tried to search forums but I never found similar problem.
I am suspecting it has something to do with my complex style of populating calendar with event.
constructor(props) {
super(props);
this.state = {
myEventSource: [],
}
// function the fetch event from google API
loadEvents = async () => {
await fetch(fetchCommand)
.then(res => res.json())
.then((res) => {
// making the loop
res.result.forEach(result => {
// when get result, it will compose the events object to be
// stored in this.state.myEventSource
var tempEvent = [];
result[0].eventsInfo.forEach(event => {
var evt = {
id: event.id,
groupId: result[0].userName,
title: event.summary,
allDay: event.start.date!=null?true:false,
start: event.start.dateTime!=null?event.start.dateTime?.toString():event.start.date?.toString(),
end: event.end.dateTime!=null?event.end.dateTime?.toString():event.end.date?.toString(),
}
tempEvent.push(evt);
});
this.TempEventSource[result[0].userName] = tempEvent;
});
});
...
this.setState({ myEventSource: this.updateCalendarOnTabChange(this.state.tabIndex), firstLoad: true });
}
render() {
return(
<FullCalendar
plugins={[ timeGridPlugin, dayGridPlugin, interactionPlugin]} //
editable={true}
...
eventSources={this.state.myEventSource}
/>
)
}
Good morning!
I have a list view set up in full calendar and have noticed that it will not display events beyond the end of the year. With it being now mid-December, this is a bit of a problem for me. We have several event that should be displaying in this list. When I change the view to month I have to click the next month button to get next years events, but at least with that I do sucessfully see the events in question.
Is there a way for my list view calendars to roll-over and include next year entries as I approach the end of the current year?
Here is an excerpt of what I have that effects the display of my calendar:
{url:'https://calendar.mydomain.com/services/id/38djsuw3hr-au8reh39dq/organization/1/department/13/',event_properties:{color:'#6a9b49'}},
]
function data_req (url, callback) {
req = new XMLHttpRequest()
req.addEventListener('load', callback)
req.open('GET', url)
req.send()
}
function add_recur_events() {
if (sources_to_load_cnt < 1) {
$('#calendar').fullCalendar('addEventSource', expand_recur_events)
} else {
setTimeout(add_recur_events, 30)
}
}
function load_ics(ics){
data_req(ics.url, function(){
$('#calendar').fullCalendar('addEventSource', fc_events(this.response, ics.event_properties))
sources_to_load_cnt -= 1
})
}
$(document).ready(function() {
$('#calendar').fullCalendar({
header: {
left: '',
center: '',
right: '' //view options on top-right (supported by v2.9.1 currently)
},
viewDisplay: function(view) {
parent.setIframeHeight(iframeId) ;
},
eventClick: function(event) {
// opens events in a new window or tab
window.open(event.url,);
return false;
},
// eventDataTransform: function(rawEventData){
// return {title: rawEventData.Title
// };
// },
defaultView: $(window).width() < 765 ? 'listYear':'listYear', //carryover code from full sized calendar
nowIndicator: false, //show a marker for current time
eventLimit: 4, // allow "more" link when too many events
fixedWeekCount: false, // have blank rows on a 6 or 7 row month
listDayFormat: 'MMMM Do',
listDayAltFormat: false,
allDayDefault: false,
noEventsMessage: "No Currently Scheduled Events"
})
sources_to_load_cnt = ics_sources.length
for (ics of ics_sources) {
load_ics(ics)
}
add_recur_events()
})
All I see is my "NoEventsMessage" text when in list view. If I create a test event the occurs prior to the end of the year it shows up in list view.
Any ideas on spanning calendar end?
thanks
[Edit: I should say that the link at the top is a JSON feed, so I am not using a prefilled list of events from within my script or from within an external file]
Here is how I solved it.
I created a custom view entry for the specific default view called "list" and gave it a one year duration:
views: {
list: {
duration: { days:365 }
}
},
I reset my default view from the dynamic version I carried over from my full-sized calendar (since I am using this in a column anyway and the window width call is not needed):
From:
defaultView: $(window).width() < 765 ? 'listYear':'listYear',
To:
defaultView: 'list',
After doing those things my January entries for next year began to display in list view.
Here is what my display calls look like (If someone wants to edit this to make it look prettier and more efficient, I don't mind :).
ics_sources = [
{url:'https://calendar.mydomain.com/services/id/38djsuw3hr-au8reh39dq/organization/1/department/13/',event_properties:{color:'#6a9b49'}},
]
function data_req (url, callback) {
req = new XMLHttpRequest()
req.addEventListener('load', callback)
req.open('GET', url)
req.send()
}
function add_recur_events() {
if (sources_to_load_cnt < 1) {
$('#calendar').fullCalendar('addEventSource', expand_recur_events)
} else {
setTimeout(add_recur_events, 30)
}
}
function load_ics(ics){
data_req(ics.url, function(){
$('#calendar').fullCalendar('addEventSource', fc_events(this.response, ics.event_properties))
sources_to_load_cnt -= 1
})
}
$(document).ready(function() {
$('#calendar').fullCalendar({
header: false,
viewDisplay: function(view) {
parent.setIframeHeight(iframeId) ;
},
eventClick: function(event) {
// opens events in a new window or tab
window.open(event.url,);
return false;
},
defaultView: 'list',
nowIndicator: false, //show a marker for current time
eventLimit: 4, // allow "more" link when too many events
fixedWeekCount: false, // have blank rows on a 6 or 7 row month
listDayFormat: 'MMMM Do',
listDayAltFormat: false,
noEventsMessage: "No Currently Scheduled Events",
views: {
list: {
duration: { days: 365 },
}
}
})
sources_to_load_cnt = ics_sources.length
for (ics of ics_sources) {
load_ics(ics)
}
add_recur_events()
})
Thanks.
[edit: removed extraneous backticks from answer.]
I'm trying to retrieve a list of events from an ajax call. I use the following code.
document.addEventListener("DOMContentLoaded", function()
{ var calendarEl = document.getElementById("id_d_agenda_1");
var calendar = new FullCalendar.Calendar(calendarEl, {
plugins: [ 'interaction', 'dayGrid', 'timeGrid', 'list' ],
header: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek'
},
defaultDate: '2019-08-12',
editable: true,
navLinks: true, // can click day/week names to navigate views
eventLimit: true, // allow "more" link when too many events
selectMirror: true,
select: function(arg) {
var title = prompt('Event Title:');
if (title) {
calendar.addEvent({
title: title,
start: arg.start,
end: arg.end,
allDay: arg.allDay
})
}
calendar.unselect()
},
events: function(arg) {
$.ajax({
url: 'd.php',
dataType: 'json',
data: {
cmd:'getdata',
start:arg.startStr,
end:arg.endStr,
tz:arg.timeZone,
component:'d_agenda_1',
},
success: function(doc) {
$(doc).each(function() {
calendar.addEvent( this );
})
}
})
}
})
calendar.render();
});
While debugging my javascript I can see the rows of events appear in 'doc'. First I tried to bulk add them to the agenda, but that didn't seem to work. Now I'm adding them one-by-one, buth they still don't appear. I have checked the this variable in the debugger and it shows a single event:
title:"value", start:"2019-08-01". In fact I'm using the sample list that comes with the package. Can someone point me to the right direction in what I'm doing wrong?
other options I tried (with no luck ;-):
I tried to leave the jquery out, but with similar effect:
success: function(doc) {
doc.forEach(function(value) {
calendar.addEvent( value );
})
}
success: function(doc) {
$(doc).each(function() {
calendar.addEvent({
title:this.title,
start:this.start
});
})
Not sure if it's helpful, but I added the selectable option and tested the select option. The calendar.addevent on the select: doesn't add the event either. Since this is copied from the sample i'm quite confused now. Fun part is that if you replace the ajax part with a regular [] expression that all works well. Even the selectable options, so there's definitely something wrong with my ajax implementation, in regards to this component.
According to the DOCS you need to have a successCallback that will return the events to the calendar.
Here is the docs https://fullcalendar.io/docs/events-function
Here is a simple Demo https://codepen.io/nasser-ali-karimi/pen/gOOJrWV?editors=0010
And in short, I can say that you need to set the events like this.
events: function(info, successCallback, failureCallback) {
successCallback([
{"resourceId":"a","title":"event 1","start":"2019-11-23","end":"2019-11-25"},
{"resourceId":"b","title":"event 3","start":"2019-11-24T12:00","end":"2019-11-25T06:00"},
{"resourceId":"b","title":"event 4","start":"2019-11-24T07:30","end":"2019-11-24T09:30"},
{"resourceId":"b","title":"event 5","start":"2019-11-24T10:00","end":"2019-11-24T15:00"},
{"resourceId":"a","title":"event 2","start":"2019-11-24T09:00","end":"2019-11-24T14:00"}
])
}
you didn't mention the events data that comes from Ajax request, so I can say you need to provide the data like what said on docs.
Addition
Note: Event's date are on 11/28 and 11,29 so navigate to those dates to see the events.
Demo https://codepen.io/nasser-ali-karimi/pen/qBBGVbG?editors=0010
events: function(info, successCallback, failureCallback) {
var arrevents = [];
jQuery.get( "https://api.myjson.com/bins/16ubhe", function( data ) {
// var response = JSON.parse(data);
// $.each(response, function(k, v) {
// arrevents.push(v);
// });
arrevents = data;
successCallback(arrevents);
});
},
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.