Samples / Learn / Focus

Focus

Puts the cursor in one table cell, addressed by column and row of the aggregation, which is how a validation jumps to the field it is about.

Class
z2ui5_cl_smp_app_421
Repository
abap2UI5/samples
UI5 libraries
sap.m, sap.ui.core
Lowest UI5 release
1.71
In the browser
Runs in the playground
Controls it builds
sap.m.Button, sap.m.CheckBox, sap.m.Column, sap.m.ColumnListItem, sap.m.Input, sap.m.Label, sap.m.MessageStrip, sap.m.OverflowToolbar, sap.m.Page, sap.m.Shell, sap.m.Table, sap.m.Text, sap.m.Title, sap.m.ToolbarSpacer, sap.ui.core.mvc.View
Documentation
cookbook/browser_interaction/focus ↗

The class

" @keywords table cell column row aggregation set_focus
" @summary Puts the cursor in one table cell, addressed by column and row of the aggregation, which is how a validation jumps to the field it is about.
" @docs https://abap2ui5.github.io/docs/cookbook/browser_interaction/focus
CLASS z2ui5_cl_smp_app_421 DEFINITION PUBLIC.

  PUBLIC SECTION.
    INTERFACES z2ui5_if_app.

    TYPES:
      BEGIN OF ty_s_row,
        index       TYPE i,
        title       TYPE string,
        value       TYPE string,
        info        TYPE string,
        checkbox    TYPE abap_bool,
        description TYPE string,
      END OF ty_s_row.
    DATA t_tab TYPE STANDARD TABLE OF ty_s_row WITH EMPTY KEY.

    DATA focuscolumn TYPE string.
    DATA focusrow    TYPE string.
    DATA focusid     TYPE string READ-ONLY.

  PROTECTED SECTION.
    CONSTANTS:
      BEGIN OF cs_column,
        title       TYPE string VALUE `Title`,
        color       TYPE string VALUE `Color`,
        info        TYPE string VALUE `Info`,
        checkbox    TYPE string VALUE `Checkbox`,
        description TYPE string VALUE `Description`,
      END OF cs_column.

    DATA client TYPE REF TO z2ui5_if_client.

    METHODS on_init.
    METHODS on_event.
    METHODS view_display.
    METHODS focus.
    METHODS read_focus.
    METHODS next_focus.
    METHODS default_focus.

  PRIVATE SECTION.
ENDCLASS.


