eventRender disappears in fullcalendar v5 - fullcalendar

Version : Fullcalendar-Scheduler v5 beta2
I tried eventRender like below in chrome:
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('planningMix');
var planningMix = $(calendarEl);
var calendar = new FullCalendar.Calendar(calendarEl, {
//...
eventRender: function(info) {
debugger
},
events: function(d, successCallback, failureCallback) {
//...
}
});
calendar.render();
});
When I run this code, "debugger" didn't fired. eventRender has became another name in V5 ?

those who were going to upgrade from V4 to V5, check this document upgrading-from-v4, there were many changes which we need to consider while upgrading.
Example of EventContent
eventContent: function (arg) {
var event = arg.event;
var customHtml = '';
customHtml += "<span class='r10 font-xxs font-bold' style='overflow: hidden;'>" + event.title + "</span>";
customHtml += "<span class='r10 highlighted-badge font-xxs font-bold'>" + event.extendedProps.age + text + "</span>";
return { html: customHtml }
}

You can use this :
eventClick: function (info) {
showdata(info.event.id);
}
I used v3 and upgrading to v5 and still working.

I also got the same problem when going to get events from back-end,
finally found a solution.
'eventSources'
eventSources: {
url: 'test/getEvents',
type: 'get',
error: function() {
alert('there was an error while fetching events!');
}
}
PHP backend array structure is like this : Example
$events = [
[
'title' => 'All Day Event',
'start' => '2022-07-26T00:00:00+05:30',
'backgroundColor'=> '#f56954', //red
'borderColor' => '#f56954', //red
'allDay' => true
],
[
'title' => 'All Day Event',
'start' => '2022-07-28T00:00:00+05:30',
'backgroundColor'=> '#f56954', //red
'borderColor' => '#f56954', //red
'allDay' => true
]
];
echo json_encode($events);

Related

Full Calender Delete an event which is in recurring sequence

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

Why doesn't ui-grid in Angular Meteor show its data when filter is activated?

Hello I have a problem
Working:
Meteor
Angular Meteor
ui-grid
I follow the plunker example in documentation ui-grid link
The problem is that the data don't show when filters are activated.
I have no errors in console.
I put my code:
html file
<button id='toggleFiltering' ng-click="inventario.toggleFiltering()" class="btn btn-success">Toggle Filtering</button>
<div id="grid1" ui-grid="inventario.gridOptions" class="grid"></div>
js file
class Inventario {
constructor($scope, $reactive, $uibModal, $http, uiGridConstants) {
'ngInject';
$reactive(this).attach($scope);
this.$uibModal = $uibModal;
var today = new Date();
var nextWeek = new Date();
this.highlightFilteredHeader = (row, rowRenderIndex, col, colRenderIndex) => {
if( col.filters[0].term ){
return 'header-filtered';
} else {
return '';
}
};
this.gridOptions = {
enableFiltering: true,
onRegisterApi: (gridApi) => {
this.gridApi = gridApi;
},
columnDefs: [
// default
{ field: 'name', headerCellClass: this.highlightFilteredHeader },
// pre-populated search field
{ field: 'gender', filter: {
term: '1',
type: uiGridConstants.filter.SELECT,
selectOptions: [ { value: '1', label: 'male' }, { value: '2', label: 'female' }, { value: '3', label: 'unknown'}, { value: '4', label: 'not stated' }, { value: '5', label: 'a really long value that extends things' } ]
},
cellFilter: 'mapGender', headerCellClass: this.highlightFilteredHeader },
// no filter input
{ field: 'company', enableFiltering: false, filter: {
noTerm: true,
condition: (searchTerm, cellValue) => {
return cellValue.match(/a/);
}
}},
// specifies one of the built-in conditions
// and a placeholder for the input
{
field: 'email',
filter: {
condition: uiGridConstants.filter.ENDS_WITH,
placeholder: 'ends with'
}, headerCellClass: this.highlightFilteredHeader
},
// custom condition function
{
field: 'phone',
filter: {
condition: (searchTerm, cellValue) => {
var strippedValue = (cellValue + '').replace(/[^\d]/g, '');
return strippedValue.indexOf(searchTerm) >= 0;
}
}, headerCellClass: this.highlightFilteredHeader
},
// multiple filters
{ field: 'age', filters: [
{
condition: uiGridConstants.filter.GREATER_THAN,
placeholder: 'greater than'
},
{
condition: uiGridConstants.filter.LESS_THAN,
placeholder: 'less than'
}
], headerCellClass: this.highlightFilteredHeader},
// date filter
{ field: 'mixedDate', cellFilter: 'date', width: '15%', filter: {
condition: uiGridConstants.filter.LESS_THAN,
placeholder: 'less than',
term: nextWeek
}, headerCellClass: this.highlightFilteredHeader
},
{ field: 'mixedDate', displayName: "Long Date", cellFilter: 'date:"longDate"', filterCellFiltered:true, width: '15%',
}
]
};
$http.get('https://cdn.rawgit.com/angular-ui/ui-grid.info/gh-pages/data/500_complex.json')
.success((data) => {
this.gridOptions.data = data;
this.gridOptions.data[0].age = -5;
data.forEach( function addDates( row, index ){
row.mixedDate = new Date();
row.mixedDate.setDate(today.getDate() + ( index % 14 ) );
row.gender = row.gender==='male' ? '1' : '2';
});
});
this.toggleFiltering = () => {
this.gridOptions.enableFiltering = !this.gridOptions.enableFiltering;
this.gridApi.core.notifyDataChange( uiGridConstants.dataChange.COLUMN );
};
}
}
const name = 'inventario';
// Módulo
export default angular
.module(name, [
uiRouter,
EditarArticulo
])
.component(name, {
templateUrl: `imports/ui/components/${name}/${name}.html`,
controllerAs: name,
controller: Inventario
})
.config(config)
.filter('mapGender', function() {
var genderHash = {
1: 'male',
2: 'female'
};
return function(input) {
if (!input){
return '';
} else {
return genderHash[input];
}
};
});
Given that everything seems to work when filtering is disabled, you must have a problem with the (multiple) filters you have declared.
It is most likely a combination of the filters that is excluding all of your data. Start by commenting out all of the filters (you should see all the data), and then re-introduce the filters one by one until you see the problem again.
This will narrow down the problem, and allow you to see which filter is wrong.

