Samples / Controls / sap.f

Grid Container

This sample represents the general usage of GridContainer.

Class
z2ui5_cl_smpc_app_168
Repository
abap2UI5/samples-controls
Ports
sap.f.sample.GridContainer
UI5 libraries
sap.f, sap.m, sap.ui.core, sap.ui.integration
Lowest UI5 release
1.71
In the browser
Runs in the playground
Controls it builds
sap.f.Card, sap.f.GridContainer, sap.f.GridContainerItemLayoutData, sap.f.GridContainerSettings, sap.f.cards.Header, sap.m.Button, sap.m.ComboBox, sap.m.CustomListItem, sap.m.DatePicker, sap.m.GenericTile, sap.m.HBox, sap.m.ImageContent, sap.m.Label, sap.m.List, sap.m.NumericContent, sap.m.ObjectStatus, sap.m.Panel, sap.m.ScrollContainer, sap.m.Switch, sap.m.Text, sap.m.TileContent, sap.m.Title, sap.m.ToggleButton, sap.m.VBox, sap.ui.core.Item, sap.ui.core.mvc.View, sap.ui.integration.widgets.Card

The class

" @keywords gridcontainer grid container sap.f scrollcontainer togglebutton panel hbox label switch text gridcontainersettings
" @summary This sample represents the general usage of GridContainer.
" @origin sap.f.sample.GridContainer - https://sdk.openui5.org/entity/sap.f.GridContainer/sample/sap.f.sample.GridContainer (status: reviewed - read against the original, not run)
CLASS z2ui5_cl_smpc_app_168 DEFINITION PUBLIC.

  PUBLIC SECTION.
    INTERFACES z2ui5_if_app.

    TYPES:
      BEGIN OF ty_city,
        text TYPE string,
        key  TYPE string,
      END OF ty_city.
    TYPES:
      BEGIN OF ty_prod,
        title        TYPE string,
        subtitle     TYPE string,
        revenue      TYPE string,
        statusschema TYPE string,
      END OF ty_prod.
    DATA cities TYPE STANDARD TABLE OF ty_city WITH EMPTY KEY.
    DATA productitems TYPE STANDARD TABLE OF ty_prod WITH EMPTY KEY.
    DATA snap_to_row         TYPE abap_bool.
    DATA allow_dense_fill    TYPE abap_bool.
    DATA inline_block_layout TYPE abap_bool.
    DATA columns_text        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_168 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( ).

    " The original binds two named models (cities>, products>) inside the cards;
    " abap2UI5 keeps one default model, so those bind directly ({cities>/cities}
    " -> {/CITIES}, {products>/productItems} -> {/PRODUCTITEMS}). The switches /
    " toggle / column-change / tile / card presses are controller handlers in
    " the original. Corrected 2026-08-21: they are NOT client toasts - the three
    " Switches carry a two-way bound state and nothing else, the Reveal Grid
    " ToggleButton is undecorated, and columnsChange round-trips into on_event.
    " The sidecar was corrected on 2026-08-05 and this half was missed.
    view->ele( n = `View` ns = `mvc`
        )->a( n = `xmlns`        v = `sap.m`
        )->a( n = `xmlns:mvc`    v = `sap.ui.core.mvc`
        )->a( n = `xmlns:f`      v = `sap.f`
        )->a( n = `xmlns:card`   v = `sap.f.cards`
        )->a( n = `xmlns:core`   v = `sap.ui.core`
        )->a( n = `xmlns:w`      v = `sap.ui.integration.widgets`
        )->a( n = `displayBlock` v = `true`
        )->a( n = `height`       v = `100%`

        )->ele( `ScrollContainer`
            )->a( n = `height`   v = `100%`
            )->a( n = `width`    v = `100%`
            )->a( n = `vertical` v = `true`

            )->ele( `ToggleButton`
                )->a( n = `id`    v = `revealGrid`
                " press wire dropped (declared): RevealGrid is a sample-local JS
                " helper module (grid outline overlay) with no declarative equivalent
                )->a( n = `text`  v = `Reveal Grid`
                )->a( n = `class` v = `sapUiSmallMargin`

            )->end(

            )->ele( `Panel`
                )->a( n = `headerText` v = `Grid Container Properties`
                )->ele( `HBox`
                    )->a( n = `alignItems` v = `Center`
                    )->tag( `Label`
                        )->a( n = `width` v = `8rem`
                        )->a( n = `class` v = `sapUiSmallMarginBegin`
                        )->a( n = `text`  v = `Snap to Row:`
" change wire dropped (declared): state is two-way bound and the
" grid binds snapToRow to the same field - the 007/128 pattern
                    )->tag( `Switch`
                        )->a( n = `state` v = client->_bind( snap_to_row )
                    )->tag( `Text`
                        )->a( n = `class` v = `sapUiTinyMarginBeginEnd`
                        )->a( n = `text`  v = `(Should the items stretch to fill the rows which they occupy, or not. If turned on the items will stretch.)`

                )->end(
                )->ele( `HBox`
                    )->a( n = `alignItems` v = `Center`
                    )->tag( `Label`
                        )->a( n = `width` v = `8rem`
                        )->a( n = `class` v = `sapUiSmallMarginBegin`
                        )->a( n = `text`  v = `Allow dense fill:`
                    )->tag( `Switch`
                        )->a( n = `state` v = client->_bind( allow_dense_fill )
                    )->tag( `Text`
                        )->a( n = `class` v = `sapUiTinyMarginBeginEnd`
                        )->a( n = `text`  v = `(Smaller items will take up all of the available space, ignoring their order.)`

                )->end(
                )->ele( `HBox`
                    )->a( n = `alignItems` v = `Center`
                    )->tag( `Label`
                        )->a( n = `width` v = `8rem`
                        )->a( n = `class` v = `sapUiSmallMarginBegin`
                        )->a( n = `text`  v = `Inline block layout:`
                    )->tag( `Switch`
                        )->a( n = `state` v = client->_bind( inline_block_layout )
                    )->tag( `Text`
                        )->a( n = `class` v = `sapUiTinyMarginBeginEnd`
                        )->a( n = `text`  v = `(Makes the grid items act like an inline-block elements.)`

                )->end(
            )->end(

            )->ele( `Panel`
                )->tag( `Text`
                    )->a( n = `class` v = `sapUiSmallMarginBegin`
                    )->a( n = `id`    v = `columnsCountText`
                    )->a( n = `text`  v = client->_bind( columns_text )

            )->end(

            )->ele( n = `GridContainer` ns = `f`
                )->a( n = `id`                v = `demoGrid`
                " the view's own static class, as in the original
                )->a( n = `class`             v = `sapUiSmallMargin`
                " the onInit attachLayoutChange handler: tiny margin on the two
                " narrow layouts, small margin otherwise. class= is NOT bindable -
                " XMLTemplateProcessor intercepts it before the property branch and
                " hands the raw string to addStyleClass, which drops any value
                " carrying a quote, so an expression there sets NO class at all
                " (which is what this port did between 2026-08-05 and 2026-08-23,
                " losing the static class too). The switch is the control's own
                " layoutChange event driving addStyleClass/removeStyleClass, both
                " whitelisted, with the branch inside the argument expression -
                " roundtrip-free, and _applyLayout fires on the FIRST layout
                " determination too, so a phone starts out tiny like the original
                )->a( n = `layoutChange`      v = client->follow_up_action(
                          val   = client->cs_event-control_by_id
                          t_arg = VALUE #( ( `demoGrid` )
                                           ( `removeStyleClass` )
                                           ( `${$parameters>/layout} === 'layoutXS' || ${$parameters>/layout} === 'layoutS' ? 'sapUiSmallMargin' : 'sapUiTinyMargin'` ) ) ) && `; ` &&
                                            client->follow_up_action(
                          val   = client->cs_event-control_by_id
                          t_arg = VALUE #( ( `demoGrid` )
                                           ( `addStyleClass` )
                                           ( `${$parameters>/layout} === 'layoutXS' || ${$parameters>/layout} === 'layoutS' ? 'sapUiTinyMargin' : 'sapUiSmallMargin'` ) ) )
                " added attrs (declared): the switch-driven properties the original
                " set imperatively (setSnapToRow / setAllowDenseFill / setInlineBlockLayout)
                )->a( n = `snapToRow`         v = client->_bind( snap_to_row )
                )->a( n = `allowDenseFill`    v = client->_bind( allow_dense_fill )
                )->a( n = `inlineBlockLayout` v = client->_bind( inline_block_layout )
                " onGridColumnsChange: the bound columnsCountText is recomputed
                )->a( n = `columnsChange`     v = client->_event( val = `COLUMNS_CHANGE` arg = `${$parameters>/columns}` )
                )->ele( n = `layout` ns = `f`
                    )->tag( n = `GridContainerSettings` ns = `f`
                        )->a( n = `rowSize`    v = `84px`
                        )->a( n = `columnSize` v = `84px`
                        )->a( n = `gap`        v = `8px`

                )->end(
                )->ele( n = `layoutXS` ns = `f`
                    )->tag( n = `GridContainerSettings` ns = `f`
                        )->a( n = `rowSize`    v = `70px`
                        )->a( n = `columnSize` v = `70px`
                        )->a( n = `gap`        v = `8px`

                )->end(

                )->ele( `GenericTile`
                    )->a( n = `header`    v = `Sales Fulfillment Application Title`
                    )->a( n = `subheader` v = `Subtitle`
                    )->a( n = `press`     v = client->follow_up_action( val   = client->cs_event-control_global
                                                                        t_arg = VALUE #( ( `MESSAGE_TOAST` ) ( `show` ) ( `Press was fired on - {0}` ) ( `$event.oSource.getMetadata().getName()` ) ) )
                    )->ele( `layoutData`
                        )->tag( n = `GridContainerItemLayoutData` ns = `f`
                            )->a( n = `minRows` v = `2`
                            )->a( n = `columns` v = `2`

                    )->end(
                    )->ele( `TileContent`
                        )->a( n = `unit`   v = `EUR`
                        )->a( n = `footer` v = `Current Quarter`
                        )->tag( `ImageContent`
                            )->a( n = `src` v = `sap-icon://home-share`

                    )->end(
                )->end(

                )->ele( n = `Card` ns = `w`
                    )->a( n = `manifest` v = `https://sdk.openui5.org/test-resources/sap/f/demokit/sample/GridContainer/cardManifest.json`
                    )->ele( n = `layoutData` ns = `w`
                        )->tag( n = `GridContainerItemLayoutData` ns = `f`
                            )->a( n = `minRows` v = `3`
                            )->a( n = `columns` v = `4`

                    )->end(
                )->end(

                )->ele( `GenericTile`
                    )->a( n = `header`    v = `Manage Activity Master Data Type`
                    )->a( n = `subheader` v = `Subtitle`
                    )->ele( `layoutData`
                        )->tag( n = `GridContainerItemLayoutData` ns = `f`
                            )->a( n = `minRows` v = `2`
                            )->a( n = `columns` v = `2`

                    )->end(
                    )->ele( `TileContent`
                        )->tag( `ImageContent`
                            )->a( n = `src` v = `sap-icon://activities`

                    )->end(
                )->end(

                )->ele( n = `Card` ns = `f`
                    )->ele( n = `layoutData` ns = `f`
                        )->tag( n = `GridContainerItemLayoutData` ns = `f`
                            )->a( n = `columns` v = `4`

                    )->end(
                    )->ele( n = `header` ns = `f`
                        )->tag( n = `Header` ns = `card`
                            )->a( n = `title`    v = `Buy bus ticket on-line`
                            )->a( n = `subtitle` v = `Buy a single drive ticket for a date`
                            )->a( n = `iconSrc`  v = `sap-icon://bus-public-transport`
                            )->a( n = `press`    v = client->follow_up_action( val   = client->cs_event-control_global
                                                                               t_arg = VALUE #( ( `MESSAGE_TOAST` ) ( `show` ) ( `Press was fired on - {0}` ) ( `$event.oSource.getMetadata().getName()` ) ) )

                    )->end(
                    )->ele( n = `content` ns = `f`
                        )->ele( `VBox`
                            )->a( n = `height`         v = `115px`
                            )->a( n = `class`          v = `sapUiSmallMargin`
                            )->a( n = `justifyContent` v = `SpaceBetween`
                            )->ele( `HBox`
                                )->a( n = `justifyContent` v = `SpaceBetween`
                                )->ele( `ComboBox`
                                    )->a( n = `width`       v = `120px`
                                    )->a( n = `placeholder` v = `From City`
                                    " sorter kept 1:1 from the original binding-info (CAPABILITIES 'Binding sorter')
                                    )->a( n = `items`       v = |\{ path: '{ client->_bind_path( cities ) }', sorter: \{ path: 'TEXT' \} \}|
                                    )->tag( n = `Item` ns = `core`
                                        )->a( n = `key`  v = `{KEY}`
                                        )->a( n = `text` v = `{TEXT}`

                                )->end(
                                )->ele( `ComboBox`
                                    )->a( n = `width`       v = `120px`
                                    )->a( n = `placeholder` v = `To City`
                                    )->a( n = `items`       v = |\{ path: '{ client->_bind_path( cities ) }', sorter: \{ path: 'TEXT' \} \}|
                                    )->tag( n = `Item` ns = `core`
                                        )->a( n = `key`  v = `{KEY}`
                                        )->a( n = `text` v = `{TEXT}`

                                )->end(
                            )->end(
                            )->ele( `HBox`
                                )->a( n = `justifyContent` v = `SpaceBetween`
                                )->tag( `DatePicker`
                                    )->a( n = `width`       v = `186px`
                                    )->a( n = `placeholder` v = `Choose Date ...`
                                )->tag( `Button`
                                    )->a( n = `text` v = `Book`
                                    )->a( n = `type` v = `Emphasized`

                            )->end(
                        )->end(
                    )->end(
                )->end(

                )->ele( `Text`
                    )->a( n = `text` v = `Lorem ipsum dolor sit amet (content abbreviated from the original filler text)`
                    )->ele( `layoutData`
                        )->tag( n = `GridContainerItemLayoutData` ns = `f`
                            )->a( n = `columns` v = `4`

                    )->end(
                )->end(

                )->ele( `GenericTile`
                    )->a( n = `header`    v = `Cumulative Totals`
                    )->a( n = `subheader` v = `Subtitle`
                    )->ele( `layoutData`
                        )->tag( n = `GridContainerItemLayoutData` ns = `f`
                            )->a( n = `minRows` v = `2`
                            )->a( n = `columns` v = `2`

                    )->end(
                    )->ele( `TileContent`
                        )->a( n = `unit`   v = `Unit`
                        )->a( n = `footer` v = `Footer Text`
                        )->tag( `NumericContent`
                            )->a( n = `value` v = `12`

                    )->end(
                )->end(

                )->ele( `GenericTile`
                    )->a( n = `header`    v = `Travel and Expenses`
                    )->a( n = `subheader` v = `Access Concur`
                    )->ele( `layoutData`
                        )->tag( n = `GridContainerItemLayoutData` ns = `f`
                            )->a( n = `minRows` v = `2`
                            )->a( n = `columns` v = `2`

                    )->end(
                    )->ele( `TileContent`
                        )->tag( `ImageContent`
                            )->a( n = `src` v = `sap-icon://travel-expense`

                    )->end(
                )->end(

                )->ele( n = `Card` ns = `f`
                    )->ele( n = `layoutData` ns = `f`
                        )->tag( n = `GridContainerItemLayoutData` ns = `f`
                            )->a( n = `minRows` v = `4`
                            )->a( n = `columns` v = `4`

                    )->end(
                    )->ele( n = `header` ns = `f`
                        )->tag( n = `Header` ns = `card`
                            )->a( n = `title`    v = `Project Cloud Transformation`
                            )->a( n = `subtitle` v = `Revenue per Product | EUR`

                    )->end(
                    )->ele( n = `content` ns = `f`
                        )->ele( `List`
                            )->a( n = `showSeparators` v = `None`
                            )->a( n = `items`          v = client->_bind( productitems )
                            )->ele( `CustomListItem`
                                )->ele( `HBox`
                                    )->a( n = `alignItems`     v = `Center`
                                    )->a( n = `justifyContent` v = `SpaceBetween`
                                    )->ele( `VBox`
                                        )->a( n = `class` v = `sapUiSmallMarginBegin sapUiSmallMarginTopBottom`
                                        )->tag( `Title`
                                            )->a( n = `level` v = `H3`
                                            )->a( n = `text`  v = `{TITLE}`
                                        )->tag( `Text`
                                            )->a( n = `text` v = `{SUBTITLE}`

                                    )->end(
                                    )->tag( `ObjectStatus`
                                        )->a( n = `class` v = `sapUiTinyMargin`
                                        )->a( n = `text`  v = `{REVENUE}`
                                        )->a( n = `state` v = `{STATUSSCHEMA}`

                                )->end(
                            )->end(
                        )->end(
                    )->end(
                )->end(

                )->ele( `GenericTile`
                    )->a( n = `header`    v = `Success Map`
                    )->a( n = `subheader` v = `Access Success Map`
                    )->ele( `layoutData`
                        )->tag( n = `GridContainerItemLayoutData` ns = `f`
                            )->a( n = `minRows` v = `2`
                            )->a( n = `columns` v = `2`

                    )->end(
                    )->ele( `TileContent`
                        )->a( n = `unit`   v = `EUR`
                        )->a( n = `footer` v = `Current Quarter`
                        )->tag( `ImageContent`
                            )->a( n = `src` v = `sap-icon://map-3`

                    )->end(
                )->end(

                )->ele( `GenericTile`
                    )->a( n = `header` v = `My Team Calendar`
                    )->ele( `layoutData`
                        )->tag( n = `GridContainerItemLayoutData` ns = `f`
                            )->a( n = `minRows` v = `2`
                            )->a( n = `columns` v = `2`

                    )->end(
                    )->ele( `TileContent`
                        )->a( n = `unit`   v = `EUR`
                        )->a( n = `footer` v = `Current Quarter`
                        )->tag( `ImageContent`
                            )->a( n = `src` v = `sap-icon://check-availability`

                    )->end(
                )->end(

                )->ele( `Text`
                    )->a( n = `text` v = `Lorem ipsum dolor sit amet (content abbreviated from the original filler text)`
                    )->ele( `layoutData`
                        )->tag( n = `GridContainerItemLayoutData` ns = `f`
                            )->a( n = `columns` v = `4`

                    )->end(
                )->end(
            )->end(
        )->end( ).

    client->view_display( view->stringify( ) ).

  ENDMETHOD.


  METHOD on_event.

    IF client->get_event( ) = `COLUMNS_CHANGE`.
      " onGridColumnsChange: setText('Current grid columns count: ' + columns)
      columns_text = |Current grid columns count: { client->get_event_arg( ) }|.
    ENDIF.

  ENDMETHOD.


  METHOD model_init.

    cities = VALUE #(
      ( text = `Berlin` key = `BR` )
      ( text = `London` key = `LN` )
      ( text = `Madrid` key = `MD` )
      ( text = `Prague` key = `PR` )
      ( text = `Paris`  key = `PS` )
      ( text = `Sofia`  key = `SF` )
      ( text = `Vienna` key = `VN` )
    ).

    productitems = VALUE #(
      ( title = `Notebook HT` subtitle = `ID23452256-D44`  revenue = `27.25K EUR` statusschema = `Success` )
      ( title = `Notebook XT` subtitle = `ID27852256-D47`  revenue = `7.35K EUR`  statusschema = `Error` )
      ( title = `Notebook ST` subtitle = `ID123555587-I05` revenue = `22.89K EUR` statusschema = `Warning` )
    ).

  ENDMETHOD.

ENDCLASS.