Skip to Content
Technical Articles
Author's profile photo Sai Sreelekha Suraparaju

Planning Calendar in SAP UI5

Hi All,

In this blog post, I am going to explain a business scenario that I had gone through and how I gave a solution to it.

Business Scenario:

Develop a web application that shows a calendar showing which agent is assigned to jobs on which days at which location.

Solution:

I have designed and developed SAP UI5 Responsive Web Application using sap.m.planningcalendar which displays rows with appointments for different entities (such as persons or teams) for the selected time interval.

About Planning Calendar:

Planning Calendar containing multiple rows with appointments, where each row represents a different person.

We can configure different time-interval views that make us switch between, such as hours or days, and even a whole week/month. The available navigation allows us to select a specific interval using a picker, or move to the previous/next interval using arrows.

The PlanningCalendar uses parts of the sap.ui.unified library.

Logon to the Business Application Studio and follow the below steps.

Step 1:

Create a Sample Application named “Planning Calendar”.

Step 2:

Step 2.1: Open the View1.view.xml file and add the below libraries.

xmlns:core=”sap.ui.core”

xmlns:unified=”sap.ui.unified”

Step2.2: Add the below code.

<PlanningCalendar
			id="PC1"
			startDate="{path: '/startDate'}"
			rows="{path: '/people'}"
			appointmentsVisualization="Filled"
			appointmentSelect="handleAppointmentSelect"
			showEmptyIntervalHeaders="false"
			showWeekNumbers="true">	
			<rows>
				<PlanningCalendarRow				
					title="{name}"				
					appointments="{path : 'appointments', templateShareable: true}">				
					<appointments>
						<unified:CalendarAppointment
							startDate="{start}"
							endDate="{end}"							
							title="{title}"
							text="{info}"
							type="{type}"
							tentative="{tentative}">
						</unified:CalendarAppointment>
					</appointments>					
				</PlanningCalendarRow>
			</rows>
		</PlanningCalendar>	

Step3:

Open the View1.controller.js file and add the below code.

  onInit: function () {
                // create model
                var oModel = new JSONModel();
                oModel.setData({
                    startDate: new Date("2020", "11", "01", "8", "0"),
                    people: [{
                        name: "Sunil",
                        appointments: [
                            {
                                start: new Date("2020", "11", "1", "08", "30"),
                                end: new Date("2020", "11", "8", "09", "30"),
                                title: "Telangana",
                                info: "Manikonda,Hyderabad",                               
                                type: "Type02",
                                tentative: false
                            },
                            {
                                start: new Date("2020", "11", "11", "10", "0"),
                                end: new Date("2020", "11", "11", "12", "0"),
                                title: "Andhra Pradesh",
                                info: "Balaji Colony,Tirupathi",
                                type: "Type01",
                                tentative: false
                            },
                            {
                                start: new Date("2020", "11", "15", "10", "0"),
                                end: new Date("2020", "11", "15", "12", "0"),
                                title: "Andhra Pradesh",
                                info: "MVP Colony,Visakapatnam",
                                type: "Type01",
                                tentative: false
                            }


                        ]

                    },
                    {
                        name: "Anil",
                        appointments: [
                            {
                                start: new Date("2020", "11", "1", "18", "00"),
                                end: new Date("2020", "11", "2", "19", "10"),
                                title: "Telangana",
                                info: "Madhapur,Hyderabad",
                                type: "Type04",
                                tentative: false
                            },
                            {
                                start: new Date("2020", "11", "5", "18", "00"),
                                end: new Date("2020", "11", "8", "19", "10"),
                                title: "Telangana",
                                info: "Banjara Hills,Hyderabad",
                                type: "Type04",
                                tentative: false
                            },
                            {
                                start: new Date("2020", "11", "11", "18", "00"),
                                end: new Date("2020", "11", "15", "19", "10"),
                                title: "Andhra Pradesh",
                                info: "Rushikonda,Visakapatnam",
                                type: "Type04",
                                tentative: false
                            }
                        ]

                    },
                    {
                        name: "Chaithanya",
                        appointments: [
                            {
                                start: new Date("2020", "11", "15", "08", "30"),
                                end: new Date("2020", "11", "15", "09", "30"),
                                title: "Telangana",
                                info: "Jiblee Hills,Hyderabad",
                                type: "Type02",
                                tentative: false
                            },

                            {
                                start: new Date("2020", "11", "1", "11", "0"),
                                end: new Date("2020", "11", "31", "23", "59"),
                                title: "Telangana",
                                info: "Mothi Nagar,Hyderabad",
                                type: "Type10",
                                tentative: false
                            }
                        ]

                    }
                    ]
                });
                this.getView().setModel(oModel);

            }

