abap2UI5

Hash

The whole hash_* family in one app: hash_set pushes #/detail, hash_replace rewrites it in place, hash_back steps back like a router, a deep link restores.

Z2UI5_CL_SMP_APP_499

Learn Hash UI5 1.71

The facts

Repository
abap2UI5/samples
Class
Z2UI5_CL_SMP_APP_499
Source file
z2ui5_cl_smp_app_499.clas.abap
Category
Hash
Learning path
Move through the app
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/event_navigation/navigatio… ↗

Keywords: routing, hash, url, page, browser, back, forward, history, deep, link, reload, hash_set, hash_replace, hash_back, hash_attach_changed, navcontainer, router, onnavback

Controls it builds

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_499.clas.abap — 227 lines Read it on GitHub ↗
" @keywords routing hash url page browser back forward history deep link reload hash_set hash_replace hash_back hash_attach_changed navcontainer router onnavback
" @summary The whole hash_* family in one app: hash_set pushes #/detail, hash_replace rewrites it in place, hash_back steps back like a router, a deep link restores.
" @docs https://abap2ui5.github.io/docs/cookbook/event_navigation/navigation/hash
"! App-owned hash routing - the URL semantics of a UI5 router, 1:1, and the
"! whole hash_* family (named after sap/ui/core/routing/HashChanger) in one
"! place:
"!
"!  - the start URL carries NO hash
"!  - opening the detail page writes '#/detail' via hash_set - setHash, a
"!    real PUSHED history entry
"!  - switching the detail variant rewrites the URL via hash_replace -
"!    replaceHash, NO new entry: the browser Back button skips the variant
"!    switches and returns straight to the first page
"!  - the BROWSER Back/Forward buttons - and a manual edit of the hash -
"!    round-trip as the event hash_attach_changed registered, and the
"!    handler shows the page the live hash (get( )-s_config-hash) names;
"!    the app instance is untouched, so the entered data survives
"!  - the in-app back button is cs_event-hash_back with '/' as its
"!    FALLBACK: the UI5 onNavBack pattern. Normally one real, consumed
"!    window.history.go(-1) - but on a COLD deep link ('#/detail' opened
"!    fresh) there is no in-app step to take, so the fallback replaces to
"!    the start page instead of falling out of the app
"!  - a reload or a shared link with '#/detail' lands on the detail page
"!
"! The draft-based routing modes (cs_event-hash_routing) are the siblings
"! z2ui5_cl_smp_app_468 and z2ui5_cl_smp_app_480. Replaces the former
"! z2ui5_cl_smp_app_322, which pushed a suffix past the UI5 HashChanger and
"! had to reach for raw JavaScript to step back.
CLASS z2ui5_cl_smp_app_499 DEFINITION PUBLIC.

  PUBLIC SECTION.
    INTERFACES z2ui5_if_app.

    DATA quantity TYPE string.
    DATA variant  TYPE string VALUE `a`.

  PROTECTED SECTION.
    DATA client       TYPE REF TO z2ui5_if_client.
    DATA check_detail TYPE abap_bool.

    METHODS view_display.
    METHODS on_event.
    METHODS hash_apply.

  PRIVATE SECTION.
ENDCLASS.


