Planning Calendar - with one line appointments and multiple appointments selection option
PlanningCalendar showing appointment with only title in one line to save space. The interval headers are only shown if there are some assigned in the visible area.
Z2UI5_CL_SMPC_APP_539
Controls
sap.m
UI5 1.97
The facts
- Repository
- abap2UI5/samples-controls
- Class
Z2UI5_CL_SMPC_APP_539- Source file
z2ui5_cl_smpc_app_539.clas.abap↗- Library
- sap.m
- UI5 entity
sap.m.PlanningCalendar- Demo kit sample
sap.m.sample.PlanningCalendarOneLine- SAP's own sample
- running at sdk.openui5.org ↗
- Minimum UI5
- 1.97
- In the playground
- runs in the browser, with no system and nothing installed
Keywords: planningcalendar, planning, calendar, sap.m, planningcalendaroneline, vbox, title, togglebutton, overflowtoolbarlayoutdata, badgecustomdata, select, item
Controls it builds
- sap.m.BadgeCustomData
- sap.m.OverflowToolbarLayoutData
- sap.m.PlanningCalendar
- sap.m.PlanningCalendarRow
- sap.m.Select
- sap.m.Title
- sap.m.ToggleButton
- sap.m.VBox
- sap.ui.core.Item
- sap.ui.core.mvc.View
- sap.ui.unified.CalendarAppointment
Read out of the builder chain by the abap2UI5 linter, not from the category this sample is filed under — which is what makes “which samples build one of these” a question the catalogue can answer at all.
Libraries
Run it here
The sample running, in this page — the app on its own, with no editor over it.
Switch to Playground with this code
Nothing is installed and nothing is sent anywhere: the ABAP is compiled to JavaScript in this browser and runs against abap2UI5 itself.
The ABAP
z2ui5_cl_smpc_app_539.clas.abap — 322 lines
Click a number to link to a line — shift-click for a range.
Read it on GitHub ↗
" @keywords planningcalendar planning calendar sap.m planningcalendaroneline vbox title togglebutton overflowtoolbarlayoutdata badgecustomdata select item
" @summary PlanningCalendar showing appointment with only title in one line to save space. The interval headers are only shown if there are some assigned in the visible area.
CLASS z2ui5_cl_smpc_app_539 DEFINITION PUBLIC.
PUBLIC SECTION.
INTERFACES z2ui5_if_app.
TYPES: BEGIN OF ty_s_appointment,
start_at TYPE string,
end_at TYPE string,
title TYPE string,
info TYPE string,
type TYPE string,
pic TYPE string,
tentative TYPE abap_bool,
END OF ty_s_appointment.
TYPES ty_t_appointment TYPE STANDARD TABLE OF ty_s_appointment WITH EMPTY KEY.
TYPES: BEGIN OF ty_s_header,
start_at TYPE string,
end_at TYPE string,
title TYPE string,
type TYPE string,
pic TYPE string,
END OF ty_s_header.
TYPES ty_t_header TYPE STANDARD TABLE OF ty_s_header WITH EMPTY KEY.
TYPES: BEGIN OF ty_s_person,
pic TYPE string,
name TYPE string,
role TYPE string,
t_appointments TYPE ty_t_appointment,
t_headers TYPE ty_t_header,
selected TYPE abap_bool,
END OF ty_s_person.
DATA t_people TYPE STANDARD TABLE OF ty_s_person WITH EMPTY KEY.
DATA start_date TYPE string.
DATA multi_select TYPE abap_bool.
DATA badge_value TYPE string.
DATA multi_tooltip TYPE string.
PROTECTED SECTION.
DATA client TYPE REF TO z2ui5_if_client.
METHODS view_display.
METHODS on_event.
METHODS model_init.
PRIVATE SECTION.
ENDCLASS.
CLASS z2ui5_cl_smpc_app_539 IMPLEMENTATION.
METHOD z2ui5_if_app~main.
me->client = client.
IF client->check_on_init( ).
model_init( ).
view_display( ).
ELSEIF client->check_on_navigated( ).
view_display( ).
ELSEIF client->check_on_event( ).
on_event( ).
ENDIF.
ENDMETHOD.
METHOD view_display.
DATA(view) = z2ui5_cl_ui5_view_builder=>factory( ).
" calendar date properties are typed "object" and demand a real JS Date;
" the model keeps ISO strings and Formatter.DateCreateObject converts them
view->ele( n = `View` ns = `mvc`
)->a( n = `xmlns:core` v = `sap.ui.core`
)->a( n = `xmlns:mvc` v = `sap.ui.core.mvc`
)->a( n = `xmlns:unified` v = `sap.ui.unified`
)->a( n = `xmlns` v = `sap.m`
)->a( n = `core:require` v = `{Formatter: 'z2ui5/model/formatter'}`
)->ele( `VBox`
)->a( n = `class` v = `sapUiSmallMargin`
)->ele( `PlanningCalendar`
)->a( n = `id` v = `PC1`
)->a( n = `stickyHeader` v = `true`
)->a( n = `showIntervalHeaders` v = `true`
)->a( n = `showEmptyIntervalHeaders` v = `false`
)->a( n = `appointmentHeight` v = `Automatic`
)->a( n = `startDate` v = |\{ path: '{ client->_bind_path( start_date ) }', formatter: 'Formatter.DateCreateObject' \}|
)->a( n = `rows` v = client->_bind( t_people )
)->a( n = `appointmentsVisualization` v = `Filled`
" onPress flips setMultipleAppointmentsSelection; the property is
" bindable, so the ToggleButton and the calendar share the flag
)->a( n = `multipleAppointmentsSelection` v = client->_bind( multi_select )
)->a( n = `appointmentSelect` v = client->_event(
val = `APPT_SELECT`
t_arg = VALUE #(
( `${$parameters>/appointment} ? ${$parameters>/appointment}.getTitle() : ''` )
( `${$parameters>/appointment} ? ${$parameters>/appointment}.getSelected() : false` )
( `$event.oSource.getSelectedAppointments().length` )
( `${$parameters>/appointments} ? ${$parameters>/appointments}.length : 0` ) ) )
)->a( n = `intervalSelect` v = client->_event(
val = `INTERVAL_SELECT`
t_arg = VALUE #(
( `${$parameters>/startDate}.getFullYear()` )
( `${$parameters>/startDate}.getMonth() + 1` )
( `${$parameters>/startDate}.getDate()` )
( `${$parameters>/startDate}.getHours()` )
( `${$parameters>/startDate}.getMinutes()` )
( `${$parameters>/endDate}.getFullYear()` )
( `${$parameters>/endDate}.getMonth() + 1` )
( `${$parameters>/endDate}.getDate()` )
( `${$parameters>/endDate}.getHours()` )
( `${$parameters>/endDate}.getMinutes()` )
( `${$parameters>/row} ? $event.oSource.indexOfRow(${$parameters>/row}) : -1` ) ) )
)->ele( `toolbarContent`
)->tag( `Title`
)->a( n = `text` v = `Title`
)->a( n = `titleStyle` v = `H4`
)->ele( `ToggleButton`
)->a( n = `id` v = `MultiSelect`
)->a( n = `icon` v = `sap-icon://select-appointments`
" onPress also swaps the tooltip between the two texts
)->a( n = `tooltip` v = client->_bind( multi_tooltip )
)->a( n = `pressed` v = client->_bind( multi_select )
)->ele( `layoutData`
)->tag( `OverflowToolbarLayoutData`
)->a( n = `priority` v = `NeverOverflow`
)->end(
)->ele( `customData`
" handleAppointmentSelect writes the selected count into
" the badge; the value is bound instead of set
)->tag( `BadgeCustomData`
)->a( n = `key` v = `badge`
)->a( n = `value` v = client->_bind( badge_value )
)->end(
)->end(
)->ele( `Select`
)->a( n = `change` v = client->_event( val = `SORT_CHANGE` arg = `${$parameters>/selectedItem}.getKey()` )
)->a( n = `width` v = `230px`
)->ele( `items`
)->tag( n = `Item` ns = `core`
)->a( n = `key` v = `default`
)->a( n = `text` v = `Default Appointments Sort`
)->tag( n = `Item` ns = `core`
)->a( n = `key` v = `custom`
)->a( n = `text` v = `Alphabetical Appointments Sort`
)->end(
)->end(
)->end(
)->ele( `rows`
)->ele( `PlanningCalendarRow`
)->a( n = `icon` v = `{PIC}`
)->a( n = `title` v = `{NAME}`
)->a( n = `text` v = `{ROLE}`
)->a( n = `selected` v = `{SELECTED}`
)->a( n = `appointments` v = `{path: 'T_APPOINTMENTS', templateShareable: false}`
)->a( n = `intervalHeaders` v = `{path: 'T_HEADERS', templateShareable: false}`
)->ele( `appointments`
)->tag( n = `CalendarAppointment` ns = `unified`
)->a( n = `startDate` v = `{ path: 'START_AT', formatter: 'Formatter.DateCreateObject' }`
)->a( n = `endDate` v = `{ path: 'END_AT', formatter: 'Formatter.DateCreateObject' }`
)->a( n = `icon` v = `{PIC}`
)->a( n = `title` v = `{TITLE}`
)->a( n = `text` v = `{INFO}`
)->a( n = `type` v = `{TYPE}`
)->a( n = `tentative` v = `{TENTATIVE}`
)->end(
)->ele( `intervalHeaders`
)->tag( n = `CalendarAppointment` ns = `unified`
)->a( n = `startDate` v = `{ path: 'START_AT', formatter: 'Formatter.DateCreateObject' }`
)->a( n = `endDate` v = `{ path: 'END_AT', formatter: 'Formatter.DateCreateObject' }`
)->a( n = `icon` v = `{PIC}`
)->a( n = `title` v = `{TITLE}`
)->a( n = `type` v = `{TYPE}` ).
client->view_display( view->stringify( ) ).
ENDMETHOD.
METHOD on_event.
CASE client->get_event( ).
WHEN `APPT_SELECT`.
" the selected count also feeds the ToggleButton's badge
badge_value = client->get_event_arg( 3 ).
DATA(appt_title) = client->get_event_arg( ).
IF appt_title IS NOT INITIAL.
DATA(selected) = COND string( WHEN client->get_event_arg( 2 ) = abap_true
THEN `selected`
ELSE `deselected` ).
client->message_box_display(
text = |'{ appt_title }' { selected }. \n Selected appointments: { client->get_event_arg( 3 ) }|
type = `show` ).
ELSE.
client->message_box_display( text = |{ client->get_event_arg( 4 ) } Appointments selected|
type = `show` ).
ENDIF.
WHEN `INTERVAL_SELECT`.
DATA(iso_start) = |{ client->get_event_arg( ) }-{ CONV i( client->get_event_arg( 2 ) ) WIDTH = 2 ALIGN = RIGHT PAD = '0' }| &&
|-{ CONV i( client->get_event_arg( 3 ) ) WIDTH = 2 ALIGN = RIGHT PAD = '0' }| &&
|T{ CONV i( client->get_event_arg( 4 ) ) WIDTH = 2 ALIGN = RIGHT PAD = '0' }| &&
|:{ CONV i( client->get_event_arg( 5 ) ) WIDTH = 2 ALIGN = RIGHT PAD = '0' }:00|.
DATA(iso_end) = |{ client->get_event_arg( 6 ) }-{ CONV i( client->get_event_arg( 7 ) ) WIDTH = 2 ALIGN = RIGHT PAD = '0' }| &&
|-{ CONV i( client->get_event_arg( 8 ) ) WIDTH = 2 ALIGN = RIGHT PAD = '0' }| &&
|T{ CONV i( client->get_event_arg( 9 ) ) WIDTH = 2 ALIGN = RIGHT PAD = '0' }| &&
|:{ CONV i( client->get_event_arg( 10 ) ) WIDTH = 2 ALIGN = RIGHT PAD = '0' }:00|.
DATA(appointment) = VALUE ty_s_appointment( start_at = iso_start
end_at = iso_end
title = `new appointment`
type = `Type09` ).
DATA(row_index) = CONV i( client->get_event_arg( 11 ) ).
" the selected rows are read from the model, not transported: PlanningCalendarRow
" has a bindable `selected`, and a JS callback (getSelectedRows().map(function...))
" is not in the UI5 expression grammar - it threw and lost the whole handler
DATA(rows) = VALUE string_table( ).
IF row_index >= 0.
APPEND |{ row_index }| TO rows.
ELSE.
LOOP AT t_people INTO DATA(person_sel).
IF person_sel-selected = abap_true.
APPEND |{ sy-tabix - 1 }| TO rows.
ENDIF.
ENDLOOP.
ENDIF.
" the row is addressed through a field symbol, not a table expression:
" abaplint's downport leaves an itab[ ] TARGET of INSERT/DELETE in
" place, and the 702 parser rejects it
LOOP AT rows INTO DATA(index).
READ TABLE t_people INDEX CONV i( index ) + 1 ASSIGNING FIELD-SYMBOL(<person>).
IF sy-subrc = 0.
INSERT appointment INTO TABLE <person>-t_appointments.
ENDIF.
ENDLOOP.
WHEN `SORT_CHANGE`.
" handleSortChange hands the calendar a JS comparator; ABAP sorts the
" rows themselves instead (see sidecar)
IF client->get_event_arg( ) = `custom`.
LOOP AT t_people ASSIGNING FIELD-SYMBOL(<row>).
SORT <row>-t_appointments BY title AS TEXT.
ENDLOOP.
ELSE.
model_init( ).
ENDIF.
ENDCASE.
ENDMETHOD.
METHOD model_init.
start_date = `2017-03-08T08:00:00`.
multi_select = abap_false.
badge_value = `0`.
multi_tooltip = `Enable multiple appointments selection`.
t_people = VALUE #(
( pic = `https://sdk.openui5.org/test-resources/sap/ui/documentation/sdk/images/John_Miller.png` name = `John Miller` role = `team member`
t_appointments = VALUE #(
( start_at = `2017-03-07T18:00:00` end_at = `2017-03-07T19:10:00` title = `Discussion of the plan` info = `Online meeting` type = `Type04` tentative = abap_false )
( start_at = `2017-03-07T14:00:00` end_at = `2017-03-07T15:15:00` title = `Department meeting` type = `Type04` tentative = abap_false )
( start_at = `2017-03-03T10:00:00` end_at = `2017-03-07T12:00:00` title = `Workshop out of the country` type = `Type07` pic = `sap-icon://sap-ui5` tentative = abap_false )
( start_at = `2017-03-08T09:00:00` end_at = `2017-03-08T11:00:00` title = `Team meeting` info = `room 105` type = `Type01` pic = `sap-icon://sap-ui5` tentative = abap_false )
( start_at = `2017-03-08T09:30:00` end_at = `2017-03-08T11:30:00` title = `Meeting with Max` type = `Type02` pic = `sap-icon://sap-ui5` tentative = abap_false )
( start_at = `2017-03-08T11:00:00` end_at = `2017-03-08T13:00:00` title = `Lunch` type = `Type03` tentative = abap_true )
( start_at = `2017-03-08T11:00:00` end_at = `2017-03-08T13:00:00` title = `Meeting with the crew` type = `Type04` tentative = abap_false )
( start_at = `2017-03-09T09:00:00` end_at = `2017-03-09T16:00:00` title = `Busy` type = `Type08` tentative = abap_false )
( start_at = `2017-03-10T09:00:00` end_at = `2017-03-10T11:00:00` title = `Team meeting` info = `room 105` type = `Type01` pic = `sap-icon://sap-ui5` tentative = abap_false )
( start_at = `2017-03-10T09:30:00` end_at = `2017-03-10T16:30:00` title = `Meeting with Max` type = `Type02` tentative = abap_false )
( start_at = `2017-03-11T00:00:00` end_at = `2017-03-13T23:59:00` title = `Vacation` info = `out of office` type = `Type04` tentative = abap_false )
( start_at = `2017-03-16T00:30:00` end_at = `2017-03-16T23:30:00` title = `New Colleague` info = `room 115` type = `Type10` tentative = abap_true )
( start_at = `2017-10-11T00:00:00` end_at = `2017-11-13T23:59:00` title = `Vacation` info = `out of office` type = `Type04` tentative = abap_false )
)
t_headers = VALUE #(
( start_at = `2016-09-01T00:00:00` end_at = `2016-12-30T23:59:00` title = `New quarter` type = `Type10` )
( start_at = `2017-03-09T08:00:00` end_at = `2017-03-09T09:00:00` title = `UI5` type = `Type05` pic = `sap-icon://sap-ui5` )
( start_at = `2017-06-01T00:00:00` end_at = `2017-09-30T23:59:00` title = `New quarter` type = `Type10` )
)
)
( pic = `sap-icon://employee` name = `Max Mustermann` role = `team member`
t_appointments = VALUE #(
( start_at = `2016-12-01T00:30:00` end_at = `2017-01-31T23:30:00` title = `New product release` info = `room 105` type = `Type03` tentative = abap_true )
( start_at = `2017-03-02T07:00:00` end_at = `2017-03-03T09:00:00` title = `Education` type = `Type05` tentative = abap_false )
( start_at = `2017-03-05T00:30:00` end_at = `2017-03-05T23:30:00` title = `New Product` info = `room 105` type = `Type03` tentative = abap_true )
( start_at = `2017-03-08T08:00:00` end_at = `2017-03-08T09:00:00` title = `Meet Donna` type = `Type06` tentative = abap_false )
( start_at = `2017-03-08T09:00:00` end_at = `2017-03-08T11:00:00` title = `Team meeting` info = `room 1` type = `Type01` pic = `sap-icon://sap-ui5` tentative = abap_false )
( start_at = `2017-03-09T14:00:00` end_at = `2017-03-09T15:15:00` title = `Department meeting` type = `Type04` tentative = abap_false )
( start_at = `2017-03-10T09:30:00` end_at = `2017-03-10T11:30:00` title = `Meeting with John` type = `Type02` tentative = abap_false )
( start_at = `2017-03-11T00:00:00` end_at = `2017-03-12T23:59:00` title = `Team Building` info = `out of office` type = `Type10` pic = `sap-icon://sap-ui5` tentative = abap_false )
( start_at = `2017-03-19T00:30:00` end_at = `2017-03-17T23:30:00` title = `New Product` info = `room 325` type = `Type07` tentative = abap_true )
( start_at = `2017-03-21T00:30:00` end_at = `2017-03-21T23:30:00` title = `New Product` info = `room 105` type = `Type03` tentative = abap_true )
( start_at = `2017-06-01T00:00:00` end_at = `2017-07-15T23:59:00` title = `Vacation` info = `out of office` type = `Type04` tentative = abap_false )
( start_at = `2017-12-01T00:30:00` end_at = `2018-03-03T23:30:00` title = `New product release` info = `room 105` type = `Type03` tentative = abap_true )
)
t_headers = VALUE #(
( start_at = `2017-03-08T08:00:00` end_at = `2017-03-08T10:00:00` title = `Development of UI5` type = `Type07` pic = `sap-icon://sap-ui5` )
( start_at = `2017-05-01T00:00:00` end_at = `2017-08-30T23:59:00` title = `New quarter` type = `Type10` )
)
) ).
ENDMETHOD.
ENDCLASS.
More in sap.m
- Wizard page mode — Demonstrates the usage of the renderMode property. The Wizard is displayed inside a Dialo…
- Wizard edit mode — Demonstrates the usage of the setCurrentStep association, which controlls the current ste…
- Wizard branching use case — The Wizard could be used in branching mode, where the choice of next step depends on the…
- simple Planning Calendar — PlanningCalendar with single row selection that illustrates the built-in views.
- Planning Calendar - with custom views — PlanningCalendar with custom views to set number of hours, days and months and change vie…
- Planning Calendar - multiple selection — PlanningCalendar with multiple row selection. No interval headers are displayed. On click…
- Planning Calendar - with min. and max. date — PlanningCalendar with min. date 2000-01-01 and max. date 2050-12-31
- Planning Calendar - with legend and option to change the first day of week — PlanningCalendar inside the main part of a sap.ui.layout.DynamicSideContent and a sap.m.P…
- Planning Calendar - with header that remains visible (fixed on top) on scroll — PlanningCalendar with header area that remains visible (fixed on top) when the rest of th…
- Planning Calendar - with appointments in different sizes — PlanningCalendar showing normal, half-sized and large appointments.
- Planning Calendar - week numbering — Demonstrates PlanningCalendar with different week numbering (only Date Picker, 1 Week and…
- Planning Calendar - with relative views — PlanningCalendar with relative views. The relative periods are not directly related to da…
On this page