Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
Former Member
Previous post https://blogs.sap.com/2017/10/31/using-a-third-party-library-with-sapui5-application-sap-cloud-devel...

Prerequisite :


Download the last Fullcalendar version from https://fullcalendar.io/download/

In my project i used FullCalendar v3.4.0 version



Download the zip file and save it on your local machine. Back to your WEB IDE Project to import files below




SAPUI5 application :


I will not comment each part of my source code because i'm not giving the unique solution. My goal is to show steps needed to build a complete Cloud project.

Create new Folder "lib" under webapp folder and import FullCalendar files



i18n content :
#~~~ Global ~~~~~~~~~~~~~~~~~~~~~~~~~~
title=Title

appTitle = App Title

appDescription=App Description

#~~~ Event View ~~~~~~~~~~~~~~~~~~~~~~~~~~
eventTitle=SAP EBC France - Calendar Planning

unknownError=Unknown Error!

#~~~ Request View ~~~~~~~~~~~~~~~~~~~~~~~~~~
requestTitle=SAP EBC France - Booking Request

formRequestTitle=Booking Request Detail :
hostText=Host
emailcustomer=Email
lastnamecustomer=Last Name
firstnamecustomer=First Name
costcentercustomer=Cost Center

emailrep=Email
lastnamerep=Last Name
firstnamerep=First Name
costcenterrep=Cost Center

evetData=Event data :
requesterText=Requester

evetIDText=Event ID
evetTitleText=Title
descriptionText=Description
saveText=Send Booking Request
cancelText=Cancel

Index.html content :
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta charset="UTF-8">

<title>BookingEBC</title>

<script id="sap-ui-bootstrap"
src="../../resources/sap-ui-core.js"
data-sap-ui-libs="sap.m"
data-sap-ui-theme="sap_belize"
data-sap-ui-compatVersion="edge"
data-sap-ui-preload="async"
data-sap-ui-resourceroots='{"BookingEBC": ""}'>
</script>

<!-- Add FullCalendar API & Script -->
<link href='./lib/fullcalendar.css' rel='stylesheet' />
<script src='./lib/moment.min.js'></script>
<script src='./lib/fullcalendar.js'></script>

<link rel="stylesheet" type="text/css" href="css/style.css">

<script>
sap.ui.getCore().attachInit(function() {
new sap.m.Shell({
app: new sap.ui.core.ComponentContainer({
height : "100%",
name : "BookingEBC"
})
}).placeAt("content");
});
</script>

<style>
body {
width: 800px;
margin: 40px 10px;
padding: 10;
font-family: "Lucida Grande",Helvetica,Arial,Verdana,sans-serif;
font-size: 14px;
}

#calendar {
style="width:60%"
margin: 0 auto;
}
</style>
</head>

<body class="sapUiBody" id="content">
</body>
</html>

View folder content :

V_ROOT.view.xml
<mvc:View controllerName="BookingEBC.controller.V_ROOT" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:mvc="sap.ui.core.mvc"
displayBlock="true" xmlns="sap.m">
<App id="V_Root">
<pages>
<Page title="ROOT">
<content></content>
</Page>
</pages>
</App>
</mvc:View>

V_MAIN.view.xml
<mvc:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m" xmlns:html="http://www.w3.org/1999/xhtml" controllerName="BookingEBC.controller.V_MAIN">
<App class="sapUiResponsiveMargin" width="auto">
<pages>
<Page title="{i18n>eventTitle}">
<content><BusyDialog id="BusyDialog" /></content>
</Page>
</pages>
</App>
</mvc:View>

V_EVENT.view.xml

The integration of Fullcalendar component is done in this view. I added an div tag in the html content, to identify my div i used calendar as an id see also the official documentation here https://fullcalendar.io/docs/usage/
<mvc:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m" xmlns:html="http://www.w3.org/1999/xhtml" controllerName="BookingEBC.controller.V_EVENT">
<App class="sapUiResponsiveMargin" width="auto">
<pages>
<Page title="{i18n>eventTitle}">
<content>
<Label text="{userapi>/name}" visible="false" />
<html:div id="calendar"></html:div>
</content>
</Page>
</pages>
</App>
</mvc:View>

