Flexible Column Layout with Routing and first page in fullscreen only
Flexible Column Layout as an app with routing that displays different pages in the initial column. The first page is only displayed in OneColumn layout type
Z2UI5_CL_SMPC_APP_578
The facts
- Repository
- abap2UI5/samples-controls
- Class
Z2UI5_CL_SMPC_APP_578- Source file
z2ui5_cl_smpc_app_578.clas.abap↗- Library
- sap.f
- UI5 entity
sap.f.FlexibleColumnLayout- Demo kit sample
sap.f.sample.FlexibleColumnLayoutWithFullscreenPage- SAP's own sample
- running at sdk.openui5.org ↗
- Minimum UI5
- 1.73
- In the playground
- runs in the browser, with no system and nothing installed
Keywords: flexiblecolumnlayout, flexible, column, layout, sap.f, flexiblecolumnlayoutwithfullscreenpage, dynamicpagetitle, title, table, text, columnlistitem, objectidentifier
Controls it builds
- sap.f.DynamicPage
- sap.f.DynamicPageTitle
- sap.f.FlexibleColumnLayout
- sap.m.Avatar
- sap.m.Button
- sap.m.Column
- sap.m.ColumnListItem
- sap.m.FlexBox
- sap.m.Label
- sap.m.ObjectIdentifier
- sap.m.ObjectNumber
- sap.m.OverflowToolbar
- sap.m.OverflowToolbarButton
- sap.m.SearchField
- sap.m.Table
- sap.m.Text
- sap.m.Title
- sap.m.ToolbarSpacer
- sap.m.VBox
- sap.ui.core.mvc.View
- sap.ui.layout.form.SimpleForm
- sap.uxap.ObjectPageDynamicHeaderTitle
- sap.uxap.ObjectPageLayout
- sap.uxap.ObjectPageSection
- sap.uxap.ObjectPageSubSection
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
Nothing is installed and nothing is sent anywhere: the ABAP is compiled to JavaScript in this browser and runs against abap2UI5 itself.
The ABAP
" @keywords flexiblecolumnlayout flexible column layout sap.f flexiblecolumnlayoutwithfullscreenpage dynamicpagetitle title table text columnlistitem objectidentifier
" @summary Flexible Column Layout as an app with routing that displays different pages in the initial column. The first page is only displayed in OneColumn layout type
CLASS z2ui5_cl_smpc_app_578 DEFINITION PUBLIC.
PUBLIC SECTION.
INTERFACES z2ui5_if_app.
TYPES: BEGIN OF ty_s_product,
productid TYPE string,
name TYPE string,
maincategory TYPE string,
category TYPE string,
suppliername TYPE string,
productpicurl TYPE string,
description TYPE string,
price TYPE p LENGTH 9 DECIMALS 2,
currencycode TYPE string,
END OF ty_s_product.
TYPES ty_t_product TYPE STANDARD TABLE OF ty_s_product WITH EMPTY KEY.
TYPES: BEGIN OF ty_s_supplier,
text TYPE string,
END OF ty_s_supplier.
TYPES ty_t_supplier TYPE STANDARD TABLE OF ty_s_supplier WITH EMPTY KEY.
DATA t_products TYPE ty_t_product.
DATA t_rows TYPE ty_t_product.
DATA t_suppliers TYPE ty_t_supplier.
" /ProductCollectionStats/Filters/0/values - the categories page of the
" begin column, which this sample starts on
DATA t_categories TYPE ty_t_supplier.
" the FlexibleColumnLayout state the router drives in the original
DATA layout TYPE string VALUE `OneColumn`.
DATA total_count TYPE i.
DATA descending TYPE abap_bool.
" the beginColumnPages page the LIVE FlexibleColumnLayout was last sent to.
" A column position is control state, not model state, so view_display( )
" loses it (app 585 idiom); this field is what lets it be re-issued
DATA begin_page TYPE string.
" the product the mid column shows and the supplier the end column shows
DATA d_name TYPE string.
DATA d_productid TYPE string.
DATA d_maincategory TYPE string.
DATA d_category TYPE string.
DATA d_suppliername TYPE string.
DATA d_productpicurl TYPE string.
DATA d_description TYPE string.
DATA d_price TYPE string.
DATA dd_text TYPE string.
PROTECTED SECTION.
DATA client TYPE REF TO z2ui5_if_client.
" the router state the original keeps (currentRouteName + the route's
" arguments): the category travels as its NAME (URL-encoded, spaces as
" %20), product and supplier as INDICES into the mock collections
DATA route TYPE string VALUE `list`.
DATA route_category TYPE string.
DATA product_ix TYPE i.
DATA supplier_ix TYPE i.
METHODS view_display.
METHODS on_event.
METHODS detail_bind IMPORTING productid TYPE string.
METHODS category_apply IMPORTING iv_category TYPE string.
METHODS hash_apply IMPORTING iv_hash TYPE string.
METHODS hash_push IMPORTING check_replace TYPE abap_bool OPTIONAL.
METHODS model_init.
PRIVATE SECTION.
ENDCLASS.
CLASS z2ui5_cl_smpc_app_578 IMPLEMENTATION.
METHOD z2ui5_if_app~main.
me->client = client.
IF client->check_on_init( ).
model_init( ).
t_rows = t_products.
total_count = lines( t_products ).
view_display( ).
ELSEIF client->check_on_navigated( ).
view_display( ).
ELSEIF client->check_on_event( ).
on_event( ).
ENDIF.
ENDMETHOD.
METHOD view_display.
" the router also matches a deep link / reload (`#/detailDetail/Laptops/
" 0/TwoColumnsMidExpanded`): the live hash rides in s_config-hash on
" every request; applying it is idempotent, so a rebuild whose hash
" matches the state simply re-derives it
DATA(lv_hash) = client->get( )-s_config-hash.
IF lv_hash IS NOT INITIAL AND lv_hash <> `#`.
hash_apply( lv_hash ).
ENDIF.
DATA(view) = z2ui5_cl_ui5_view_builder=>factory( ).
DATA(fcl) = view->ele( n = `View` ns = `mvc`
)->a( n = `height` v = `100%`
)->a( n = `xmlns` v = `sap.m`
)->a( n = `xmlns:f` v = `sap.f`
)->a( n = `xmlns:form` v = `sap.ui.layout.form`
)->a( n = `xmlns:mvc` v = `sap.ui.core.mvc`
)->a( n = `xmlns:uxap` v = `sap.uxap`
)->ele( n = `FlexibleColumnLayout` ns = `f`
)->a( n = `id` v = `fcl`
)->a( n = `backgroundDesign` v = `Translucent`
" the original wires stateChange to onStateChanged: only a layout
" change by a NAVIGATION ARROW replace-navTo's the URL - the flag
" and the new layout travel with the event, the backend guards on it
)->a( n = `stateChange` v = client->_event( val = `STATE_CHANGED` t_arg = VALUE #( ( `${$parameters>/isNavigationArrow}` ) ( `${$parameters>/layout}` ) ) )
)->a( n = `layout` v = client->_bind( layout ) ).
" List.view.xml - the categories page the sample starts on, and
" Detail.view.xml - the products page that replaces it in the begin column
DATA(begin_column) = fcl->ele( n = `beginColumnPages` ns = `f` ).
begin_column->ele( n = `DynamicPage` ns = `f`
)->a( n = `id` v = `categoriesPage`
)->a( n = `toggleHeaderOnTitleClick` v = `false`
)->ele( n = `title` ns = `f`
)->ele( n = `DynamicPageTitle` ns = `f`
)->ele( n = `heading` ns = `f`
)->tag( `Title`
)->a( n = `text` v = `Categories`
)->end(
)->end(
)->end(
)->ele( n = `content` ns = `f`
)->ele( `Table`
)->a( n = `id` v = `categoriesTable`
)->a( n = `mode` v = `SingleSelectMaster`
)->a( n = `inset` v = `false`
)->a( n = `class` v = `sapFDynamicPageAlignContent`
)->a( n = `width` v = `auto`
)->a( n = `items` v = client->_bind( t_categories )
)->a( n = `itemPress` v = client->_event( val = `CATEGORY_ITEM` arg = `${$parameters>/listItem}.getBindingContext().getProperty('TEXT')` )
)->ele( `columns`
)->ele( `Column`
)->a( n = `width` v = `12em`
)->tag( `Text`
)->a( n = `text` v = `Category`
)->end(
)->end(
)->ele( `items`
)->ele( `ColumnListItem`
)->a( n = `type` v = `Navigation`
)->ele( `cells`
)->tag( `ObjectIdentifier`
)->a( n = `title` v = `{TEXT}`
)->end(
)->end(
)->end(
)->end(
)->end(
)->end( ).
begin_column->ele( n = `DynamicPage` ns = `f`
)->a( n = `id` v = `dynamicPageId`
)->a( n = `toggleHeaderOnTitleClick` v = `false`
)->ele( n = `title` ns = `f`
)->ele( n = `DynamicPageTitle` ns = `f`
)->ele( n = `heading` ns = `f`
)->tag( `Title`
)->a( n = `text` v = `Products`
)->end(
)->end(
)->end(
)->ele( n = `content` ns = `f`
)->ele( `Table`
)->a( n = `id` v = `productsTable`
)->a( n = `mode` v = `SingleSelectMaster`
)->a( n = `inset` v = `false`
)->a( n = `class` v = `sapFDynamicPageAlignContent`
)->a( n = `width` v = `auto`
)->a( n = `items` v = client->_bind( t_rows )
)->a( n = `itemPress` v = client->_event( val = `LIST_ITEM` arg = `${$parameters>/listItem}.getBindingContext().getProperty('PRODUCTID')` )
)->ele( `headerToolbar`
)->ele( `OverflowToolbar`
)->tag( `ToolbarSpacer`
)->tag( `SearchField`
)->a( n = `width` v = `17.5rem`
)->a( n = `search` v = client->_event( val = `SEARCH` arg = `${$parameters>/query}` )
)->tag( `OverflowToolbarButton`
)->a( n = `icon` v = `sap-icon://add`
)->a( n = `type` v = `Transparent`
)->a( n = `tooltip` v = `Add`
)->a( n = `press` v = client->_event( `ADD` )
)->tag( `OverflowToolbarButton`
)->a( n = `icon` v = `sap-icon://sort`
)->a( n = `type` v = `Transparent`
)->a( n = `tooltip` v = `Sort`
)->a( n = `press` v = client->_event( `SORT` )
)->end(
)->end(
)->ele( `columns`
)->ele( `Column`
)->a( n = `width` v = `12em`
)->tag( `Text`
)->a( n = `text` v = `Product`
)->end(
)->ele( `Column`
)->a( n = `hAlign` v = `End`
)->tag( `Text`
)->a( n = `text` v = `Price`
)->end(
)->end(
)->ele( `items`
)->ele( `ColumnListItem`
)->a( n = `type` v = `Navigation`
)->ele( `cells`
)->tag( `ObjectIdentifier`
)->a( n = `title` v = `{NAME}`
)->a( n = `text` v = `{PRODUCTID}`
)->tag( `ObjectNumber`
)->a( n = `number` v = |\{ parts:[\{path:'PRICE'\},\{path:'CURRENCYCODE'\}], type:'sap.ui.model.type.Currency', formatOptions:\{showMeasure:false\} \}|
)->a( n = `unit` v = `{CURRENCYCODE}`
)->end(
)->end(
)->end(
)->end(
)->end(
)->ele( n = `footer` ns = `f`
)->ele( `OverflowToolbar`
)->tag( `ToolbarSpacer`
)->tag( `Button`
)->a( n = `type` v = `Accept`
)->a( n = `text` v = `Accept`
)->tag( `Button`
)->a( n = `type` v = `Reject`
)->a( n = `text` v = `Reject`
)->end(
)->end(
)->end( ).
" Detail.view.xml - the ObjectPage of the mid column
DATA(detail) = fcl->ele( n = `midColumnPages` ns = `f`
)->ele( n = `ObjectPageLayout` ns = `uxap`
)->a( n = `id` v = `ObjectPageLayout`
)->a( n = `showTitleInHeaderContent` v = `true`
)->a( n = `alwaysShowContentHeader` v = `false`
)->a( n = `preserveHeaderStateOnScroll` v = `false`
)->a( n = `headerContentPinnable` v = `true`
)->a( n = `isChildPage` v = `true`
)->a( n = `upperCaseAnchorBar` v = `false` ).
DATA(detail_title) = detail->ele( n = `headerTitle` ns = `uxap`
)->ele( n = `ObjectPageDynamicHeaderTitle` ns = `uxap` ).
detail_title->ele( n = `expandedHeading` ns = `uxap`
)->tag( `Title`
)->a( n = `text` v = client->_bind( d_name )
)->a( n = `wrapping` v = `true`
)->a( n = `class` v = `sapUiSmallMarginEnd`
)->end(
)->ele( n = `snappedHeading` ns = `uxap`
)->ele( `FlexBox`
)->a( n = `wrap` v = `Wrap`
)->a( n = `fitContainer` v = `true`
)->a( n = `alignItems` v = `Center`
)->ele( `FlexBox`
)->a( n = `wrap` v = `NoWrap`
)->a( n = `fitContainer` v = `true`
)->a( n = `alignItems` v = `Center`
)->a( n = `class` v = `sapUiTinyMarginEnd`
)->tag( `Avatar`
)->a( n = `src` v = client->_bind( d_productpicurl )
)->a( n = `displaySize` v = `S`
)->a( n = `displayShape` v = `Square`
)->tag( `Title`
)->a( n = `text` v = client->_bind( d_name )
)->a( n = `wrapping` v = `true`
)->a( n = `class` v = `sapUiTinyMarginEnd`
)->end(
)->end(
)->end(
)->ele( n = `navigationActions` ns = `uxap`
)->tag( `OverflowToolbarButton`
)->a( n = `id` v = `enterFullScreenBtn`
)->a( n = `type` v = `Transparent`
)->a( n = `icon` v = `sap-icon://full-screen`
)->a( n = `tooltip` v = `Enter Full Screen Mode`
)->a( n = `visible` v = |\{= ${ client->_bind( layout ) } !== 'MidColumnFullScreen' \}|
)->a( n = `press` v = client->_event( `MID_FULL_SCREEN` )
)->tag( `OverflowToolbarButton`
)->a( n = `id` v = `exitFullScreenBtn`
)->a( n = `type` v = `Transparent`
)->a( n = `icon` v = `sap-icon://exit-full-screen`
)->a( n = `tooltip` v = `Exit Full Screen Mode`
)->a( n = `visible` v = |\{= ${ client->_bind( layout ) } === 'MidColumnFullScreen' \}|
)->a( n = `press` v = client->_event( `MID_EXIT_FULL_SCREEN` )
)->tag( `OverflowToolbarButton`
)->a( n = `type` v = `Transparent`
)->a( n = `icon` v = `sap-icon://decline`
)->a( n = `tooltip` v = `Close middle column`
)->a( n = `visible` v = |\{= ${ client->_bind( layout ) } !== 'OneColumn' \}|
)->a( n = `press` v = client->_event( `MID_CLOSE` )
)->end(
)->ele( n = `actions` ns = `uxap`
)->tag( `Button`
)->a( n = `text` v = `Edit`
)->a( n = `type` v = `Emphasized`
)->tag( `Button`
)->a( n = `text` v = `Delete`
)->a( n = `type` v = `Transparent`
)->tag( `Button`
)->a( n = `text` v = `Copy`
)->a( n = `type` v = `Transparent`
)->tag( `Button`
)->a( n = `text` v = `Toggle Footer`
)->a( n = `type` v = `Transparent`
)->tag( `Button`
)->a( n = `icon` v = `sap-icon://action`
)->a( n = `tooltip` v = `Share`
)->a( n = `type` v = `Transparent`
)->end(
)->end( ).
detail->ele( n = `headerContent` ns = `uxap`
)->ele( `FlexBox`
)->a( n = `wrap` v = `Wrap`
)->a( n = `fitContainer` v = `true`
)->a( n = `alignItems` v = `Stretch`
)->tag( `Avatar`
)->a( n = `src` v = client->_bind( d_productpicurl )
)->a( n = `displaySize` v = `L`
)->a( n = `displayShape` v = `Square`
)->a( n = `class` v = `sapUiTinyMarginEnd`
)->ele( `VBox`
)->a( n = `justifyContent` v = `Center`
)->a( n = `class` v = `sapUiSmallMarginEnd`
)->tag( `Label`
)->a( n = `text` v = `Main Category`
)->tag( `Text`
)->a( n = `text` v = client->_bind( d_maincategory )
)->end(
)->ele( `VBox`
)->a( n = `justifyContent` v = `Center`
)->a( n = `class` v = `sapUiSmallMarginEnd`
)->tag( `Label`
)->a( n = `text` v = `Subcategory`
)->tag( `Text`
)->a( n = `text` v = client->_bind( d_category )
)->end(
)->ele( `VBox`
)->a( n = `justifyContent` v = `Center`
)->a( n = `class` v = `sapUiSmallMarginEnd`
)->tag( `Label`
)->a( n = `text` v = `Price`
)->tag( `ObjectNumber`
)->a( n = `number` v = client->_bind( d_price )
)->a( n = `emphasized` v = `false`
)->end(
)->end(
)->end( ).
DATA(sections) = detail->ele( n = `sections` ns = `uxap` ).
sections->ele( n = `ObjectPageSection` ns = `uxap`
)->a( n = `title` v = `General Information`
)->ele( n = `subSections` ns = `uxap`
)->ele( n = `ObjectPageSubSection` ns = `uxap`
)->ele( n = `blocks` ns = `uxap`
)->ele( n = `SimpleForm` ns = `form`
)->a( n = `maxContainerCols` v = `2`
)->a( n = `editable` v = `false`
)->a( n = `layout` v = `ResponsiveGridLayout`
)->a( n = `labelSpanL` v = `12`
)->a( n = `labelSpanM` v = `12`
)->a( n = `emptySpanL` v = `0`
)->a( n = `emptySpanM` v = `0`
)->a( n = `columnsL` v = `1`
)->a( n = `columnsM` v = `1`
)->ele( n = `content` ns = `form`
)->tag( `Label`
)->a( n = `text` v = `Product ID`
)->tag( `Text`
)->a( n = `text` v = client->_bind( d_productid )
)->tag( `Label`
)->a( n = `text` v = `Description`
)->tag( `Text`
)->a( n = `text` v = client->_bind( d_description )
)->tag( `Label`
)->a( n = `text` v = `Supplier`
)->tag( `Text`
)->a( n = `text` v = client->_bind( d_suppliername )
)->end(
)->end(
)->end(
)->end(
)->end(
)->end( ).
sections->ele( n = `ObjectPageSection` ns = `uxap`
)->a( n = `title` v = `Suppliers`
)->ele( n = `subSections` ns = `uxap`
)->ele( n = `ObjectPageSubSection` ns = `uxap`
)->ele( n = `blocks` ns = `uxap`
)->ele( `Table`
)->a( n = `id` v = `suppliersTable`
)->a( n = `mode` v = `SingleSelectMaster`
)->a( n = `items` v = client->_bind( t_suppliers )
)->a( n = `itemPress` v = client->_event( val = `SUPPLIER_ITEM` arg = `${$parameters>/listItem}.getBindingContext().getProperty('TEXT')` )
)->ele( `columns`
)->tag( `Column`
)->end(
)->ele( `items`
)->ele( `ColumnListItem`
)->a( n = `type` v = `Navigation`
)->ele( `cells`
)->tag( `ObjectIdentifier`
)->a( n = `text` v = `{TEXT}`
)->end(
)->end(
)->end(
)->end(
)->end(
)->end(
)->end(
)->end( ).
" DetailDetailDetail.view.xml - the end column
fcl->ele( n = `endColumnPages` ns = `f`
)->ele( n = `DynamicPage` ns = `f`
)->a( n = `toggleHeaderOnTitleClick` v = `false`
)->ele( n = `title` ns = `f`
)->ele( n = `DynamicPageTitle` ns = `f`
)->ele( n = `heading` ns = `f`
)->ele( `FlexBox`
)->a( n = `wrap` v = `Wrap`
)->a( n = `fitContainer` v = `true`
)->a( n = `alignItems` v = `Center`
)->tag( `Title`
)->a( n = `text` v = client->_bind( dd_text )
)->a( n = `wrapping` v = `true`
)->a( n = `class` v = `sapUiTinyMarginEnd`
)->end(
)->end(
)->ele( n = `navigationActions` ns = `f`
)->tag( `OverflowToolbarButton`
)->a( n = `type` v = `Transparent`
)->a( n = `icon` v = `sap-icon://full-screen`
)->a( n = `tooltip` v = `Enter Full Screen Mode`
)->a( n = `visible` v = |\{= ${ client->_bind( layout ) } !== 'EndColumnFullScreen' \}|
)->a( n = `press` v = client->_event( `END_FULL_SCREEN` )
)->tag( `OverflowToolbarButton`
)->a( n = `type` v = `Transparent`
)->a( n = `icon` v = `sap-icon://exit-full-screen`
)->a( n = `tooltip` v = `Exit Full Screen Mode`
)->a( n = `visible` v = |\{= ${ client->_bind( layout ) } === 'EndColumnFullScreen' \}|
)->a( n = `press` v = client->_event( `END_EXIT_FULL_SCREEN` )
)->tag( `OverflowToolbarButton`
)->a( n = `type` v = `Transparent`
)->a( n = `icon` v = `sap-icon://decline`
)->a( n = `tooltip` v = `Close end column`
)->a( n = `press` v = client->_event( `END_CLOSE` )
)->end(
)->end(
)->end(
)->ele( n = `content` ns = `f`
)->tag( `Text`
)->a( n = `text` v = `Information about Supplier`
)->end(
)->end(
)->end( ).
client->view_display( view->stringify( ) ).
" Component.js: oProductsModel.setSizeLimit(1000) - the collection is 123 rows
" and the JSONModel caps a bound aggregation at 100, so the table would stop 23
" rows short of the count its own title reports
client->follow_up_action( val = client->cs_event-set_size_limit
t_arg = VALUE #( ( `1000` ) ( client->cs_view-main ) ) ).
" The column position of a FlexibleColumnLayout is LIVE control state:
" view_display( ) destroys the MAIN slot and XMLView.create builds a fresh
" tree, so the begin column comes back on the first beginColumnPages entry
" (categoriesPage) - while layout and t_rows are class state that survive.
" Measured 2026-08-27: after a SEARCH the user was back on the categories
" while the layout still claimed three columns and the filtered products
" table was bound but off screen. Re-issuing the SAME page the CATEGORY_ITEM
" branch last sent is the app 585 idiom; a view that has never navigated
" parks nothing and issues nothing
IF begin_page IS NOT INITIAL.
client->follow_up_action( val = client->cs_event-control_by_id
t_arg = VALUE #( ( `fcl` ) ( `to` ) ( begin_page ) ) ).
ENDIF.
" the original's router, app-owned: the hash carries the route the way
" the manifest patterns spell it, and a hash change the app did not
" write (browser Back/Forward, a manual edit) round-trips as
" HASH_CHANGED. Re-asserted per render - it dies with an app switch
client->follow_up_action( val = client->cs_event-hash_attach_changed
t_arg = VALUE #( ( `HASH_CHANGED` ) ) ).
ENDMETHOD.
METHOD detail_bind.
" Detail.controller's bindElement( '/ProductCollection/<n>' ) - the relative
" bindings of the original resolve against the bound element, the port folds
" them to root-seeded fields (app 229 idiom)
ASSIGN t_products[ productid = productid ] TO FIELD-SYMBOL(<product>).
IF sy-subrc <> 0.
RETURN.
ENDIF.
d_name = <product>-name.
d_productid = <product>-productid.
d_maincategory = <product>-maincategory.
d_category = <product>-category.
d_suppliername = <product>-suppliername.
d_productpicurl = <product>-productpicurl.
d_description = <product>-description.
d_price = |{ <product>-currencycode } { <product>-price }|.
ENDMETHOD.
METHOD on_event.
CASE client->get_event( ).
WHEN `CATEGORY_ITEM`.
" List.controller's onListItemPress: the begin column swaps to the
" products page, filtered to the pressed category, and the mid column
" opens on the FIRST product of it - navTo('detailDetail') with the
" category name and that product's index into the FULL collection
category_apply( client->get_event_arg( ) ).
IF t_rows IS NOT INITIAL.
detail_bind( t_rows[ 1 ]-productid ).
READ TABLE t_products WITH KEY productid = t_rows[ 1 ]-productid TRANSPORTING NO FIELDS.
IF sy-subrc = 0.
product_ix = sy-tabix - 1.
ENDIF.
ENDIF.
route = `detailDetail`.
layout = `TwoColumnsMidExpanded`.
hash_push( ).
WHEN `LIST_ITEM`.
" Detail.controller's onListItemPress opens the mid column on that
" product - the route carries its index into the FULL collection
" (the bindingContext path index of the original)
detail_bind( client->get_event_arg( ) ).
READ TABLE t_products WITH KEY productid = client->get_event_arg( ) TRANSPORTING NO FIELDS.
IF sy-subrc = 0.
product_ix = sy-tabix - 1.
ENDIF.
route = `detailDetail`.
layout = `TwoColumnsMidExpanded`.
hash_push( ).
WHEN `SUPPLIER_ITEM`.
" handleItemPress: level 2 opens the end column
dd_text = client->get_event_arg( ).
READ TABLE t_suppliers WITH KEY text = dd_text TRANSPORTING NO FIELDS.
IF sy-subrc = 0.
supplier_ix = sy-tabix - 1.
ENDIF.
route = `detailDetailDetail`.
layout = `ThreeColumnsMidExpanded`.
hash_push( ).
WHEN `MID_FULL_SCREEN`.
route = `detailDetail`.
layout = `MidColumnFullScreen`.
hash_push( ).
WHEN `MID_EXIT_FULL_SCREEN`.
route = `detailDetail`.
layout = `TwoColumnsMidExpanded`.
hash_push( ).
WHEN `MID_CLOSE`.
" DetailDetail's handleClose leaves the products page alone in the
" begin column - navigateToView('detail')
route = `detail`.
layout = `OneColumn`.
hash_push( ).
WHEN `END_FULL_SCREEN`.
route = `detailDetailDetail`.
layout = `EndColumnFullScreen`.
hash_push( ).
WHEN `END_EXIT_FULL_SCREEN`.
route = `detailDetailDetail`.
layout = `ThreeColumnsMidExpanded`.
hash_push( ).
WHEN `END_CLOSE`.
route = `detailDetail`.
layout = `TwoColumnsMidExpanded`.
hash_push( ).
WHEN `STATE_CHANGED`.
" onStateChanged: the layout is a two-way binding, so the model
" already carries the value this event reports - but when a
" NAVIGATION ARROW changed it, the original replace-navTo's the
" URL: same route, new layout, no new history entry
IF client->get_event_arg( ) = abap_true.
layout = client->get_event_arg( 2 ).
hash_push( abap_true ).
ENDIF.
WHEN `HASH_CHANGED`.
" browser Back/Forward (or a manual edit) moved the app-owned hash -
" the router's routeMatched: derive route, category, indices and
" layout from the hash this request carries. The instance itself is
" untouched, so search text and sort order survive like in the
" original
hash_apply( client->get( )-s_config-hash ).
WHEN `SEARCH`.
" onSearch filters the table's items on Name
DATA(query) = to_upper( client->get_event_arg( ) ).
IF query IS INITIAL.
t_rows = t_products.
ELSE.
CLEAR t_rows.
LOOP AT t_products INTO DATA(product).
IF to_upper( product-name ) CS query.
APPEND product TO t_rows.
ENDIF.
ENDLOOP.
ENDIF.
WHEN `SORT`.
" onSort flips the Name sorter; a thin frontend sorts the data it sends
descending = xsdbool( descending = abap_false ).
IF descending = abap_true.
SORT t_rows BY name DESCENDING.
ELSE.
SORT t_rows BY name ASCENDING.
ENDIF.
WHEN `ADD`.
" onAdd: MessageBox.show( 'This functionality is not ready yet.' )
client->message_box_display( text = `This functionality is not ready yet.`
type = `information`
title = `Aw, Snap!` ).
ENDCASE.
ENDMETHOD.
METHOD category_apply.
" the category the URL (or the pressed row) names: filter the products
" page to it and swap the begin column onto that page. Idempotent - the
" same category leaves T_ROWS alone, so a search filtered further is not
" reset by the next render's hash_apply
IF iv_category = route_category AND begin_page IS NOT INITIAL.
RETURN.
ENDIF.
route_category = iv_category.
" the right-hand name of a WHERE resolves to the COLUMN, so the local
" one must not share it (apps 520/524)
DATA(sel_category) = iv_category.
CLEAR t_rows.
LOOP AT t_products INTO DATA(row) WHERE category = sel_category.
APPEND row TO t_rows.
ENDLOOP.
" park it too, so a later view_display( ) can put the column back
begin_page = `dynamicPageId`.
client->follow_up_action( val = client->cs_event-control_by_id
t_arg = VALUE #( ( `fcl` ) ( `to` ) ( begin_page ) ) ).
ENDMETHOD.
METHOD hash_apply.
" the router's routeMatched, read side: parse the app hash back into
" route, category, indices and layout. The original's patterns: ''
" (list start), '{layout}' (the ':layout:' list route),
" 'detail/{category}/{layout}',
" 'detailDetail/{category}/{product}/{layout}',
" 'detailDetailDetail/{category}/{product}/{supplier}/{layout}' -
" the category is its NAME (spaces ride URL-encoded), product/supplier
" are INDICES into the mock collections, defaulting to 0 like the
" original's `arguments.product || this._product || "0"`
DATA(lv_hash) = iv_hash.
IF lv_hash CS `#`.
lv_hash = substring_after( val = lv_hash sub = `#` ).
ENDIF.
SHIFT lv_hash LEFT DELETING LEADING `/`.
SPLIT lv_hash AT `/` INTO TABLE DATA(lt_seg).
DELETE lt_seg WHERE table_line IS INITIAL.
DATA(lv_cat) = replace( val = VALUE string( lt_seg[ 2 ] OPTIONAL ) sub = `%20` with = ` ` occ = 0 ).
DATA(lv_p) = VALUE string( lt_seg[ 3 ] OPTIONAL ).
DATA(lv_s) = VALUE string( lt_seg[ 4 ] OPTIONAL ).
CASE VALUE string( lt_seg[ 1 ] OPTIONAL ).
WHEN ``.
route = `list`.
layout = `OneColumn`.
" back on the categories page - the list route targets List.view
IF begin_page IS NOT INITIAL.
CLEAR begin_page.
CLEAR route_category.
client->follow_up_action( val = client->cs_event-control_by_id
t_arg = VALUE #( ( `fcl` ) ( `to` ) ( `categoriesPage` ) ) ).
ENDIF.
WHEN `detail`.
route = `detail`.
category_apply( lv_cat ).
layout = COND #( WHEN lv_p IS NOT INITIAL THEN lv_p ELSE `OneColumn` ).
WHEN `detailDetail`.
route = `detailDetail`.
category_apply( lv_cat ).
product_ix = COND #( WHEN lv_p CO `0123456789` AND lv_p IS NOT INITIAL AND strlen( lv_p ) <= 4 THEN lv_p ).
layout = COND #( WHEN lv_s IS NOT INITIAL THEN lv_s ELSE `TwoColumnsMidExpanded` ).
IF product_ix < lines( t_products ).
detail_bind( t_products[ product_ix + 1 ]-productid ).
ENDIF.
WHEN `detailDetailDetail`.
route = `detailDetailDetail`.
category_apply( lv_cat ).
product_ix = COND #( WHEN lv_p CO `0123456789` AND lv_p IS NOT INITIAL AND strlen( lv_p ) <= 4 THEN lv_p ).
supplier_ix = COND #( WHEN lv_s CO `0123456789` AND lv_s IS NOT INITIAL AND strlen( lv_s ) <= 4 THEN lv_s ).
layout = COND #( WHEN VALUE string( lt_seg[ 5 ] OPTIONAL ) IS NOT INITIAL
THEN lt_seg[ 5 ]
ELSE `ThreeColumnsMidExpanded` ).
IF product_ix < lines( t_products ).
detail_bind( t_products[ product_ix + 1 ]-productid ).
ENDIF.
IF supplier_ix < lines( t_suppliers ).
dd_text = t_suppliers[ supplier_ix + 1 ]-text.
ENDIF.
WHEN OTHERS.
" the single-segment ':layout:' list route, e.g. '#/OneColumn'
route = `list`.
layout = lt_seg[ 1 ].
IF begin_page IS NOT INITIAL.
CLEAR begin_page.
CLEAR route_category.
client->follow_up_action( val = client->cs_event-control_by_id
t_arg = VALUE #( ( `fcl` ) ( `to` ) ( `categoriesPage` ) ) ).
ENDIF.
ENDCASE.
ENDMETHOD.
METHOD hash_push.
DATA lv_hash TYPE string.
" the router's navTo, write side: compose the current route the way the
" manifest patterns spell it and push it as the app-owned hash. The
" category name is URL-encoded the way the original's navTo encodes it
DATA(lv_cat) = replace( val = route_category sub = ` ` with = `%20` occ = 0 ).
CASE route.
WHEN `detail`.
lv_hash = |/detail/{ lv_cat }/{ layout }|.
WHEN `detailDetail`.
lv_hash = |/detailDetail/{ lv_cat }/{ product_ix }/{ layout }|.
WHEN `detailDetailDetail`.
lv_hash = |/detailDetailDetail/{ lv_cat }/{ product_ix }/{ supplier_ix }/{ layout }|.
WHEN OTHERS.
lv_hash = |/{ layout }|.
ENDCASE.
" a NAVIGATION ARROW rewrites the URL in place (the original's
" replace-navTo) - everything else is a real, pushed history entry
IF check_replace = abap_true.
client->hash_replace( lv_hash ).
ELSE.
client->hash_set( lv_hash ).
ENDIF.
ENDMETHOD.
METHOD model_init.
" the full mock /ProductCollection, in the mock order - the items binding
" carries NO sorter, so the backend owns the order. Do not add one: a
" declared sorter is re-applied by JSONListBinding.update on every model
" change (ClientListBinding.applySort), so it becomes the primary key and
" the ABAP order survives only as a tiebreak - which is exactly what made
" the Sort button unable to sort here
t_products = VALUE #(
( productid = `HT-1000` name = `Notebook Basic 15`
maincategory = `Computer Systems` category = `Laptops` suppliername = `Very Best Screens` productpicurl = `https://sdk.openui5.org/test-resources/sap/ui/documentation/sdk/images/HT-1000.jpg`
description = `Notebook Basic 15 with 2,80 GHz quad core, 15" LCD, 4 GB DDR3 RAM, 500 GB Hard Disc, Windows 8 Pro` price = `956` currencycode = `EUR` )
( productid = `HT-1001` name = `Notebook Basic 17`
maincategory = `Computer Systems` category = `Laptops` suppliername = `Very Best Screens` productpicurl = `https://sdk.openui5.org/test-resources/sap/ui/documentation/sdk/images/HT-1001.jpg`
description = `Notebook Basic 17 with 2,80 GHz quad core, 17" LCD, 4 GB DDR3 RAM, 500 GB Hard Disc, Windows 8 Pro` price = `1249` currencycode = `EUR` )
( productid = `HT-1002` name = `Notebook Basic 18`
maincategory = `Computer Systems` category = `Laptops` suppliername = `Very Best Screens` productpicurl = `https://sdk.openui5.org/test-resources/sap/ui/documentation/sdk/images/HT-1002.jpg`
description = `Notebook Basic 18 with 2,80 GHz quad core, 18" LCD, 8 GB DDR3 RAM, 1000 GB Hard Disc, Windows 8 Pro` price = `1570` currencycode = `EUR` )
( productid = `HT-1003` name = `Notebook Basic 19`
maincategory = `Computer Systems` category = `Laptops` suppliername = `Smartcards` productpicurl = `https://sdk.openui5.org/test-resources/sap/ui/documentation/sdk/images/HT-1003.jpg`
description = `Notebook Basic 19 with 2,80 GHz quad core, 19" LCD, 8 GB DDR3 RAM, 1000 GB Hard Disc, Windows 8 Pro` price = `1650` currencycode = `EUR` )
( productid = `HT-1007` name = `ITelO Vault`
maincategory = `Computer Components` category = `Accessories` suppliername = `Technocom` productpicurl = `https://sdk.openui5.org/test-resources/sap/ui/documentation/sdk/images/HT-1007.jpg`
description = `Digital Organizer with State-of-the-Art Storage Encryption` price = `299` currencycode = `EUR` )
( productid = `HT-1010` name = `Notebook Professional 15`
maincategory = `Computer Systems` category = `Accessories` suppliername = `Very Best Screens` productpicurl = `https://sdk.openui5.org/test-resources/sap/ui/documentation/sdk/images/HT-1010.jpg`
description = `Notebook Professional 15 with 2,80 GHz quad core, 15" Multitouch LCD, 8 GB DDR3 RAM, 500 GB SSD - DVD-Writer (DVD-R/+R/-RW/-RAM),Windows 8 Pro` price = `1999` currencycode = `EUR` )
( productid = `HT-1011` name = `Notebook Professional 17`
maincategory = `Computer Systems` category = `Laptops` suppliername = `Very Best Screens` productpicurl = `https://sdk.openui5.org/test-resources/sap/ui/documentation/sdk/images/HT-1011.jpg`
description = `Notebook Professional 17 with 2,80 GHz quad core, 17" Multitouch LCD, 8 GB DDR3 RAM, 500 GB SSD - DVD-Writer (DVD-R/+R/-RW/-RAM),Windows 8 Pro` price = `2299` currencycode = `EUR` )
( productid = `HT-1020` name = `ITelO Vault Net`
maincategory = `Computer Components` category = `Accessories` suppliername = `Technocom` productpicurl = `https://sdk.openui5.org/test-resources/sap/ui/documentation/sdk/images/HT-1020.jpg`
description = `Digital Organizer with State-of-the-Art Encryption for Storage and Network Communications` price = `459` currencycode = `EUR` )
( productid = `HT-1021` name = `ITelO Vault SAT`
maincategory = `Computer Components` category = `Accessories` suppliername = `Technocom` productpicurl = `https://sdk.openui5.org/test-resources/sap/ui/documentation/sdk/images/HT-1021.jpg`
description = `Digital Organizer with State-of-the-Art Encryption for Storage and Secure Stellite Link` price = `149` currencycode = `EUR` )
( productid = `HT-1022` name = `Comfort Easy`
maincategory = `Computer Components` category = `Accessories` suppliername = `Technocom` productpicurl = `https://sdk.openui5.org/test-resources/sap/ui/documentation/sdk/images/HT-1022.jpg`
description = `32 GB Digital Assistant with high-resolution color screen` price = `1679` currencycode = `EUR` )
( productid = `HT-1023` name = `Comfort Senior`
maincategory = `Computer Components` category = `Accessories` suppliername = `Technocom` productpicurl = `https://sdk.openui5.org/test-resources/sap/ui/documentation/sdk/images/HT-1023.jpg`
description = `64 GB Digital Assistant with high-resolution color screen and synthesized voice output` price = `512` currencycode = `EUR` )
( productid = `HT-1030` name = `Ergo Screen E-I`
maincategory = `Computer Components` category = `Flat Screen Monitors` suppliername = `Very Best Screens` productpicurl = `https://sdk.openui5.org/test-resources/sap/ui/documentation/sdk/images/HT-1030.jpg`
description = `Optimum Hi-Resolution max. 1920 x 1080 @ 85Hz, Dot Pitch: 0.27mm` price = `230` currencycode = `EUR` )
( productid = `HT-1031` name = `Ergo Screen E-II`
maincategory = `Computer Components` category = `Flat Screen Monitors` suppliername = `Very Best Screens` productpicurl = `https://sdk.openui5.org/test-resources/sap/ui/documentation/sdk/images/HT-1031.jpg`
description = `Optimum Hi-Resolution max. 1920 x 1200 @ 85Hz, Dot Pitch: 0.26mm` price = `285` currencycode = `EUR` )
( productid = `HT-1032` name = `Ergo Screen E-III`
maincategory = `Computer Components` category = `Flat Screen Monitors` suppliername = `Very Best Screens` productpicurl = `https://sdk.openui5.org/test-resources/sap/ui/documentation/sdk/images/HT-1032.jpg`
description = `Optimum Hi-Resolution max. 2560 x 1440 @ 85Hz, Dot Pitch: 0.25mm` price = `345` currencycode = `EUR` )
( productid = `HT-1035` name = `Flat Basic`
maincategory = `Computer Components` category = `Flat Screen Monitors` suppliername = `Very Best Screens` productpicurl = `https://sdk.openui5.org/test-resources/sap/ui/documentation/sdk/images/HT-1035.jpg`
description = `Optimum Hi-Resolution max. 1600 x 1200 @ 85Hz, Dot Pitch: 0.24mm` price = `399` currencycode = `EUR` )
( productid = `HT-1036` name = `Flat Future`
maincategory = `Computer Components` category = `Flat Screen Monitors` suppliername = `Very Best Screens` productpicurl = `https://sdk.openui5.org/test-resources/sap/ui/documentation/sdk/images/HT-1036.jpg`
description = `Optimum Hi-Resolution max. 2048 x 1080 @ 85Hz, Dot Pitch: 0.26mm` price = `430` currencycode = `EUR` )
( productid = `HT-1037` name = `Flat XL`
maincategory = `Computer Components` category = `Flat Screen Monitors` suppliername = `Very Best Screens` productpicurl = `https://sdk.openui5.org/test-resources/sap/ui/documentation/sdk/images/HT-1037.jpg`
description = `Optimum Hi-Resolution max. 2016 x 1512 @ 85Hz, Dot Pitch: 0.24mm` price = `1230` currencycode = `EUR` )
( productid = `HT-1040` name = `Laser Professional Eco`
maincategory = `Printers & Scanners` category = `Printers` suppliername = `Alpha Printers` productpicurl = `https://sdk.openui5.org/test-resources/sap/ui/documentation/sdk/images/HT-1040.jpg`
description = `Print 2400 dpi image quality color documents at speeds of up to 32 ppm (color) or 36 ppm (monochrome), letter/A4. Powerful 500 MHz processor, 512MB of memory` price = `830` currencycode = `EUR` )
The first 900 lines of 1253 — the whole class is on GitHub.
More in sap.f
- Grid Container - Drag and Drop From List to GridContainer — This sample represents how items from a control which is not GridContainer can be dragged…
- Grid Container - Keyboard navigation between multiple grids — This sample demonstrates the keyboard navigation between multiple grids
- Semantic Page - Freestyle Sample — This sample demonstrates a SemanticPage with all semantic-specific actions both in the ti…
- Dynamic Page with Analytical Table — Dynamic Page containing an Analytical Table in the content area aligned with the SAP Fior…
- Dynamic Page with Wizard — Dynamic Page containing a sap.m.Wizard and WizardProgressNavigator in the content area.
- Flexible Column Layout with programmatic scrolling to an item — FlexibleColumnLayout where the app programmatically scrolls to some item within the newly…
- Flexible Column Layout with Routing and One Initial Column — Flexible Column Layout as an app with routing that starts with a single initial column.
- Flexible Column Layout with Routing and Two Initial Columns — Flexible Column Layout as an app with routing that starts with two initial columns.
- Grid List - Item Designs — This is a sample for GridList item templates representing a typical tools page dashboard…
- Navigation with keyboard arrows between multiple GridLists — This sample demonstrates the keyboard navigation between multiple grids
- Shell Bar with Product Switch — Shell Bar example with enabled Product Switch, configurable by the app developer. The Pro…
- Shell Bar with Flexible Column Layout — Example of Shell Bar in combination with Flexible Column Layout.