Browser
Writes to the browser's local and session storage and reads it back, so a value survives a reload without any state in the backend.
Z2UI5_CL_SMP_APP_327
Learn
Browser
UI5 1.71
The facts
- Repository
- abap2UI5/samples
- Class
Z2UI5_CL_SMP_APP_327- Source file
z2ui5_cl_smp_app_327.clas.abap↗- Category
- Browser
- Learning path
- Reach outside the view
- Minimum UI5
- 1.71 — the floor abap2UI5 holds its samples to
- In the playground
- runs in the browser, with no system and nothing installed
- Documentation
- abap2ui5.github.io/docs/cookbook/browser_interaction/clipbo… ↗
Keywords: localstorage, sessionstorage, persist, store_data, offline
Controls it builds
- sap.m.Button
- sap.m.Input
- sap.m.Label
- sap.m.MessageStrip
- sap.m.Page
- sap.m.Select
- sap.m.Shell
- sap.ui.core.Item
- sap.ui.core.mvc.View
- sap.ui.layout.form.SimpleForm
- z2ui5.cc.Storage
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_smp_app_327.clas.abap — 217 lines
Click a number to link to a line — shift-click for a range.
Read it on GitHub ↗
" @keywords localstorage sessionstorage persist store_data offline
" @summary Writes to the browser's local and session storage and reads it back, so a value survives a reload without any state in the backend.
" @docs https://abap2ui5.github.io/docs/cookbook/browser_interaction/clipboard
CLASS z2ui5_cl_smp_app_327 DEFINITION PUBLIC.
PUBLIC SECTION.
INTERFACES z2ui5_if_app.
" Both fields are strings on purpose. The value round-trips through the
" browser and back through the storage, so whatever sits under the key is
" outside this app's control - and the framework converts it into these
" components BEFORE main( ) runs, where no TRY/CATCH of ours can reach it.
" A numeric component would let one oversized stored value (or a leftover
" from an earlier shape) fail the conversion on every single app start,
" leaving no screen from which to clear it.
TYPES:
BEGIN OF ty_s_value,
field1 TYPE string,
field2 TYPE string,
END OF ty_s_value.
TYPES:
BEGIN OF ty_s_storage,
type TYPE string,
prefix TYPE string,
key TYPE string,
value TYPE ty_s_value,
END OF ty_s_storage.
TYPES:
BEGIN OF ty_s_type,
type TYPE string,
END OF ty_s_type.
DATA s_storage TYPE ty_s_storage.
DATA s_stored_value TYPE ty_s_value.
DATA t_types TYPE STANDARD TABLE OF ty_s_type WITH EMPTY KEY.
PROTECTED SECTION.
DATA client TYPE REF TO z2ui5_if_client.
METHODS on_init.
METHODS on_event.
METHODS view_display.
METHODS json_get_value
IMPORTING
json TYPE string
name TYPE string
RETURNING
VALUE(result) TYPE string.
PRIVATE SECTION.
ENDCLASS.
CLASS z2ui5_cl_smp_app_327 IMPLEMENTATION.
METHOD z2ui5_if_app~main.
me->client = client.
IF client->check_on_init( ).
on_init( ).
ELSEIF client->check_on_navigated( ).
view_display( ).
ELSEIF client->check_on_event( ).
on_event( ).
ENDIF.
ENDMETHOD.
METHOD on_init.
t_types = VALUE #( ( type = `local` ) ( type = `session` ) ).
s_storage = VALUE #( type = `local`
prefix = `prefix1`
key = `key1`
value = VALUE #( field1 = `1`
field2 = `textfld1` ) ).
view_display( ).
ENDMETHOD.
METHOD on_event.
CASE client->get_event( ).
WHEN `LOCAL_STORAGE_LOADED`.
" The z2ui5:Storage control read a value out of the browser storage
" and reports it through its `finished` event. The payload is a whole
" structure, so it arrives as JSON - here it is picked apart field by
" field, which is also what keeps this tolerant: whatever sits under
" the key may carry more (or other) fields than this app models - an
" earlier shape, or a value someone else wrote. A field that is not
" there simply stays empty.
DATA(lv_json) = client->get_event_arg( 4 ).
s_storage-value = VALUE #( field1 = json_get_value( json = lv_json
name = `FIELD1` )
field2 = json_get_value( json = lv_json
name = `FIELD2` ) ).
WHEN `GET_STORED_VALUE`.
s_storage-value = s_stored_value.
ENDCASE.
ENDMETHOD.
METHOD json_get_value.
" A minimal reader for one string field of a flat JSON object: find
" `"<name>":"` and take what stands up to the next quote. The model writes
" the ABAP component names in upper case, hence the case-insensitive
" search. An app parsing arbitrary JSON wants a real parser instead.
DATA(lv_marker) = |"{ name }":"|.
DATA(lv_off) = find( val = json sub = lv_marker case = abap_false ).
IF lv_off < 0.
RETURN.
ENDIF.
result = substring_before( val = substring( val = json
off = lv_off + strlen( lv_marker ) )
sub = `"` ).
ENDMETHOD.
METHOD view_display.
DATA(view) = z2ui5_cl_ui5_view_builder=>factory(
)->ele( n = `View` ns = `mvc`
)->a( n = `displayBlock` v = `true`
)->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:form` v = `sap.ui.layout.form`
)->a( n = `xmlns:z2ui5` v = `z2ui5.cc` ).
DATA(page) = view->ele( `Shell`
)->ele( `Page`
)->a( n = `title` v = `abap2UI5 - Browser - Local and Session Storage`
)->a( n = `showNavButton` b = client->check_app_prev_stack( )
)->a( n = `navButtonPress` v = client->_event_nav_app_leave( ) ).
page->tag( `MessageStrip`
)->a( n = `text` v = `Reads and writes the browser's local or session storage. The ` &&
`value is a whole ABAP structure, not just a string: the write ` &&
`side sends it with the STORE_DATA frontend action, the invisible ` &&
`z2ui5:Storage control reads it back and reports it as JSON.`
)->a( n = `type` v = `Information`
)->a( n = `showIcon` b = abap_true
)->a( n = `class` v = `sapUiSmallMargin` ).
page->ele( n = `SimpleForm` ns = `form`
)->a( n = `title` v = `Local/Session Storage`
)->a( n = `editable` b = abap_true
)->ele( n = `content` ns = `form`
)->tag( `Label`
)->a( n = `text` v = `Type`
)->ele( `Select`
)->a( n = `forceSelection` b = abap_true
)->a( n = `selectedKey` v = client->_bind( s_storage-type )
)->a( n = `items` v = client->_bind( t_types )
)->tag( n = `Item` ns = `core`
)->a( n = `key` v = `{TYPE}`
)->a( n = `text` v = `{TYPE}`
)->end(
)->tag( `Label`
)->a( n = `text` v = `Prefix`
)->tag( `Input`
)->a( n = `value` v = client->_bind( s_storage-prefix )
)->tag( `Label`
)->a( n = `text` v = `Key`
)->tag( `Input`
)->a( n = `value` v = client->_bind( s_storage-key )
)->tag( `Label`
)->a( n = `text` v = `Value - Field 1`
)->tag( `Input`
)->a( n = `type` v = `Number`
)->a( n = `value` v = client->_bind( s_storage-value-field1 )
)->tag( `Label`
)->a( n = `text` v = `Value - Field 2`
)->tag( `Input`
)->a( n = `value` v = client->_bind( s_storage-value-field2 )
)->tag( `Label`
)->a( n = `text` v = ``
)->tag( `Button`
)->a( n = `press` v = client->follow_up_action(
val = z2ui5_if_client=>cs_event-store_data
t_arg = VALUE #( ( |${ client->_bind( s_storage ) }| ) ) )
)->a( n = `text` v = `store`
)->tag( `Button`
)->a( n = `press` v = client->_event( `GET_STORED_VALUE` )
)->a( n = `text` v = `get` ).
" Invisible companion control: it reads `key` out of the selected storage
" and fires `finished` when the stored value differs from `value`. The
" comparison is by value, so a structure does not re-trigger on every
" render.
page->tag( n = `Storage` ns = `z2ui5`
)->a( n = `finished` v = client->_event( val = `LOCAL_STORAGE_LOADED`
t_arg = VALUE #( ( `${$parameters>/type}` )
( `${$parameters>/prefix}` )
( `${$parameters>/key}` )
( `${$parameters>/value}` ) ) )
)->a( n = `type` v = client->_bind( s_storage-type )
)->a( n = `prefix` v = client->_bind( s_storage-prefix )
)->a( n = `key` v = client->_bind( s_storage-key )
)->a( n = `value` v = client->_bind( s_stored_value ) ).
client->view_display( view->stringify( ) ).
ENDMETHOD.
ENDCLASS.
More in Browser
On this page