Step4:

Run the Application. The Output screen would be like below. By default Hours view will be selected.

We can navigate to different Views by selecting options available in the dropdown like below.

We can see 1 month View in Ipad Mode like below:

Step5:

Sometimes in Month view, we can’t able to see the clear information (Location) of the appointment. For that, we are adding a message box to pops up while clicking on the selected appointment.

Add the below function in js file.

 handleAppointmentSelect: function (oEvent) {
                var oAppointment = oEvent.getParameter("appointment"),
                    sSelected;
                if (oAppointment) {
                    sSelected = oAppointment.getSelected() ? "selected" : "deselected";                    
                    MessageBox.show("'" + oAppointment.getTitle() + "' " + sSelected +"\n"+ oAppointment.getText());
                } else {
                    var aAppointments = oEvent.getParameter("appointments");
                    var sValue = aAppointments.length + " Appointments selected";
                    MessageBox.show(sValue);
                }
            }

Reload the application and click on any of the appointments to show detailed info.

Conclusion: By the following, we have successfully visualized the Agent details clearly in different Views.

 

I hope it helps.

Thank you.

Assigned Tags

      7 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Maciej Kaczmarek
      Maciej Kaczmarek

      Hello Sai,

      nice example, this was exactly I was looking for.

      I'm trying to map fields of type date from ODataSource into the single Instance unified:CalendarAppointment but can't see any appointments in the calendar controll.

      <SinglePlanningCalendar
                          class="sapUiSmallMarginTop"
                          viewChange="handleViewChange"
                          headerDateSelect="handleHeaderDateSelect"
                          moreLinkPress="handleMoreLinkPress"
                          startDate="{path: 'ConfState>/date'}"
                          enableAppointmentsDragAndDrop="false"
                          enableAppointmentsResize="false"
                          enableAppointmentsCreate="false"
                          appointments="{path: '/xFFLExTimCnFSet'}">
                      <views>
                          <SinglePlanningCalendarDayView key="DayView" title="{i18n>filter.time.day}"/>
                          <SinglePlanningCalendarWeekView key="WeekView" title="{i18n>filter.time.week}"/>
                          <SinglePlanningCalendarMonthView key="MonthView" title="{i18n>filter.time.month}"/>
                      </views>
                      <appointments>
                          <unified:CalendarAppointment
                                  title="{Description}"
                                  text="{Description}"
                                  type="{TimSta}"
                                  icon="{icon}"
                                  startDate="{StartDate}"
                                  endDate="{EndDate}">
                          </unified:CalendarAppointment>
                      </appointments>
                  </SinglePlanningCalendar>

      My single data item from ODataSource (the root path is here /xFFLExTimCnFSet) has fields StartDate, StartTime, EndDate, EndTime, Description, ...

      Is there anything special I have to care about? Maybe the problem ist that the fields "StartDate" and "EndDate" contains only day, month and year values and time value is zero.  How would be the best approach to combine those StartDate+StartTime and EndDate+EndTime repectivelly before the data will is given to the Calendar control?

      Thanks!

      Author's profile photo Rufat Gadirov
      Rufat Gadirov

      Hi Maciej Kaczmarek,

      I have the exact same issue. How did you solve it? The planning calendar expects a Javascript Date Object via new...but how to pass this via SAP CAP CDS OData behind it? I tested both with datatype Date and DateTime.

      BR
      Rufat

      Author's profile photo Maciej Kaczmarek
      Maciej Kaczmarek

      Hello Rufat,

       

      what do you mean with "expects a Javascript Date Object via new..." ?

      My current view works now and is like (TimeState is JsonModel bound to this view):

      <SinglePlanningCalendar
      					id="confCalendar"
      					headerDateSelect="onCalDateHeaderChange"
      					viewChange="onCalViewChange"
      					startDateChange="onCalDateChange"
      					moreLinkPress="onCalMoreLinkPress"
      					startDate="{path: 'TimeState>/date'}"
      					enableAppointmentsDragAndDrop="false"
      					enableAppointmentsResize="false"
      					enableAppointmentsCreate="false"
      					appointments="{path: 'time>/xFFLExTimCnFSet', templateShareable: false, parameters: {operationMode: 'Client'}}"
      					appointmentSelect="onSelectConf"
      					stickyMode="All">
      				<views>
      					<SinglePlanningCalendarDayView key="DayView" title="{i18n>times.filter.time.day}"/>
      					<SinglePlanningCalendarWeekView key="WeekView" title="{i18n>times.filter.time.week}"/>
      					<SinglePlanningCalendarMonthView key="MonthView" title="{i18n>times.filter.time.month}"/>
      				</views>
      				<actions>
      					<Button
      							icon="sap-icon://travel-itinerary"
      							press=".onCreateConf($event, 'T')"
      							text="{parts: [{path: 'deviceModel>/isNoPhone'}, {path: 'i18n>times.travel.title'}], formatter: '.timeState.formateButtonTextCalendar'}"
      							visible="{TimeState>/VISIBLE/CREATE_TRAVEL_CONF_BUTTON}"
      					/>
      					<Button text="{parts: [{path: 'deviceModel>/isNoPhone'}, {path: 'i18n>times.work.title'}], formatter: '.timeState.formateButtonTextCalendar'}"
      							icon="sap-icon://timesheet" press=".onCreateConf($event, 'W')"/>
      				</actions>
      				<appointments>
      					<unified:CalendarAppointment
      							title="{time>AccDesc}"
      							text="{=${time>Description}!=='' ? ${time>Description}.slice(0,50) : ${time>Description}.length > 50 ? '...': ''}"
      							type="{parts: [{path: 'time>TimCat'}], formatter: '.timeState.formatCalenderType'}"
      							icon="{parts: [{path: 'time>'}], formatter: '.timeState.getTimeItemIcon'}"
      							startDate="{parts: [{path: 'time>StartDate'}, {path: 'time>StartTime'}], formatter: '.timeState.formatCalenderDate'}"
      							endDate="{parts: [{path: 'time>EndDate'}, {path: 'time>EndTime'}], formatter: '.timeState.formatCalenderDate'}">
      					</unified:CalendarAppointment>
      				</appointments>
      			</SinglePlanningCalendar>
      Author's profile photo Rufat Gadirov
      Rufat Gadirov

      Hi Maciej Kaczmarek,

      thank you, I just had issues with the date format. Can you show a snippet of your data model, please? I am using CAP CDS with data type DateTime, didn´t succeed yet.  Otherwise, I got the mentioned errors.

      BR
      Rufat

      Author's profile photo Manoj Yadav
      Manoj Yadav

      Hello,

      If i want to pass date from Odata, in which format it should be?

      Regards,

      Manoj

      Author's profile photo FIRAT ASAN
      FIRAT ASAN

      Thank you Sai Sreelekha Suraparaju,

      that's good blog and helpful. But i want to ask how u set your OData Structure? And how we can do entity under entity without association.

       

      For example we have firma information like :

      {Company Name:

      Company Adress:

      Company Budget:

      Company Products :{

      Product name:

      Product size:

      Product price: }

      }

       

      I want to ask exactly how can we set up OData Structure with only one Entity set for planning calendar.

       

       

      Author's profile photo Mamatha Majji
      Mamatha Majji

      Hi Firat,

      In OData Using one Entity we can achieve this, in UI by filtering the  whole response Data from OData Service with Unique Key i.e.., either Person Id or Person Name push into one Array named Appointments or any respective Array Name.

      By this after filtering the Data you will get the Data similar to this like below:

      1. OData Response Data which has 79 Records initially.

      Response%20Data%20from%20OData%20Call

      Response Data from OData Call

        2. After filtering the  whole OData Response with unique record then got 12 records.

        Filtered%20Data

      Filtered Data

        3. Now in this Filtered Array each record has Appointments Array as shown below:

          With%20Appointments%20inner%20Array

      With Appointments inner Array

       So by this way you can bind the appointments to calendar. But this causes some performance issue   when we have huge number of records say like 10k, so in that case better to create a Deep Entity   at  backend which has header and Item Entities which is better approach for eradicating the   performance issue further.

       

      Regards,

      Mamatha M