Calendar¶
The calendar view provides a visual overview of a week, a month, or both. It supports both single or range date selection. It also allow Use calendar view to filter the information based on days. For example, events, tasks, and deadlines.
The calendar consists of three parts: header, weekday label, and dates.
Calendar Structure¶
Calendar Header¶
The header displays the current month or selected date information if a date is selected. For Android, there are components on the right side (not applicable for DateRange type): a back-to-today button (small calendar icon) allows you to return to the current month or week by tapping the button. Left and right arrow buttons enable navigation between months or weeks.
Weekday Label¶
A one-letter label shows the weekday as the column header of the calendar. StartDayOfWeek customizes the start day of the week to either Sunday, Saturday, or Monday. The default is Sunday.
Date Label Container¶
The date label container shows all the days of the month/week in a grid view.
Legend¶
The legend section will display the icon and title of the event indicators to give user meaningful information of the events on the calendar. It will only be visible if you have defined event indicators and the visible month or week has events.
Dragging Handle¶
The dragging handle provides a visual cue on the dragging behavior to expand the week view and collapse the month view when calendar type is set to Expendable.
Other Features¶
Calendar Type¶
Calendar support various types:
Month- Displays the calendar in month view. Only single date selection is applicable.
Week- Displays the calendar in week view. Only single date selection is applicable.
Expandable- Displays the calendar in either week or month view. A dragging handle allows you to expand from week view to month view by swiping down. You can collapse from month view to week view by swiping up. Only single date selection is applicable.
DateRange- Displays the calendar similar to month view but allows more than one month to be displayed. You may scroll vertically through the calendar months. Use this type to allow range selection. The first date selected is the start date of the range, and when a second date is selected, it becomes the end date of the range, with the entire range of dates between the start and end dates (inclusive) being selected. To modify the set of selected dates on iOS, click on a selected date within the range, and it becomes the new end date, with all later dates deselected. To unselect the entire range, click outside the range, anywhere in the calendar view. For Android, any click on a date within or outside the selected range results in deactivating the existing range. The end date of the range must be later than the start date. If you click on a date earlier than the start date, the newly selected date becomes the start date, and the original start date is deselected. Specifically for
DateRangetype, in multi-section scenarios, the calendar displays with default height (600 for Android and 450 for iOS), while in single-section scenarios, the calendar displays in full screen. You may customize the height of the calendar by specifying theHeightproperty in the metadata definition for both single and multi-section scenarios.
- Displays the calendar similar to month view but allows more than one month to be displayed. You may scroll vertically through the calendar months. Use this type to allow range selection. The first date selected is the start date of the range, and when a second date is selected, it becomes the end date of the range, with the entire range of dates between the start and end dates (inclusive) being selected. To modify the set of selected dates on iOS, click on a selected date within the range, and it becomes the new end date, with all later dates deselected. To unselect the entire range, click outside the range, anywhere in the calendar view. For Android, any click on a date within or outside the selected range results in deactivating the existing range. The end date of the range must be later than the start date. If you click on a date earlier than the start date, the newly selected date becomes the start date, and the original start date is deselected. Specifically for
Navigation¶
To navigate between months or weeks in sequence, use left and right arrow buttons for Android, and scroll for iOS.
Selection Behavior¶
The selected date is displayed based on today's date by default. You can customize it through metadata definition or ClientAPI. You may change the selected date by tapping the desired date. For DateRange type, you need to select two dates to form a valid range. IsPersistentSelection is a flag that determines the behavior of the selection. When set to true (the default), the selected date is retained even when you navigate to other months. If the flag is set to false, when you navigate to another month, the first day of the displayed month is shown as selected. IsPersistentSelection is not applicable for DateRange type and defaults to true.
Calendar Range Limit¶
There is a limit to the months you can navigate. The calendar is limited with a start date and end date. The start date defaults to January 1st of two years prior to the initially selected date. The end date defaults to December 31st of two years following the initially selected date. You may customize the limit by defining StartDate and EndDate on metadata definition.
Selected Date¶
When user selects a date in a single selection calendar type, an event OnSelectedDateChange will be triggered.
In DateRange calendar type, when you complete selection of a date range, an event OnSelectedDateRangeChange will be triggered.
If you have defined events and the selected date(s) has events tied to it:
- In single date selection type (
Month,Week, orExtendable), you will also receive a binding that's an object with propertiesIndicatorNameandEntitySetscontaining the related entities. - In date range selection type (
DateRange), you will also receive a binding that's an array of object with propertiesDate,IndicatorNameandEntitySetscontaining the related entities.
See Event Indicators topic below for more details.
You can get or set selected date programmatically via CalendarProxy's getSelectedDate and setSelectedDate API for single date selection calendar type, or getSelectedDateRange or setSelectedDateRange API for date range calendar type.
Event Indicators¶
You can use Calendar Event Indicators to identify special events or statuses directly on the calendar. This feature helps you quickly spot important dates and plan effectively. The indicators have customizable appearances and can be dynamically assigned based on metadata or runtime data. This provides an efficient way to manage and view calendar events.
Indicators¶
You can define a list of indicators in the Indicators property that accept an array of indicator definition, each indicator is represented by a name, icon and title.
- The name will be used to reference the indicator to display in an event
- The icon will be displayed in each of the date in the calendar that has an event
- Both icon and title will be displayed as part of the legend section in the calendar
You can then display these indicators in your calendar by specifying their name in events via the calendar's Events or Event property.
Events¶
There are 2 ways you can populate events in the Calendar. Using static array via Events property or using dynamic binding list via Event property:
-
Eventscan be used if you wish to construct your own list of events and return them as an array via rule. This is useful if you wish you have full control on how you retrieve data and construct the list of events for your Calendar. However, you must retrieve all events in one go as it does not support on-demand loading. Each item in the array is an object that must haveIndicatorNameandDate:Dateindicates which date (in ISO 8601 format) in the calendar must be display the indicator.IndicatorNamethat specify the indicator that'll be displayed for that that event. The value should match one of the indicators' name you have predefined in theIndicatorsproperty.
-
Eventcan be used if you wish to make use of theTargetsbinding to populate events in your calendar. TheEventobject accepts only a single propertyIndicatorNamethat specifies the indicator that'll be displayed for that event. The value should match one of the indicators' name you have predefined in theIndicatorsproperty. Typically, you will use rule to decide which indicator's name to return for each populated date.To populate the events using
Event, you need to defineTargets(note on the plural naming) binding, It accepts an array ofTargetdefinition. EachTargetaccepts the standard target binding specifiers such asService,EntitySet, andQueryOptions, but it also accept a calendar specific property calledDatePropertieswhich accept an array.DatePropertiesallows you to specify one or more properties of your Entity Set that should be used as filter criteria for on-demand querying of events data. These properties must be of typeDateorDateTime. The filters for multiple date properties will be combined usingORoperator.
Targets Binding Example¶
The following example will guide you on how to use Event and Targets for dynamic binding of events in your calendar. Let's assume you have defined your calendar as the following:
{
"_Type": "Section.Type.Calendar",
"_Name": "CalendarSection",
"Indicators":[{
"_Name": "UpcomingIndicator",
"Icon": "sap-icon://to-be-reviewed",
"Title": "Upcoming Deadline",
"Style": {
"Icon": "GreenColorStyle"
}
},{
"_Name": "OverdueIndicator",
"Icon": "sap-icon://alert",
"Title": "Overdue",
"Style": {
"Icon": "WarningColorStyle"
}
},{
"_Name": "HighPrioOverdueIndicator",
"Icon": "sap-icon://error",
"Title": "Overdue (Critical)",
"Style": {
"Icon": "CriticalColorStyle"
}
}],
"Event": {
"IndicatorName": "/MyApp/Rules/GetIndicators.js"
},
"Targets": [
{
"Service":"/MyApp/Services/EquipmentMaintenance.service",
"EntitySet": "ServiceOrders",
"DateProperties":["DueDate"]
}
]
}
Whenever user scrolls through the calendar, the app will send queries to retrieve ServiceOrders entities with DueDate that fall within the months that user is scrolling to. Finally, the app will render the indicators on the dates that matches the entities' DueDate.
By default, at least 3 months of data will be retrieved, which is the month user scrolled to and the month before and after, it can be configured with EventLoadRange.
If user scrolls to the month of September 2025, a query that looks like this /ServiceOrders?$filter=(DueDate ge datetime'2025-08-01T00:00:00' AND DueDate le datetime'2025-10-31T00:00:00') will be sent and as an example, the OData service might return something like the following:
[
{ "@odata.readLink": "ServicerOrders(1001)", "DueDate":"2025-08-22T00:00:00", "Priority":"Low"},
{ "@odata.readLink": "ServicerOrders(1801)", "DueDate":"2025-09-02T00:00:00", "Priority":"Medium"},
{ "@odata.readLink": "ServicerOrders(3005)", "DueDate":"2025-09-06T00:00:00", "Priority":"High"},
{ "@odata.readLink": "ServicerOrders(3011)", "DueDate":"2025-10-07T00:00:00", "Priority":"Low"},
{ "@odata.readLink": "ServicerOrders(4411)", "DueDate":"2025-10-07T00:00:00", "Priority":"High"}
]
// Note that the `DueDate` values all falls within the range.
In this case, 4 dates, 22-Aug, 02-Sep, 06-Sep, and 07-Oct, will be displayed with indicators in the Calendar.
If you have set your Event's IndicatorName with a rule, it will be triggered for each date that is found to contain entities.
When triggered, the rule will receive a CalendarProxy instance with a binding that contains Date and EntitySets property. You can access them via clientAPI.binding.Date or clientAPI.binding.EntitySets, assuming your rule's first argument is named clientAPI.
Datewill contain the ISO 8601 formatted date that tells you which date is being resolvedEntitySetsis an object that contains one or more names of the OData entity set you have defined in theTargetsbinding. Each entity set is an array that contains the entities that falls on that date based the property you set inDateProperties(in this example, theDueDate).
With these information, you can decide indicator's name to be returned to be displayed on a specific date.
Using the above ServiceOrders data set as example, your rule will be triggered 4 times, each time the binding will contain data as such:
{
"Date":"Fri Aug 29 2025 00:00:00 GMT+0800 (+08) {}", //This property will be a JavaScript Date object, not a string
"EntitySets": {
"ServiceOrders":[
{
"@odata.readLink": "/ServiceOrders(1001)",
"DueDate": "2025-08-22T00:00:00", //OData date will be in ISO8601 format
"Priority": "Low",
"AndOtherProperties": "..."
}
]
}
}
{
"Date":"Tue Sep 02 2025 00:00:00 GMT+0800 (+08) {}", //This property will be a JavaScript Date object, not a string
"EntitySets": {
"ServiceOrders":[
{
"@odata.readLink": "/ServiceOrders(1801)",
"DueDate": "2025-09-02T00:00:00", //OData date will be in ISO8601 format
"Priority": "Medium",
"AndOtherProperties": "..."
}
]
}
}
{
"Date":"Sat Sep 06 2025 00:00:00 GMT+0800 (+08) {}", //This property will be a JavaScript Date object, not a string
"EntitySets": {
"ServiceOrders":[
{
"@odata.readLink": "/ServiceOrders(3005)",
"DueDate": "2025-09-06T00:00:00", //OData date will be in ISO8601 format
"Priority": "High",
"AndOtherProperties": "..."
}
]
}
}
{
"Date":"Tue Oct 07 2025 00:00:00 GMT+0800 (+08) {}", //NOTE: this property will be a JavaScript Date object, not a string
"EntitySets": {
"ServiceOrders":[
{
"@odata.readLink": "/ServiceOrders(3011)",
"DueDate": "2025-10-07T00:00:00", // NOTE: OData date will be in ISO8601 format
"Priority": "Low",
"AndOtherProperties": "..."
},
{
"@odata.readLink": "/ServiceOrders(4411)",
"DueDate": "2025-10-07T00:00:00", // NOTE: OData date will be in ISO8601 format
"Priority": "High",
"AndOtherProperties": "..."
}
]
}
}
And you can then use these information to make decision and return a specific indicator's name, such as the following:
export default function GetIndicators(clientAPI) {
let today = new Date();
let targetDate = clientAPI.binding.Date;
let entitySets = clientAPI.binding.EntitySets;
// display OverdueIndicator because the entities found has DueDate older than today
if (targetDate < today) {
// return HighPrioOverdueIndicator to be displayed if there's even one entity with priority=High falls on this date
if (entitySets && entitySets.ServiceOrders) {
const found = entitySets.ServiceOrders.find((element) => element.Priority === "High");
}
return "OverdueIndicator";
}
else { // else return UpcomingIndicator
return "UpcomingIndicator";
}
}