V_REQUEST.view.xml
<mvc:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:l="sap.ui.layout" xmlns:f="sap.ui.layout.form" controllerName="BookingEBC.controller.V_REQUEST">
<App class="sapUiResponsiveMargin" width="auto">
<pages>
<Page title="{i18n>requestTitle}" showNavButton="true" navButtonPress="onNavBack">
<content>
<f:Form id="FormChange354wideDual1" editable="true" >
<f:title>
<core:Title text="{i18n>hostText}"/>
</f:title>
<!-- <f:layout>
<f:ResponsiveGridLayout labelSpanXL="4" labelSpanL="3" labelSpanM="4" labelSpanS="12" adjustLabelSpan="false" emptySpanXL="0" emptySpanL="4" emptySpanM="0" emptySpanS="0" columnsXL="2" columnsL="1" columnsM="1" singleContainerFullSize="false"/>
</f:layout>-->
<f:layout>
<f:ResponsiveGridLayout labelSpanXL="5" labelSpanL="2" labelSpanM="5" labelSpanS="5" adjustLabelSpan="true" emptySpanXL="0" emptySpanL="0" emptySpanM="0" emptySpanS="0" columnsXL="1" columnsL="1" columnsM="1" singleContainerFullSize="true"/>
</f:layout>
<f:formContainers>
<f:FormContainer>
<f:formElements>
<f:FormElement label=" ">
<f:fields>
<Switch id="switchId" state="{globalData>/enableState}" change="onSwitch">
<layoutData>
<FlexItemData growFactor="1"/>
</layoutData>
</Switch>
</f:fields>
</f:FormElement>
<f:FormElement label="{i18n>emailcustomer}">
<f:fields>
<Input value=" " id="emailCustomer" enabled="{globalData>/enableState}" required="{globalData>/enableState}"/>
</f:fields>
</f:FormElement>
<f:FormElement label="{i18n>lastnamecustomer}">
<f:fields>
<Input value=" " id="lastnameCustomer" enabled="{globalData>/enableState}" required="{globalData>/enableState}"/>
</f:fields>
</f:FormElement>
<f:FormElement label="{i18n>firstnamecustomer}">
<f:fields>
<Input value=" " id="firstnameCustomer" enabled="{globalData>/enableState}" required="{globalData>/enableState}"/>
</f:fields>
</f:FormElement>
<f:FormElement label="{i18n>costcentercustomer}">
<f:fields>
<Input id="costcenterCustomer" value="{CUST_COSTCENTER}" required="true" showValueHelp="true" valueHelpOnly="false" valueHelpRequest="onValueHelpRequestCustomer"/>
</f:fields>
</f:FormElement>
</f:formElements>
</f:FormContainer>
</f:formContainers>
</f:Form>
<f:Form id="FormChange354wideDual2" editable="true" >
<f:title>
<core:Title text="{i18n>requesterText}"/>
</f:title>
<!-- <f:layout>
<f:ResponsiveGridLayout labelSpanXL="4" labelSpanL="3" labelSpanM="4" labelSpanS="12" adjustLabelSpan="false" emptySpanXL="0" emptySpanL="4" emptySpanM="0" emptySpanS="0" columnsXL="2" columnsL="1" columnsM="1" singleContainerFullSize="false"/>
</f:layout>-->
<f:layout>
<f:ResponsiveGridLayout labelSpanXL="5" labelSpanL="2" labelSpanM="5" labelSpanS="5" adjustLabelSpan="true" emptySpanXL="0" emptySpanL="0" emptySpanM="0" emptySpanS="0" columnsXL="1" columnsL="1" columnsM="1" singleContainerFullSize="true"/>
</f:layout>
<f:formContainers>
<f:FormContainer>
<f:FormElement label="" visible="false">
<f:fields>
<Input value="{userapi>/name}" id="nameRep" enabled="false"/>
</f:fields>
</f:FormElement>
<f:FormElement label="{i18n>emailrep}">
<f:fields>
<Input value="{userapi>/email}" id="emailRep" enabled="false"/>
</f:fields>
</f:FormElement>
<f:FormElement label="{i18n>lastnamerep}">
<f:fields>
<Input value="{userapi>/lastName}" id="lastnameRep" enabled="false"/>
</f:fields>
</f:FormElement>
<f:FormElement label="{i18n>firstnamerep}">
<f:fields>
<Input value="{userapi>/firstName}" id="firstnameRep" enabled="false"/>
</f:fields>
</f:FormElement>
<f:FormElement label="{i18n>costcenterrep}">
<f:fields>
<Input id="costcenterRep" value="{SREP_COSTCENTER}" required="true" showValueHelp="true" valueHelpOnly="false" valueHelpRequest="onValueHelpRequestSalesRep"/>
</f:fields>
</f:FormElement>
<f:formElements>
<f:FormElement label="{i18n>evetIDText}" visible="false">
<f:fields>
<Input value="{ID}" id="eventID"/>
</f:fields>
</f:FormElement>
<f:FormElement label="{i18n>evetTitleText}">
<f:fields>
<Input value="{TITLE}" id="titleID" maxLength="50"/>
</f:fields>
</f:FormElement>
<f:FormElement label="{i18n>startDateText}" visible="false">
<f:fields>
<Input value="{START_DATE}" id="startDateID"/>
</f:fields>
</f:FormElement>
<f:FormElement label="{i18n>endDateText}" visible="false">
<f:fields>
<Input value="{END_DATE}" id="endDateID"/>
</f:fields>
</f:FormElement>
<f:FormElement label="{i18n>colorText}" visible="false">
<f:fields>
<Input value="{COLOR}" id="colorID"/>
</f:fields>
</f:FormElement>
<f:FormElement label="{i18n>statusText}" visible="false">
<f:fields>
<Input value="{STATUS}" id="statusID"/>
</f:fields>
</f:FormElement>
<f:FormElement label="{i18n>descriptionText}">
<f:fields>
<TextArea value="{DESCRIPTION}" id="descriptionID" rows="8"/>
</f:fields>
</f:FormElement>
<f:FormElement label="{i18n>yearText}" visible="false">
<f:fields>
<Input value="{YEAR}" id="yearID"/>
</f:fields>
</f:FormElement>
<f:FormElement label="{i18n>monthText}" visible="false">
<f:fields>
<Input value="{MONTH}" id="monthID"/>
</f:fields>
</f:FormElement>
<f:FormElement label="{i18n>dayText}" visible="false">
<f:fields>
<Input value="{DAY}" id="dayID"/>
</f:fields>
</f:FormElement>
</f:formElements>
</f:FormContainer>
</f:formContainers>
</f:Form>
</content>
<footer>
<Bar>
<contentRight>
<Button id="save" text="{i18n>saveText}" type="Emphasized" press="onSave"/>
<Button id="cancel" text="{i18n>cancelText}" press="onNavBack"/>
</contentRight>
</Bar>
</footer>
</Page>
</pages>
</App>
</mvc:View>