CLASS z2ui5_cl_smp_app_499 IMPLEMENTATION.

  METHOD z2ui5_if_app~main.

    me->client = client.

    IF client->check_on_navigated( ).
      view_display( ).

    ELSEIF client->check_on_event( ).
      on_event( ).
    ENDIF.

  ENDMETHOD.


  METHOD view_display.

    " a deep link / reload: the live hash rides in s_config-hash on every
    " request, so a render whose hash already names the detail page starts
    " there - the routeMatched of a cold start
    hash_apply( ).

    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` ).
    DATA(nav) = view->ele( `Shell`
        )->ele( `NavContainer`
            )->a( n = `id` v = `nav` ).

    DATA(main) = nav->ele( `Page`
        )->a( n = `id`             v = `page-main`
        )->a( n = `title`          v = `abap2UI5 - App-Owned Hash Routing`
        )->a( n = `showNavButton`  b = client->check_app_prev_stack( )
        )->a( n = `navButtonPress` v = client->_event_nav_app_leave( ) ).

    main->tag( `MessageStrip`
        )->a( n = `text`     v = `The URL has no hash right now. Type something, open the detail page and watch ` &&
                   `the address bar: hash_set writes #/detail, and the BROWSER Back button returns here ` &&
                   `- with the input still set.`
        )->a( n = `type`     v = `Information`
        )->a( n = `showIcon` b = abap_true
        )->a( n = `class`    v = `sapUiSmallMargin` ).

    DATA(form) = main->ele( n = `SimpleForm` ns = `form`
        )->a( n = `title`    v = `Some state`
        )->a( n = `editable` b = abap_true
        )->ele( n = `content` ns = `form` ).

    form->tag( `Label`
        )->a( n = `text` v = `quantity` ).
    form->tag( `Input`
        )->a( n = `value` v = client->_bind( quantity ) ).

    form->tag( `Button`
        )->a( n = `press` v = client->_event( `GO_DETAIL` )
        )->a( n = `text`  v = `open the detail page (#/detail)`
        )->a( n = `type`  v = `Emphasized` ).

    DATA(detail) = nav->ele( `Page`
        )->a( n = `id`             v = `page-detail`
        )->a( n = `title`          v = `Detail (#/detail)`
        )->a( n = `showNavButton`  b = abap_true
        " the router app's nav-back, the UI5 onNavBack pattern: one real,
        " CONSUMED step back in the browser history - and on a cold deep
        " link, where no step exists, a REPLACE to the '/' fallback. Either
        " way the hash change round-trips as HASH_CHANGED below
        )->a( n = `navButtonPress` v = client->follow_up_action( val   = z2ui5_if_client=>cs_event-hash_back
                                                                 t_arg = VALUE #( ( `/` ) ) ) ).

    detail->tag( `MessageStrip`
        )->a( n = `text`     v = `This page is #/detail. Reload the browser or share the URL - it lands here. ` &&
                   `The back arrow is cs_event-hash_back with '/' as fallback: normally a real ` &&
                   `window.history.go(-1), and on a cold deep link a replace to the start page.`
        )->a( n = `type`     v = `Success`
        )->a( n = `showIcon` b = abap_true
        )->a( n = `class`    v = `sapUiSmallMargin` ).

    DATA(vform) = detail->ele( n = `SimpleForm` ns = `form`
        )->a( n = `title`    v = `hash_replace - the URL follows, Back skips it`
        )->a( n = `editable` b = abap_true
        )->ele( n = `content` ns = `form` ).

    vform->tag( `Label`
        )->a( n = `text` v = `variant (watch the URL - and note Back still returns to the first page)` ).
    vform->ele( `SegmentedButton`
        )->a( n = `selectedKey`     v = client->_bind( variant )
        )->a( n = `selectionChange` v = client->_event( val = `VARIANT` arg = `${$parameters>/item}.getKey()` )
        )->ele( `items`
            )->tag( `SegmentedButtonItem`
                )->a( n = `key`  v = `a`
                )->a( n = `text` v = `Variant A`
            )->tag( `SegmentedButtonItem`
                )->a( n = `key`  v = `b`
                )->a( n = `text` v = `Variant B`
            )->tag( `SegmentedButtonItem`
                )->a( n = `key`  v = `c`
                )->a( n = `text` v = `Variant C`

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

    detail->tag( `ObjectStatus`
        )->a( n = `text`  v = client->_bind( quantity )
        )->a( n = `title` v = `quantity from the first page`
        )->a( n = `class` v = `sapUiSmallMargin` ).

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

    " hash changes the app did not write itself (browser Back/Forward, a
    " manual edit) round-trip as HASH_CHANGED - registered per render, since
    " the registration dies with an app switch
    client->follow_up_action( val   = z2ui5_if_client=>cs_event-hash_attach_changed
                              t_arg = VALUE #( ( `HASH_CHANGED` ) ) ).

    " a rebuilt NavContainer is back on its first page while check_detail
    " survives as class state - re-issue the page it should show
    IF check_detail = abap_true.
      client->follow_up_action( val   = client->cs_event-control_by_id
                                t_arg = VALUE #( ( `nav` ) ( `to` ) ( `page-detail` ) ) ).
    ENDIF.

  ENDMETHOD.


  METHOD on_event.

    CASE client->get_event( ).

      WHEN `GO_DETAIL`.
        " the router's navTo: switch the page and PUSH the app-owned hash -
        " a real history entry, so the browser Back button has a step to take
        check_detail = abap_true.
        client->follow_up_action( val   = client->cs_event-control_by_id
                                  t_arg = VALUE #( ( `nav` ) ( `to` ) ( `page-detail` ) ) ).
        client->hash_set( |/detail/{ variant }| ).

      WHEN `VARIANT`.
        " the router's replace-navTo: the URL follows the variant WITHOUT a
        " new history entry - Back keeps returning to the first page, not
        " through every variant ever clicked
        variant = client->get_event_arg( ).
        client->hash_replace( |/detail/{ variant }| ).

      WHEN `HASH_CHANGED`.
        " the router's routeMatched: show the page the hash now names
        hash_apply( ).
        client->follow_up_action( val   = client->cs_event-control_by_id
                                  t_arg = VALUE #( ( `nav` )
                                                   ( `to` )
                                                   ( COND #( WHEN check_detail = abap_true
                                                             THEN `page-detail`
                                                             ELSE `page-main` ) ) ) ).

    ENDCASE.

  ENDMETHOD.


  METHOD hash_apply.

    " '/detail' or '/detail/{variant}' - everything else is the first page
    DATA(lv_hash) = client->get( )-s_config-hash.
    check_detail = xsdbool( lv_hash CS `/detail` ).
    IF check_detail = abap_true.
      DATA(lv_variant) = substring_after( val = lv_hash sub = `/detail/` ).
      IF lv_variant CO `abc` AND lv_variant IS NOT INITIAL.
        variant = lv_variant.
      ENDIF.
    ENDIF.

  ENDMETHOD.

ENDCLASS.

More in Hash

Search every abap2UI5 sample · the full list on one page

On this page