font-awesome icon in display of combobox extjs 6

I tried several ways to set an icon, in the displayfield, when an item of the combo is selected with not luck, this is the fiddle for anyone to want try to help with this. very much appreciated any light.
fiddle example
The only solution is to transform the input type combo in a div with this:
fieldSubTpl: [
'<div class="{hiddenDataCls}" role="presentation"></div>',
'<div id="{id}" type="{type}" style="background-color:white; font-size:1.1em; line-height: 2.1em;" ',
'<tpl if="size">size="{size}" </tpl>',
'<tpl if="tabIdx">tabIndex="{tabIdx}" </tpl>',
'class="{fieldCls} {typeCls}" autocomplete="off"></div>',
'<div id="{cmpId}-triggerWrap" class="{triggerWrapCls}" role="presentation">',
'{triggerEl}',
'<div class="{clearCls}" role="presentation"></div>',
'</div>', {
compiled: true,
disableFormats: true
}
],
Override the setRawValue method of the combo like this:
setRawValue: function (value) {
var me = this;
me.rawValue = value;
// Some Field subclasses may not render an inputEl
if (me.inputEl) {
// me.inputEl.dom.value = value;
// use innerHTML
me.inputEl.dom.innerHTML = value;
}
return value;
},
and style your fake combo div like you want.
Thats because an input on HTML can't have HTML like value inside it.
Keep attenction, the get Value method will return you the HTML inside the div, and maybe you should also override it, but thats the only one method.
You will be able to get the selected value with this method:
Ext.fly(combo.getId()+'-inputEl').dom.innerHTML.replace(/<(.|\n)*?>/gm, '');
If I were you I would like to do something like this:
combo.getMyValue();
So add this property to your combo:
getMyValue:function(){
var combo=this;
if(Ext.fly(combo.id+'-inputEl'))
return Ext.fly(combo.id+'-inputEl').dom.innerHTML.replace(/<(.|\n)*?>/gm, '');
},
Here is a working fiddle
Perhaps my solution is similar to a hack, but it works in 6.7.0 and is a bit simpler.
Tested in Chrome. Theme - Material. For another theme will require minor improvements.
Sencha Fiddle live example
Ext.application({
name: 'Fiddle',
launch: function () {
var store = new Ext.data.Store({
fields: [{
name: 'class',
convert: function (value, model) {
if (value && model) {
var name = value
.replace(/(-o-)|(-o$)/g, '-outlined-')
.replace(/-/g, ' ')
.slice(3)
.trim();
model.data.name = name.charAt(0).toUpperCase() + name.slice(1);
return value;
}
}
}, {
name: 'name'
}],
data: [{
class: 'fa-address-book'
}, {
class: 'fa-address-book-o'
}, {
class: 'fa-address-card'
}]
});
var form = Ext.create('Ext.form.Panel', {
fullscreen: true,
referenceHolder: true,
items: [{
xtype: 'combobox',
id: 'iconcombo',
queryMode: 'local',
editable: false,
width: 300,
valueField: 'class',
displayField: 'name',
store: store,
itemTpl: '<div><i class="fa {class}"></i> {name}</div>',
afterRender: () => {
var component = Ext.getCmp('iconcombo');
var element = document.createElement('div');
element.className = 'x-input-el';
element.addEventListener('click', () => component.expand());
component.inputElement.parent().dom.prepend(element);
component.inputElement.hide();
component.addListener(
'change', (me, newValue, oldValue) => {
component.updateInputValue.call(me, newValue, oldValue);
},
component
);
var method = component.updateInputValue;
component.updateInputValue = (value, oldValue) => {
method.call(component, value, oldValue);
var selection = component.getSelection();
if (selection) {
element.innerHTML =
'<div><i class="fa ' + selection.get('class') + '"></i> ' + selection.get('name') + '</div>';
}
};
}
}, {
xtype: 'button',
text: 'getValue',
margin: '30 0 0 0',
handler: function (component) {
var combo = Ext.getCmp('iconcombo');
alert(combo.getValue());
}
}]
});
form.show();
}
});