Controller folder content :

V_ROOT.controller.js 
sap.ui.define([
"sap/ui/core/mvc/Controller"
], function(Controller) {
"use strict";

return Controller.extend("BookingEBC.controller.V_ROOT", {

});
});

V_MAIN.controller.js
sap.ui.define([
"sap/ui/core/mvc/Controller"
], function(Controller) {
"use strict";

return Controller.extend("BookingEBC.controller.V_MAIN", {
//Initial Load
onInit: function()
{
},

// After Loading UI5 component
onAfterRendering: function()
{
var oDialog = this.getView().byId("BusyDialog");
oDialog.open();

jQuery.sap.delayedCall(2000, this, function () {
oDialog.close();
});
this.goToEventCalendar();
},

goToEventCalendar: function()
{
var date = new Date();
var currentDay = date.getFullYear() + "-" + ("0" + (date.getMonth() + 1)).slice(-2) + "-" + ("0" + date.getDate()).slice(-2);

// Now Get the Router Info
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);

// Tell the Router to Navigate To Route_Event which is linked to V_EvenT view
oRouter.navTo("Route_Event", {SelectedDate: currentDay});
}
});
});

V_EVENT.controller.js

This is the main point to integrate Fullcalndar component so i will explain how we can do it.

OnInit() function validate the Rout config and call the _onRouterFound. See

https://sapui5.hana.ondemand.com/1.36.9/docs/guide/e5200ee755f344c8aef8efcbab3308fb.html for more information about routing and navigation



_onRouterFound() read the navigation route arguments and call _readBackEndEvents()

Note : I'm using a date as a parameter in my Route Pattern



_readBackEndEvents() call the Events Entity from our Odata service



_mapResults() Read data from Events Entity and save it to a local array variable "events".  To manage and use the Fullcalendar component we have this instruction :
this.byId("calendar").$().fullCalendar({});

		//MAP JSON Resut To Model
