Message Popover - Message Handling
The message handling concept sample shows how you can connect an error inside the page (such as input validation error) with an error, visualized as an item in a message popover.
Z2UI5_CL_SMPC_APP_065
Controls
sap.m
UI5 1.84
The facts
- Repository
- abap2UI5/samples-controls
- Class
Z2UI5_CL_SMPC_APP_065- Source file
z2ui5_cl_smpc_app_065.clas.abap↗- Library
- sap.m
- UI5 entity
sap.m.MessagePopover- Demo kit sample
sap.m.sample.MessagePopoverMessageHandling- SAP's own sample
- running at sdk.openui5.org ↗
- Minimum UI5
- 1.84
- In the playground
- runs in the browser, with no system and nothing installed
Keywords: messagepopover, message, popover, sap.m, handling, vbox, simpleform, title, label, input, select, item
Controls it builds
- sap.m.Button
- sap.m.Input
- sap.m.Label
- sap.m.MessageItem
- sap.m.MessagePopover
- sap.m.OverflowToolbar
- sap.m.Page
- sap.m.Select
- sap.m.ToolbarSpacer
- sap.m.VBox
- sap.ui.core.Item
- sap.ui.core.Title
- sap.ui.core.mvc.View
- sap.ui.layout.form.SimpleForm
- z2ui5.cc.MessageManager
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_065.clas.abap — 375 lines
Click a number to link to a line — shift-click for a range.
Read it on GitHub ↗
" @keywords messagepopover message popover sap.m handling vbox simpleform title label input select item
" @summary The message handling concept sample shows how you can connect an error inside the page (such as input validation error) with an error, visualized as an item in a message popover.
CLASS z2ui5_cl_smpc_app_065 DEFINITION PUBLIC.
PUBLIC SECTION.
INTERFACES z2ui5_if_app.
TYPES:
BEGIN OF ty_s_form,
name TYPE string,
street_name TYPE string,
street_number TYPE string,
zip_code TYPE string,
zip_city TYPE string,
country TYPE string,
email TYPE string,
phone_number TYPE string,
phone_time TYPE string,
website TYPE string,
END OF ty_s_form.
TYPES:
BEGIN OF ty_s_employment,
jobtitle TYPE string,
paygrade TYPE string,
weeklyhours TYPE string,
unit TYPE string,
class TYPE string,
fte TYPE string,
END OF ty_s_employment.
TYPES:
BEGIN OF ty_s_message,
message TYPE string,
description TYPE string,
type TYPE string,
target TYPE string,
additionaltext TYPE string,
code TYPE string,
END OF ty_s_message.
DATA t_forms TYPE STANDARD TABLE OF ty_s_form WITH EMPTY KEY.
DATA t_employment TYPE STANDARD TABLE OF ty_s_employment WITH EMPTY KEY.
DATA t_messages TYPE STANDARD TABLE OF ty_s_message WITH EMPTY KEY.
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_065 IMPLEMENTATION.
METHOD z2ui5_if_app~main.
me->client = client.
IF client->check_on_init( ).
model_init( ).
view_display( ).
" original onInit: MessageToast.show('Press "Save" to trigger validation.')
client->message_toast_display( `Press "Save" to trigger validation.` ).
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( ).
view->ele( n = `View` ns = `mvc`
)->a( n = `height` v = `100%`
)->a( n = `xmlns` v = `sap.m`
)->a( n = `xmlns:mvc` v = `sap.ui.core.mvc`
)->a( n = `xmlns:core` v = `sap.ui.core`
)->a( n = `xmlns:f` v = `sap.ui.layout.form`
)->a( n = `xmlns:z2ui5` v = `z2ui5.cc`
)->ele( `Page`
)->a( n = `id` v = `messageHandlingPage`
)->a( n = `showHeader` v = `false`
)->ele( `content`
)->ele( `VBox`
)->a( n = `id` v = `formContainer`
)->a( n = `class` v = `sapUiSmallMargin`
)->a( n = `items` v = client->_bind( t_forms )
)->ele( n = `SimpleForm` ns = `f`
)->a( n = `editable` v = `true`
)->a( n = `layout` v = `ColumnLayout`
)->a( n = `title` v = `Personal`
)->a( n = `columnsM` v = `2`
)->a( n = `columnsL` v = `2`
)->a( n = `columnsXL` v = `2`
)->ele( n = `content` ns = `f`
)->tag( n = `Title` ns = `core`
)->a( n = `text` v = `Information`
)->tag( `Label`
)->a( n = `text` v = `Name`
)->tag( `Input`
)->a( n = `required` v = `true`
)->a( n = `value` v = `{ path: 'NAME', type: 'sap.ui.model.type.String' }`
)->a( n = `change` v = client->_event( `CHANGE` )
)->tag( `Label`
)->a( n = `text` v = `Street/No.`
)->tag( `Input`
)->a( n = `value` v = `{STREET_NAME}`
)->tag( `Input`
)->a( n = `value` v = `{STREET_NUMBER}`
)->tag( `Label`
)->a( n = `text` v = `ZIP Code/City`
)->tag( `Input`
)->a( n = `value` v = `{ path: 'ZIP_CODE', type: 'sap.ui.model.type.Integer' }`
)->tag( `Input`
)->a( n = `value` v = `{ZIP_CITY}`
)->tag( `Label`
)->a( n = `text` v = `Country`
)->ele( `Select`
)->a( n = `selectedKey` v = `{COUNTRY}`
)->tag( n = `Item` ns = `core`
)->a( n = `key` v = `England`
)->a( n = `text` v = `England`
)->tag( n = `Item` ns = `core`
)->a( n = `key` v = `Germany`
)->a( n = `text` v = `Germany`
)->tag( n = `Item` ns = `core`
)->a( n = `key` v = `USA`
)->a( n = `text` v = `USA`
)->end(
)->tag( n = `Title` ns = `core`
)->a( n = `text` v = `Contact`
)->tag( `Label`
)->a( n = `text` v = `Email`
)->tag( `Input`
)->a( n = `value` v = `{ path: 'EMAIL', type: 'sap.ui.model.type.String', constraints: { search: '^\\w+[\\w-+\\.]*\\@[a-zA-Z]+.[a-zA-Z]+' } }`
)->tag( `Label`
)->a( n = `text` v = `Phone Number`
)->tag( `Input`
)->a( n = `value` v = `{PHONE_NUMBER}`
)->tag( `Input`
)->a( n = `value` v = `{PHONE_TIME}`
)->tag( `Label`
)->a( n = `text` v = `Personal website`
)->tag( `Input`
)->a( n = `value` v = `{WEBSITE}`
)->end(
)->end(
)->end(
)->ele( `VBox`
)->a( n = `id` v = `formContainerEmployment`
)->a( n = `class` v = `sapUiSmallMargin`
)->a( n = `items` v = client->_bind( t_employment )
)->ele( n = `SimpleForm` ns = `f`
)->a( n = `editable` v = `true`
)->a( n = `layout` v = `ColumnLayout`
)->a( n = `title` v = `Personal`
)->a( n = `columnsM` v = `2`
)->a( n = `columnsL` v = `2`
)->a( n = `columnsXL` v = `2`
)->ele( n = `content` ns = `f`
)->tag( n = `Title` ns = `core`
)->a( n = `text` v = `Information`
)->tag( `Label`
)->a( n = `text` v = `Job Classification`
)->tag( `Input`
)->a( n = `value` v = `{JOBTITLE}`
)->tag( `Label`
)->a( n = `text` v = `Pay Grade`
)->tag( `Input`
)->a( n = `value` v = `{PAYGRADE}`
)->tag( `Label`
)->a( n = `text` v = `Standard Weekly Hours`
)->tag( `Input`
)->a( n = `value` v = `{ path: 'WEEKLYHOURS', type: 'sap.ui.model.type.Integer', constraints: { maximum: 40 } }`
)->a( n = `change` v = client->_event( `CHANGE` )
)->tag( n = `Title` ns = `core`
)->a( n = `text` v = `Rating`
)->tag( `Label`
)->a( n = `text` v = `Unit`
)->tag( `Input`
)->a( n = `value` v = `{UNIT}`
)->tag( `Label`
)->a( n = `text` v = `Employee Class`
)->tag( `Input`
)->a( n = `value` v = `{CLASS}`
)->tag( `Label`
)->a( n = `text` v = `FTE`
)->tag( `Input`
)->a( n = `value` v = `{FTE}`
)->end(
)->end(
)->end(
)->tag( n = `MessageManager` ns = `z2ui5`
)->a( n = `items` v = client->_bind( t_messages )
)->end(
)->ele( `footer`
)->ele( `OverflowToolbar`
)->ele( `Button`
)->a( n = `id` v = `messagePopoverBtn`
)->a( n = `visible` v = |\{= !!$\{message>/\}.length \}|
)->a( n = `text` v = |\{= $\{message>/\}.length \}|
)->a( n = `type` v = `Emphasized`
)->a( n = `ariaHasPopup` v = `Dialog`
" original: this.oMP.toggle(oEvent.getSource()) - a pure client-side toggle, so
" wired roundtrip-free (no on_event) anchored to the button by its own id
)->a( n = `press` v = client->follow_up_action( val = client->cs_event-control_by_id
t_arg = VALUE #( ( `messagePopover` ) ( `toggleBy` ) ( `messagePopoverBtn` ) ) )
)->ele( `dependents`
)->ele( `MessagePopover`
)->a( n = `id` v = `messagePopover`
)->a( n = `items` v = `{message>/}`
)->a( n = `groupItems` v = `true`
" activeTitlePress is a MessagePopover event (not MessageItem); it ships the
" pressed message's target control id so the handler can scroll+focus it
)->a( n = `activeTitlePress` v = client->_event( val = `ACTIVE_TITLE` arg = `${$parameters>/item}.getBindingContext('message').getObject().getControlIds()[0]` )
)->tag( `MessageItem`
)->a( n = `title` v = `{message>message}`
)->a( n = `subtitle` v = `{message>additionalText}`
)->a( n = `type` v = `{message>type}`
)->a( n = `description` v = `{message>message}`
)->a( n = `activeTitle` v = `true`
" group name (Personal, <section>): a domain classification computed in
" the backend (see model above) and carried on the Message code field,
" NOT a frontend expression - the original derives it in its controller's
" getGroupName; only Email sits in the Contact group, the rest in Information
)->a( n = `groupName` v = `{message>code}`
)->end(
)->end(
)->end(
)->tag( `ToolbarSpacer`
)->tag( `Button`
)->a( n = `type` v = `Emphasized`
)->a( n = `text` v = `Save`
)->a( n = `press` v = client->_event( `SAVE` )
)->tag( `Button`
)->a( n = `text` v = `Cancel`
)->end(
)->end(
)->end( ).
client->view_display( view->stringify( ) ).
ENDMETHOD.
METHOD on_event.
CASE client->get_event( ).
WHEN `ACTIVE_TITLE`.
" original: activeTitlePress scrolls to the message's target control, closes the popover
" and focuses the control; the full control id travels from the pressed MessageItem's
" message object (getControlIds()[0]) and the frontend SCROLL_INTO_VIEW + SET_FOCUS act on it
DATA(lv_control_id) = client->get_event_arg( ).
IF lv_control_id IS NOT INITIAL.
client->follow_up_action( val = client->cs_event-scroll_into_view
t_arg = VALUE #( ( lv_control_id ) ) ).
client->follow_up_action( val = client->cs_event-control_by_id
t_arg = VALUE #( ( `messagePopover` ) ( `close` ) ) ).
client->follow_up_action( val = client->cs_event-set_focus
t_arg = VALUE #( ( lv_control_id ) ) ).
ENDIF.
WHEN `SAVE`.
" original generateInvalidUserInput(): force a set of fields invalid to demo the message
" handling, then open the MessagePopover. abap2UI5 only auto-collects validation messages
" from USER input, not from programmatically-set model values, so Save mirrors the four
" issues explicitly on the SAME rows the original targets - formContainer.getItems()[4/5/6]
" = John Miller / Stefan Bosch / Maria Fontes, plus the employment row: it injects the
" invalid values and authors the matching four messages (3 Errors + 1 Warning), which the
" z2ui5.cc.MessageManager reconciles into the message manager.
IF lines( t_forms ) >= 7.
" John Miller -> /T_FORMS/4/NAME
t_forms[ 5 ]-name = ``.
" Stefan Bosch -> /T_FORMS/5/ZIP_CODE
t_forms[ 6 ]-zip_code = `AAA`.
" Maria Fontes -> /T_FORMS/6/EMAIL
t_forms[ 7 ]-email = `MariaFontes.com`.
ENDIF.
IF t_employment IS NOT INITIAL.
t_employment[ 1 ]-weeklyhours = `400`.
ENDIF.
t_messages = VALUE #(
( message = `A mandatory field is required` type = `Error` additionaltext = `Name`
target = `/T_FORMS/4/NAME` )
( message = `Enter a number with no decimal places` type = `Error` additionaltext = `ZIP Code/City`
target = `/T_FORMS/5/ZIP_CODE` )
( message = `Enter a valid value` type = `Error` additionaltext = `Email`
target = `/T_FORMS/6/EMAIL` )
( message = `The value should not exceed 40` type = `Warning` additionaltext = `Standard Weekly Hours`
description = `The value of the working hours field should not exceed 40 hours.`
target = `/T_EMPLOYMENT/0/WEEKLYHOURS` ) ).
" the message group (Personal, <section>) is a domain classification, so
" it is computed in the backend (thin frontend) and rides on the Message
" code field - the original derives it in its controller's getGroupName.
LOOP AT t_messages REFERENCE INTO DATA(lr_msg).
lr_msg->code = COND #( WHEN lr_msg->additionaltext = `Email`
THEN `Personal, Contact`
ELSE `Personal, Information` ).
ENDLOOP.
" original: oMP.openBy(oButton) after the values are set - open the popover anchored to the button
client->follow_up_action( val = client->cs_event-control_by_id
t_arg = VALUE #( ( `messagePopover` ) ( `openBy` ) ( `messagePopoverBtn` ) ) ).
WHEN `CHANGE`.
" the sample's onChange manually adds/removes required-field and constraint messages; here
" the typed binding + constraints collect those AUTOMATICALLY into the message> model
" (no app code), so the handler only pushes the model back
ENDCASE.
ENDMETHOD.
METHOD model_init.
t_forms = VALUE #(
( name = `Julie Armstrong` street_name = `Mainstreet` street_number = `1278`
zip_code = `12345` zip_city = `Maintown` country = `Germany`
email = `Julie.Armstrong@company.com` phone_number = `+1 (610) 661-1000` phone_time = `12:00` website = `n/a` )
( name = `Denise Smith` street_name = `Mainstreet` street_number = `1567`
zip_code = `12345` zip_city = `Maintown` country = `Germany`
email = `Denise.Smith@company.com` phone_number = `+1 (610) 661-1000` phone_time = `12:00` website = `n/a` )
( name = `Richard Wilson` street_name = `Mainstreet` street_number = `2984`
zip_code = `12345` zip_city = `Maintown` country = `Germany`
email = `Richard.Wilson@company.com` phone_number = `+1 (610) 661-1000` phone_time = `12:00` website = `n/a` )
( name = `Gerd Becker` street_name = `Mainstreet` street_number = `3614`
zip_code = `12345` zip_city = `Maintown` country = `Germany`
email = `Gerd.Becker@company.com` phone_number = `+1 (610) 661-1000` phone_time = `12:00` website = `n/a` )
( name = `John Miller` street_name = `Mainstreet` street_number = `1618`
zip_code = `AAA` zip_city = `Maintown` country = `Germany`
email = `John.Miller@company.com` phone_number = `+1 (610) 661-1000` phone_time = `12:00` website = `n/a` )
( name = `Stefan Bosch` street_name = `Mainstreet` street_number = `4864`
zip_code = `12345` zip_city = `Maintown` country = `Germany`
email = `Stefan.Bosch@company.com` phone_number = `+1 (610) 661-1000` phone_time = `12:00` website = `n/a` )
( name = `Maria Fontes` street_name = `Mainstreet` street_number = `4864`
zip_code = `12345` zip_city = `Maintown` country = `Germany`
email = `` phone_number = `+1 (610) 661-1000` phone_time = `12:00` website = `MariaFontescompany.com` )
( name = `Antonio Ferrari` street_name = `Mainstreet` street_number = `2598`
zip_code = `12345` zip_city = `Maintown` country = `Germany`
email = `Antonio.Ferrari@company.com` phone_number = `+1 (610) 661-1000` phone_time = `12:00` website = `n/a` ) ).
t_employment = VALUE #(
( jobtitle = `Senior UI Developer (UIDEV-SR)` paygrade = `Salary Grade 18 (GR-14` weeklyhours = `0`
unit = `ABC` class = `Employee` fte = `1` ) ).
ENDMETHOD.
ENDCLASS.
More in sap.m
- LightBox — Displays several image thumbnails. Clicking on each of them will open a LightBox.
- Menu — This control is used to show a menu in both desktop and mobile.
- Menu Button — This control is used to open a menu in both desktop and mobile.
- Message Strip with enableFormattedText — A sample MessageStrip that shows status messages with additional formatting.
- News Content — This control is used to display the news content text and subheader in a tile.
- Numeric Content with Icon — Shows NumericContent including an icon.
- MessagePopover — MessagePopover is a control that displays a summarized list of different types of message…
- Message Popover - Async Message Handling — The message handling concept sample shows how you can use callback functions for resolvin…
- Slider — With the Slider a user can choose a value from a numerical range.
- Radio Button — Typically the Radio Button is used by other controls. E.g. the List uses it for the singl…
- Progress Indicator — Shows the progress of a process in a graphical way. To indicate the progress, the inside…
- Object Identifier — The object identifier is a small building block representing an object by a title and sho…
On this page