FullCalendar - Images as events

Looking to use Full Calendar and to include images as events and draggable. In short, would love to see how this example https://fullcalendar.io/js/fullcalendar-3.0.1/demos/external-dragging.html would work with small thumbnails instead of the text "My Event 1, My Event 2" etc. And have that image show up on the calendar.
Thanks in advance.
You can add any image url to your eventObject by adding the attribute "imageurl" inside of the events definition (if you just want the image, don't specify a title):
events: [
{
title : 'event',
start : '2016-10-12',
end : '2016-10-14',
imageurl:'img/edit.png', //you can pass the image url with a variable if you wish different images for each event
.
.
.
}
After that, you add the following code in the eventRender, which will add the image icon to the event (16 width and height is a good size for a thumbnail):
eventRender: function(event, eventElement) {
if (event.imageurl) {
eventElement.find("div.fc-content").prepend("<img src='" + event.imageurl +"' width='16' height='16'>");
}
},
For further details refer to this question: Add Icon(s) in first line of an event (fullCalendar)
In version Fullcalendar 5 or newer eventRender is no longer used, instead used eventContent
Full code:
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'dayGridMonth',
events: [
{
title: '',
start: '2020-09-02',
image_url: 'images/demo/event-calendar-1.png',
},
{
title: '',
start: '2020-09-02',
image_url: 'images/demo/event-calendar-2.png',
},
{
title: 'Event',
start: '2020-09-17',
image_url: 'images/demo/event-calendar-1.png',
},
{
title: '',
start: '2020-09-19',
image_url: 'images/demo/event-calendar-3.png',
},
{
title: 'Hello',
start: '2020-09-28'
},
],
eventContent: function(arg) {
let arrayOfDomNodes = []
// title event
let titleEvent = document.createElement('div')
if(arg.event._def.title) {
titleEvent.innerHTML = arg.event._def.title
titleEvent.classList = "fc-event-title fc-sticky"
}
// image event
let imgEventWrap = document.createElement('div')
if(arg.event.extendedProps.image_url) {
let imgEvent = '<img src="'+arg.event.extendedProps.image_url+'" >'
imgEventWrap.classList = "fc-event-img"
imgEventWrap.innerHTML = imgEvent;
}
arrayOfDomNodes = [ titleEvent,imgEventWrap ]
return { domNodes: arrayOfDomNodes }
},
});
calendar.render();
});