_mapResults: function(data, SelectedDate)
{
var events = [];
var self = this;

for (var i = 0; i < data.results.length; i++)
{
events.push({
id: data.results[i].ID,
title: data.results[i].TITLE,
start: data.results[i].START_DATE,
end: data.results[i].END_DATE,
status: data.results[i].STATUS,
color: data.results[i].COLOR
});
}

this.byId("calendar").$().fullCalendar(
{
// Alow click
eventClick: function(calEvent, jsEvent, view)
{
self.goToRequestForm(calEvent);
},

// put your options and callbacks here
header:
{
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek'
},
height: 700,
weekends: false,
minTime: "09:00:00",
maxTime: "20:0:00",
defaultDate: SelectedDate, //'2017-05-12',
defaultView: 'agendaWeek',
navLinks: true, // can click day/week names to navigate views
editable: false,
eventLimit: true, // allow "more" link when too many events
//events: events,
allDay: false
});

this.byId("calendar").$().fullCalendar('removeEvents');
this.byId("calendar").$().fullCalendar( 'addEventSource', events);
this.byId("calendar").$().fullCalendar( 'refetchEvents' );
},

Complete source code :
sap.ui.define([
"sap/ui/core/mvc/Controller"
], function(Controller) {
"use strict";

return Controller.extend("BookingEBC.controller.V_EVENT", {
//Initial Load
onInit: function()
{
// Call UserAPI and stored into a JSON Model
var userModel = new sap.ui.model.json.JSONModel("/services/userapi/currentUser");
this.getView().setModel(userModel, "userapi");

// Get the Router Info
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);

// Validate/Match the Router Details sent from source using oRouter.navTo("Route_Event", {SelectedDate: selectedDate});
oRouter.getRoute("Route_Event").attachMatched(this._onRouteFound, this);
},

_onRouteFound: function(oEvt)
{
var oArgument = oEvt.getParameter("arguments");
this._readBackEndEvents(oArgument.SelectedDate);
},

_readBackEndEvents: function(SelectedDate)
{
var oODataModel = sap.ui.getCore().getModel();
var self = this;

oODataModel.read("/Events", {
method: "GET",
success: function(data, oResponse)
{
self._mapResults(data, SelectedDate);
},
error: function()
{
// show error messge
sap.m.MessageToast.show("unknownError");
}
});
},

// After Loading UI5 component
onAfterRendering: function()
{
//this._readBackEndEvents();
/* var oODataModel = sap.ui.getCore().getModel();
var self = this;

oODataModel.read("/Event", {
method: "GET",
success: function(data, oResponse)
{
self._mapResults(data);
},
error: function()
{
// show error messge
sap.m.MessageToast.show("unknownError");
}
}); */
},

//MAP JSON Resut To Model
_mapResults: function(data, SelectedDate)
{
var events = [];
var self = this;

for (var i = 0; i < data.results.length; i++)
{
events.push({
id: data.results[i].ID,
title: data.results[i].TITLE,
start: data.results[i].START_DATE,
end: data.results[i].END_DATE,
status: data.results[i].STATUS,
color: data.results[i].COLOR
});
}

this.byId("calendar").$().fullCalendar(
{
// Alow click
eventClick: function(calEvent, jsEvent, view)
{
self.goToRequestForm(calEvent);
},

// put your options and callbacks here
header:
{
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek'
},
height: 700,
weekends: false,
minTime: "09:00:00",
maxTime: "20:0:00",
defaultDate: SelectedDate, //'2017-05-12',
defaultView: 'agendaWeek',
navLinks: true, // can click day/week names to navigate views
editable: false,
eventLimit: true, // allow "more" link when too many events
//events: events,
allDay: false
});

this.byId("calendar").$().fullCalendar('removeEvents');
this.byId("calendar").$().fullCalendar( 'addEventSource', events);
this.byId("calendar").$().fullCalendar( 'refetchEvents' );
},

goToRequestForm: function(calEvent)
{
//The requester can click only on a Green Slot
if (calEvent.status !== "F")
{
return;
}
// Get Property of the Clicked Item. i.e. Event.id of the item which was clicked
var selectEventID = calEvent.id; //calEvent.getSource().getBindingContext().getProperty("id");

// Now Get the Router Info
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);

// Tell the Router to Navigate To Route_Request which is linked to V_REQUEST view
oRouter.navTo("Route_Request", {SelectedItem: selectEventID});
}
});
});