CLASS z2ui5_cl_smp_app_421 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_tab = VALUE #(
        ( index = 0 title = `entry 01` value = `red`    info = `completed` description = `this is a description` checkbox = abap_true )
        ( index = 1 title = `entry 02` value = `blue`   info = `completed` description = `this is a description` checkbox = abap_true )
        ( index = 2 title = `entry 03` value = `green`  info = `completed` description = `this is a description` checkbox = abap_true )
        ( index = 3 title = `entry 04` value = `orange` info = `completed` description = ``                     checkbox = abap_true )
        ( index = 4 title = `entry 05` value = `grey`   info = `completed` description = `this is a description` checkbox = abap_true )
        ( index = 5 title = ``         value = ``       info = ``          description = ``                     checkbox = abap_false ) ).

    default_focus( ).
    view_display( ).
    focus( ).

  ENDMETHOD.


  METHOD on_event.

    CASE client->get_event( ).
      WHEN `FOCUS`.
        focus( ).
      WHEN `NEXT`.
        read_focus( ).
        next_focus( ).
        focus( ).
      WHEN `RESET`.
        default_focus( ).
        focus( ).
    ENDCASE.

  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` ).

    DATA(page) = view->ele( `Shell`
        )->ele( `Page`
            )->a( n = `title`          v = `abap2UI5 - Focus - Focus a Table Cell by Column and Row`
            )->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 = `Set the keyboard focus to any editable table cell from the backend - type a column id ` &&
                   `(Title, Color, Info, Checkbox or Description) and a row index, then press Set Focus, or ` &&
                   `use Next / Reset. No JavaScript is shipped with the view: every cell has a stable control ` &&
                   `id (<column>_<row>) that the set_focus follow-up action targets, and the framework reports ` &&
                   `the currently focused cell back to the backend in s_focus.`
        )->a( n = `type`     v = `Information`
        )->a( n = `showIcon` b = abap_true
        )->a( n = `class`    v = `sapUiSmallMargin` ).

    DATA(tab) = page->ele( `Table`
        )->ele( `headerToolbar`
            )->ele( `OverflowToolbar`
                )->tag( `Title`
                    )->a( n = `text` v = client->_bind( focusid )
                )->tag( `ToolbarSpacer`
                )->tag( `Label`
                    )->a( n = `text` v = `Column Id`
                )->tag( `Input`
                    )->a( n = `placeholder` v = `Column`
                    )->a( n = `value`       v = client->_bind( focuscolumn )
                    )->a( n = `submit`      v = client->_event( `FOCUS` )
                    )->a( n = `width`       v = `8rem`
                )->tag( `Label`
                    )->a( n = `text` v = `Row Index`
                )->tag( `Input`
                    )->a( n = `placeholder` v = `Row`
                    )->a( n = `type`        v = `Number`
                    )->a( n = `value`       v = client->_bind( focusrow )
                    )->a( n = `submit`      v = client->_event( `FOCUS` )
                    )->a( n = `width`       v = `6rem`
                )->tag( `Button`
                    )->a( n = `press` v = client->_event( `FOCUS` )
                    )->a( n = `text`  v = `Set Focus`
                )->tag( `Button`
                    )->a( n = `press` v = client->_event( `NEXT` )
                    )->a( n = `text`  v = `Next Focus`
                )->tag( `Button`
                    )->a( n = `press` v = client->_event( `RESET` )
                    )->a( n = `text`  v = `Reset Focus`
            )->end(
        )->end( ).

    tab->ele( `columns`
        )->ele( `Column`
            )->tag( `Text`
                )->a( n = `text` v = `Index`
        )->end(
        )->ele( `Column`
            )->tag( `Text`
                )->a( n = `text` v = `Title`
        )->end(
        )->ele( `Column`
            )->tag( `Text`
                )->a( n = `text` v = `Color`
        )->end(
        )->ele( `Column`
            )->tag( `Text`
                )->a( n = `text` v = `Info`
        )->end(
        )->ele( `Column`
            )->tag( `Text`
                )->a( n = `text` v = `Checkbox`
        )->end(
        )->ele( `Column`
            )->tag( `Text`
                )->a( n = `text` v = `Description` ).

    " Build the rows explicitly (no aggregation binding): only then does every
    " cell keep the stable control id <column>_<row> that set_focus can target.
    " A bound template would clone the cells under randomly generated ids.
    " Each cell binds its own row component (tab / tab_index), so the model
    " keeps the table's array shape while the view addresses single rows.
    DATA(items) = tab->ele( `items` ).

    LOOP AT t_tab REFERENCE INTO DATA(row).

      DATA(index) = sy-tabix.
      DATA(i)     = index - 1.

      items->ele( `ColumnListItem`
          )->ele( `cells`
              )->tag( `Text`
                  )->a( n = `text` t = |{ row->index }|
              )->tag( `Input`
                  )->a( n = `id`     t = |{ cs_column-title }_{ i }|
                  )->a( n = `value`  v = client->_bind( val = row->title tab = t_tab tab_index = index )
                  )->a( n = `submit` v = client->_event( `NEXT` )
              )->tag( `Input`
                  )->a( n = `id`     t = |{ cs_column-color }_{ i }|
                  )->a( n = `value`  v = client->_bind( val = row->value tab = t_tab tab_index = index )
                  )->a( n = `submit` v = client->_event( `NEXT` )
              )->tag( `Input`
                  )->a( n = `id`     t = |{ cs_column-info }_{ i }|
                  )->a( n = `value`  v = client->_bind( val = row->info tab = t_tab tab_index = index )
                  )->a( n = `submit` v = client->_event( `NEXT` )
              )->tag( `CheckBox`
                  )->a( n = `id`       t = |{ cs_column-checkbox }_{ i }|
                  )->a( n = `selected` v = client->_bind( val = row->checkbox tab = t_tab tab_index = index )
              )->tag( `Input`
                  )->a( n = `id`     t = |{ cs_column-description }_{ i }|
                  )->a( n = `value`  v = client->_bind( val = row->description tab = t_tab tab_index = index )
                  )->a( n = `submit` v = client->_event( `NEXT` ) ).

    ENDLOOP.

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

  ENDMETHOD.


  METHOD focus.

    focusid = |{ focuscolumn }_{ focusrow }|.

    client->follow_up_action(
        val   = z2ui5_if_client=>cs_event-set_focus
        t_arg = VALUE #( ( focusid ) ) ).

  ENDMETHOD.


  METHOD read_focus.

    SPLIT client->get( )-s_focus-id AT `_` INTO DATA(col) DATA(row).

    IF row IS NOT INITIAL
        AND row CO `0123456789`
        AND ( col = cs_column-title
           OR col = cs_column-color
           OR col = cs_column-info
           OR col = cs_column-checkbox
           OR col = cs_column-description ).

      focuscolumn = col.
      focusrow    = row.
    ENDIF.

  ENDMETHOD.


  METHOD next_focus.

    focuscolumn = SWITCH #( focuscolumn
                            WHEN cs_column-title    THEN cs_column-color
                            WHEN cs_column-color    THEN cs_column-info
                            WHEN cs_column-info     THEN cs_column-checkbox
                            WHEN cs_column-checkbox THEN cs_column-description
                            ELSE cs_column-title ).

    IF focuscolumn = cs_column-title.

      " focusrow is what the user typed into the Row Index input - a Number
      " input still lets 99999999999 through, which does not fit TYPE i
      TRY.
          DATA(nextrow) = CONV i( focusrow ) + 1.
        CATCH cx_sy_conversion_error cx_sy_arithmetic_error.
          nextrow = 0.
      ENDTRY.
      IF line_exists( t_tab[ nextrow + 1 ] ).
        focusrow = |{ nextrow }|.
      ELSE.
        focusrow = `0`.
      ENDIF.
    ENDIF.

  ENDMETHOD.


  METHOD default_focus.

    focuscolumn = cs_column-title.
    focusrow    = `0`.

  ENDMETHOD.

ENDCLASS.