How to add events to Google Calendar using FullCalendar?

I'm trying in my FullCalendar add events to my google calendar, followed the example below,
How to add events to Google Calendar using FullCalendar
but does not work me, if anyone knows how to do please help.
this my code
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'/>
<link href='../fullcalendar.css' rel='stylesheet'/>
<link href='../fullcalendar.print.css' rel='stylesheet' media='print'/>
<script src='../lib/moment.min.js'></script>
<script src='../lib/jquery.min.js'></script>
<script src='../fullcalendar.min.js'></script>
<script src='../gcal.js'></script>
<script>
$(document).ready(function () {
$('#calendar').fullCalendar({
selectable: true,
selectHelper: true,
var eventData, title;
select: function(start, end) {
title = prompt('Event Title:');
},
editable: true
}
if (title) {
$('#calendar').fullCalendar('renderEvent',
{
title: title,
start: start,
end: end
},
true // make the event "stick"
);
// Now we push it to Google also :
add_event_gcal(title,start,end);
}
}
$('#calendar').fullCalendar('unselect');
});
});
/****** NOW WE ASK THE EVENT TO BE PUSHED TO GOOGLE **************/
function add_event_gcal(title,start,end) {
alert(title);
// I will create the eventInsert script in a new page, and I name it here :
var url = "php/calendrier_add.php",
data = {'titre_event' :title, 'start' : start, 'end' :end};
// I want to check in the page the result of what happened
$('#gcal_loader').load(url,data,function(responseTxt,statusTxt,xhr){
if(statusTxt == "error") alert("Error: " + xhr.status + ": " + xhr.statusText);
});
}
</script>
<style>
body {
margin: 40px 10px;
padding: 0;
font-family: "Lucida Grande", Helvetica, Arial, Verdana, sans-serif;
font-size: 14px;
}
#loading {
display: none;
position: absolute;
top: 10px;
right: 10px;
}
#calendar {
max-width: 900px;
margin: 0 auto;
}
</style>
</head>
<body>
<div id='loading'>loading...</div>
<div id='calendar'></div>
</body>
</html>
this is file php
<?php
// variables can only be got with $_REQUEST ?
$titre_event = $_REQUEST['titre_event'];
$start = $_REQUEST['start'];
$end = $_REQUEST['end'];
$allday = $_REQUEST['allday'];
/*$where_event = $_REQUEST['where_event'];
$content_event = $_REQUEST['content_event'];*/
/********************************************
GOOGLE API CONNECTION
********************************************/
/************************************************
Make an API request authenticated with a service account.
************************************************/
require_once realpath(dirname(__FILE__) . '/../google/autoload.php');// or wherever autoload.php is located
$path = realpath(dirname(__FILE__) . '/../google/autoload.php');
/************************************************
The name is the email address value provided as part of the service account (not your address!)
cf. : https://console.developers.google.com/project/<your account>
************************************************/
$client_id = '1020443454327******'; // YOUR Client ID
$service_account_name ='102044345*****'; // Email Address in the console account
$key_file_location = realpath(dirname(__FILE__) . '/../google/Mi proyecto-edc74d9206de.p12'); // key.p12 to create in the Google API console
echo "key".$key_file_location;
if (strpos($client_id, "googleusercontent") == false || !strlen($service_account_name) || !strlen($key_file_location)) {
echo "no credentials were set.";
exit;
}
/** We create service access ***/
$client = new Google_Client();
/************************************************
If we have an access token, we can carry on. (Otherwise, we'll get one with the help of an assertion credential.)
Here we have to list the scopes manually. We also supply the service account
************************************************/
if (isset($_SESSION['service_token'])) {
$client->setAccessToken($_SESSION['service_token']);
}
$key = file_get_contents($key_file_location);
$cred = new Google_Auth_AssertionCredentials(
$service_account_name,
array('https://www.googleapis.com/auth/calendar'), // ou calendar_readonly
$key
);
$client->setAssertionCredentials($cred);
if ($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion($cred);
}
$_SESSION['service_token'] = $client->getAccessToken();
/********************************************
END OF GOOGLE API CONNECTION
********************************************/
/*********** AT LAAAAST, WE PUSH THE EVENT IN GOOGLE CALENDAR ***************/
// Get the API client and construct the service object.
$service = new Google_Service_Calendar($client);
// We get the calendar
$calendarId = 'qv8rv593gn5g8pumu0bid6bco0#group.calendar.google.com'; // or whatever calendar you like where you have editable rights
/************* INSERT ****************/
$event = new Google_Service_Calendar_Event(array(
'summary' => $titre_event,
//'location' => $where_event,
// 'description' => $content_event,
'start' => array(
'dateTime' => $start, //'2015-06-08T15:00:00Z'
'timeZone' => 'Europe/Paris',
),
'end' => array(
'dateTime' => $end,
'timeZone' => 'Europe/Paris',
),
/* in case you need that :
'attendees' => array(
array('email' => 'lpage#example.com'),
array('email' => 'sbrin#example.com'),
),*/
'reminders' => array(
'useDefault' => FALSE,
'overrides' => array(
array('method' => 'email', 'minutes' => 20)
),
),
));
$event = $service->events->insert($calendarId, $event);
printf('Event created: %s', $event->htmlLink);
?>
I found the answer
https://developers.google.com/google-apps/calendar/v3/reference/events/insert#examples
1)
//Global variables to access the calendar
clientId = 'Your cliendID',
scopes = 'https://www.googleapis.com/auth/calendar',
calendarId = 'Your google calendar id',
eventsList = [];
//Autorice the user
checkAuth();
//authorization in google
function checkAuth() {
gapi.auth.authorize(
{
'client_id': clientId,
'scope': scopes,
'immediate': true
}, handleAuthResult);
}
//checks if authorized
function handleAuthResult(authResult) {
if (authResult && !authResult.error) {
loadCalendarApi();
} else {
handleAuthClick();
}
}
//request credentials
function handleAuthClick() {
gapi.auth.authorize(
{
client_id: clientId,
scope: scopes,
immediate: false
}, handleAuthResult);
return false;
}
function loadCalendarApi() {
gapi.client.load('calendar', 'v3', makeApiCall);
}`
2)
// Load the API and make an API call. Display the results on the screen.
function makeApiCall() {
requestList = gapi.client.calendar.events.list({
'calendarId': calendarId
});
console.log('--- eventsList ---');
console.log(eventsList);
uiCalendarConfig.calendars['myCalendar'].fullCalendar('removeEventSource', eventsList);
eventsList = [];
// Step 6: Execute the API request
requestList
.then(function (resp) {
if (resp.result.error) {
reportError('Google Calendar API: ' + data.error.message, data.error.errors);
} else if (resp.result.items) {
resp.result.items.forEach(function (entry, index) {
eventsList.push({
id: entry.id,
title: entry.summary,
start: entry.start.dateTime || entry.start.date, // try timed. will fall back to all-day
end: entry.end.dateTime || entry.end.date, // same
url: url,
location: entry.location,
description: entry.description
});
});
}
if (eventsList.length > 0) {
uiCalendarConfig.calendars['myCalendar'].fullCalendar('addEventSource', eventsList, true);
}
}, function (reason) {
console.log('Error: ' + reason.result.error.message);
});
}`
3)
//insert into calendar
function makeRpcRequest(eventData) {
gapi
.client
.load('calendar', 'v3')
.then(function () {
request = gapi.client.calendar.events.insert({
'calendarId': calendarId,
'resource': eventData
});
request.then(function (resp) {
if (resp.result.error) {
reportError('Google Calendar API: ' + data.error.message, data.error.errors);
} else {
makeApiCall();
console.log(resp);
var creator = resp.result.creator.email;
var calendarEntry = resp.result.htmlLink;
console.log('--- Calendar entry successfully created by---');
console.log(creator);
console.log('--- dd ---');
console.log(calendarEntry);
}
}, function (reason) {
console.log('Error: ' + reason.result.error.message);
});
});
}`

Resources