V_EVENT.controller.js
sap.ui.define([
"sap/ui/core/mvc/Controller"
], function(Controller) {
"use strict";

return Controller.extend("BookingEBC.controller.V_EVENT", {
//Initial Load
onInit: function()
{
// Call UserAPI and stored into a JSON Model
var userModel = new sap.ui.model.json.JSONModel("/services/userapi/currentUser");
this.getView().setModel(userModel, "userapi");

// Get the Router Info
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);

// Validate/Match the Router Details sent from source using oRouter.navTo("Route_Event", {SelectedDate: selectedDate});
oRouter.getRoute("Route_Event").attachMatched(this._onRouteFound, this);
},

_onRouteFound: function(oEvt)
{
var oArgument = oEvt.getParameter("arguments");
this._readBackEndEvents(oArgument.SelectedDate);
},

_readBackEndEvents: function(SelectedDate)
{
var oODataModel = sap.ui.getCore().getModel();
var self = this;

oODataModel.read("/Events", {
method: "GET",
success: function(data, oResponse)
{
//self.byId("calendar").$().fullCalendar('removeEvents');
self._mapResults(data, SelectedDate);
},
error: function()
{
// show error messge
sap.m.MessageToast.show("unknownError");
}
});
},

// After Loading UI5 component
onAfterRendering: function()
{
//this._readBackEndEvents();
/* var oODataModel = sap.ui.getCore().getModel();
var self = this;

oODataModel.read("/Event", {
method: "GET",
success: function(data, oResponse)
{
self._mapResults(data);
},
error: function()
{
// show error messge
sap.m.MessageToast.show("unknownError");
}
}); */
},

//MAP JSON Resut To Model
_mapResults: function(data, SelectedDate)
{
//sap.ui.commons.MessageBox.alert("Current Month" + SelectedDate);
var events = [];
var self = this;

for (var i = 0; i < data.results.length; i++)
{
events.push({
id: data.results[i].ID,
title: data.results[i].TITLE,
start: data.results[i].START_DATE,
end: data.results[i].END_DATE,
status: data.results[i].STATUS,
color: data.results[i].COLOR
});
}


this.byId("calendar").$().fullCalendar(
{
// Good method to change rendering
/* eventAfterRender: function (event, element, view) {
if (event.status === "F")
{
element.css('background-color', '#77DD77');
} else if (event.status === "W")
{
element.css('background-color', '#FFFF00');
} else if (event.status === "B")
{
element.css('background-color', '#FF0000');
}
},*/

// Alow click
eventClick: function(calEvent, jsEvent, view)
{
self.goToRequestForm(calEvent);
},

// Catch navigation click on calendar object
/* viewRender: function (view, element)
{
var b = view.start._d;
var m = b.getMonth();
sap.ui.commons.MessageBox.alert("Current Month" + m);
},*/

// put your options and callbacks here
header:
{
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek'
},
height: 700,
weekends: false,
minTime: "09:00:00",
maxTime: "20:0:00",
defaultDate: SelectedDate, //'2017-05-12',
defaultView: 'agendaWeek',
navLinks: true, // can click day/week names to navigate views
editable: false,
eventLimit: true, // allow "more" link when too many events
//events: events,
allDay: false
});

this.byId("calendar").$().fullCalendar('removeEvents');
this.byId("calendar").$().fullCalendar( 'addEventSource', events);
this.byId("calendar").$().fullCalendar( 'refetchEvents' );
},

goToRequestForm: function(calEvent)
{
//The requester can click only on a Green Slot
if (calEvent.status !== "F")
{
return;
}
// Get Property of the Clicked Item. i.e. Event.id of the item which was clicked
var selectEventID = calEvent.id; //calEvent.getSource().getBindingContext().getProperty("id");

// Now Get the Router Info
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);

// Tell the Router to Navigate To Route_Request which is linked to V_REQUEST view
oRouter.navTo("Route_Request", {SelectedItem: selectEventID});
}
});
});

Conclusion :


This is the last part of my series i hope this content will help you to understand what we need to complete an End-To-End SAP development Cloud scenario. Below a list of skills needed :

  1. Front End/UI Part ( JavaScript, HTML, CSS, SAPUI5 ), WEB IDE utilisation

  2. SCP Cloud Platform ( set up, connectivity )

  3. Odata Knowledge and how to consume our service in the Front-End app

  4. Back-End Development ( it will depend of your technologie ) in my case i used a HANA MDC so XSJS and SQL Skills, table creation, some admin tasks ( creating users/roles )


 
1 Comment
Labels in this area