Recursive function realizes multi-level linkage search help in provinces and cities

1. Demand background

When there are mutually hierarchical fields in the program and you need to use search help, you can do so by calling search help multiple times. For example, in the program, you need to fill in the third-level address of the province, city, and city

2. Implementation method

2.1. Straight talk

Program search help is usually implemented using F4IF_INT_TABLE_VALUE_REQUEST. Multi-level search help can be achieved simply by calling the F4 function multiple times.

Click the province field to pop up the province search help. According to the selected province, query the corresponding city, and the city search help pops up. According to the selected city, query the corresponding district and county, and the district and county search help pops up. After selection, update to the ALV report.

In the same way, if you click on the city, the search help for the city and district will pop up; if you click on the district, only the search help for the district will pop up.

as the picture shows:

Click on the provincial field code example. You need to write F4 three times:

"--------------------@General Bin--------------------
READ TABLE gt_cjso_alv ASSIGNING <fs_cjso_alv> INDEX pv_row_no-row_id.
  "Get the corresponding data set
  CASE lv_fieldname1.
    WHEN 'ZZDEADREGION'."Shipping Address-Province
      SELECT
        land1,
        bland AS zzdeadregion,
        bezei
      FROM t005u
      INTO TABLE @DATA(lt_t005u)
      WHERE land1 EQ 'CN'
        AND spras EQ @sy-langu.

      ASSIGN lt_t005u TO <lt_f4table>.

      REFRESH gt_return.
      CALL FUNCTION 'F4IF_INT_TABLE_VALUE_REQUEST'
        EXPORTING
          retfield = lv_fieldname1
          dynpprog=sy-repid
          dynpnr = sy-dynnr
          dynprofield=lv_fieldname2
          value_org = 'S'
          display = 'F'
        TABLES
          value_tab = <lt_f4table>
          return_tab = gt_return
        EXCEPTIONS
          parameter_error = 1
          no_values_found = 2
          OTHERS = 3.

      IF sy-subrc = 0.
        READ TABLE gt_return INTO gs_return INDEX 1.
        IF sy-subrc = 0.
          ASSIGN COMPONENT lv_fieldname1 OF STRUCTURE <fs_cjso_alv> TO <lv_field>.
          <lv_field> = gs_return-fieldval.

          SELECT
            country,
            region,
            city_code AS zzdeadcity,
            city_name
          FROM v_adrcity
          INTO TABLE @DATA(lt_v_adrcity)
          WHERE country EQ 'CN'
            AND langu EQ @sy-langu
            AND region EQ @<fs_cjso_alv>-zzdeadregion.
          ASSIGN lt_v_adrcity TO <lt_f4table>.

          lv_fieldname = 'ZZDEADCITY'.
          lv_dynprofld = 'ZZDEADCITY'.
          REFRESH gt_return.
          CALL FUNCTION 'F4IF_INT_TABLE_VALUE_REQUEST'
            EXPORTING
              retfield = lv_fieldname
              dynpprog=sy-repid
              dynpnr = sy-dynnr
              dynprofield = lv_dynprofld
              value_org = 'S'
              display = 'F'
            TABLES
              value_tab = <lt_f4table>
              return_tab = gt_return
            EXCEPTIONS
              parameter_error = 1
              no_values_found = 2
              OTHERS = 3.

          IF sy-subrc = 0.
            READ TABLE gt_return INTO gs_return INDEX 1.
            IF sy-subrc = 0.
              ASSIGN COMPONENT 'ZZDEADCITY' OF STRUCTURE <fs_cjso_alv> TO <lv_field>.
              <lv_field> = gs_return-fieldval.

              lv_zzdeadcity = |{ <fs_cjso_alv>-zzdeadcity ALPHA = IN }|.
              SELECT
                country,
                city_code,
                city_name,
                strt_code AS zzdeadstreet,
                street
              FROM m_strta
              INTO TABLE @DATA(lt_m_strta)
              WHERE country EQ 'CN'
                AND langu EQ @sy-langu
                AND region EQ @<fs_cjso_alv>-zzdeadregion
                AND city_code EQ @lv_zzdeadcity.

              ASSIGN lt_m_strta TO <lt_f4table>.

              lv_fieldname = 'ZZDEADSTREET'.
              lv_dynprofld = 'ZZDEADSTREET'.
              REFRESH gt_return.
              CALL FUNCTION 'F4IF_INT_TABLE_VALUE_REQUEST'
                EXPORTING
                  retfield = lv_fieldname
                  dynpprog=sy-repid
                  dynpnr = sy-dynnr
                  dynprofield = lv_dynprofld
                  value_org = 'S'
                  display = 'F'
                TABLES
                  value_tab = <lt_f4table>
                  return_tab = gt_return
                EXCEPTIONS
                  parameter_error = 1
                  no_values_found = 2
                  OTHERS = 3.

              IF sy-subrc = 0.
                READ TABLE gt_return INTO gs_return INDEX 1.
                IF sy-subrc = 0.
                  ASSIGN COMPONENT 'ZZDEADSTREET' OF STRUCTURE <fs_cjso_alv> TO <lv_field>.
                  <lv_field> = gs_return-fieldval.
                ENDIF.
              ENDIF.
            ENDIF.
          ENDIF.
        ENDIF.
      ENDIF.
    WHEN 'ZZDEADCITY'."Shipping address - City
    …
    WHEN 'ZZDEADSTREET'."Shipping address-district and county
    …
    WHEN OTHERS.
  ENDCASE.

  PERFORM frm_refresh_alv USING g_grid_9001.
"--------------------@General Bin--------------------

2.2. Simple recursion

Although the above method can be implemented, the third-level address requires writing repetitive code five times. If you encounter search help with more levels, you need to write N(N + 1)/2 times of code, so we can use a recursive function. , repeatedly calling the search help to make the code more concise.

Here is a little explanation, what is a recursive function?

Recursive function: A function that calls itself inside a function is called a recursive function. Recursive functions can transform complex problems into simpler sub-problems to solve. A classic example of a recursive function is the factorial function, where n! is equal to n times (n-1)!. The factorial is calculated inside the function by calling itself.

Extract common code and write recursive functions

"--------------------@General Bin--------------------
FORM frm_callback_f4 USING pv_level pv_fieldname CHANGING ps_alv TYPE ty_cjso_alv.

* DATA:lv_zzdeadcity TYPE vbak-zzdeadcity. "Shipping address-city

  DATA:lt_return TYPE STANDARD TABLE OF ddshretval,
       ls_return TYPE ddshretval.

  DATA:lv_next_field TYPE dfies-fieldname,
       lv_next_level TYPE int4,
       lv_fieldname TYPE dfies-fieldname,
       lv_dynprofld TYPE help_info-dynprofld.

  FIELD-SYMBOLS:<lv_field>.

  lv_fieldname = pv_fieldname.
  lv_dynprofld = pv_fieldname.
  CONDENSE:lv_fieldname,lv_dynprofld NO-GAPS.
  lv_next_level = pv_level.
  "According to the level, query the data set of the current level and assign the field name of the next level.
  CASE lv_next_level.
    WHEN 1."Level 1 Province
      SELECT
        land1,
        bland AS zzdeadregion,
        bezei
      FROM t005u
      INTO TABLE @DATA(lt_t005u)
      WHERE land1 EQ 'CN'
        AND spras EQ @sy-langu.

      UNASSIGN <gt_f4table>.
      ASSIGN lt_t005u TO <gt_f4table>.
      lv_next_field = 'ZZDEADCITY'.
    WHEN 2."Layer 2 City
      SELECT
        country,
        region,
        city_code AS zzdeadcity,
        city_name
      FROM v_adrcity
      INTO TABLE @DATA(lt_v_adrcity)
      WHERE country EQ 'CN'
        AND langu EQ @sy-langu
        AND region EQ @ps_alv-zzdeadregion.

      UNASSIGN <gt_f4table>.
      ASSIGN lt_v_adrcity TO <gt_f4table>.
      lv_next_field = 'ZZDEADSTREET'.
    WHEN 3."Third layer area
      DATA(lv_zzdeadcity) = |{ ps_alv-zzdeadcity ALPHA = IN }|.
      SELECT
        country,
        city_code,
        city_name,
        strt_code AS zzdeadstreet,
        street
      FROM m_strta
      INTO TABLE @DATA(lt_m_strta)
      WHERE country EQ 'CN'
        AND langu EQ @sy-langu
        AND region EQ @ps_alv-zzdeadregion
        AND city_code EQ @lv_zzdeadcity.

      UNASSIGN <gt_f4table>.
      ASSIGN lt_m_strta TO <gt_f4table>.

    WHEN OTHERS.
  ENDCASE.

  "Calling the search help function
  CALL FUNCTION 'F4IF_INT_TABLE_VALUE_REQUEST'
    EXPORTING
      retfield = lv_fieldname
      dynpprog=sy-repid
      dynpnr = sy-dynnr
      dynprofield = lv_dynprofld
      value_org = 'S'
      display = 'F'
    TABLES
      value_tab = <gt_f4table>
      return_tab = lt_return
    EXCEPTIONS
      parameter_error = 1
      no_values_found = 2
      OTHERS = 3.

  IF sy-subrc = 0.
    READ TABLE lt_return INTO ls_return INDEX 1.
    IF sy-subrc = 0.
      ASSIGN COMPONENT lv_fieldname OF STRUCTURE ps_alv TO <lv_field>.
      <lv_field> = ls_return-fieldval.
      IF lv_next_level < 3."Exit after third level query
        lv_next_level = lv_next_level + 1.
        "Call the function itself and start the next cycle
        PERFORM frm_callback_f4 USING lv_next_level lv_next_field CHANGING ps_alv.
      ENDIF.
    ENDIF.
  ENDIF.
ENDFORM.
"--------------------@General Bin--------------------

Called when a field is clicked, through the assignment level, multi-level search help can be called cyclically, and the code is simpler and more reusable.

"--------------------@General Bin--------------------
FORM frm_alv_on_f4_9001 USING pv_fieldname pv_fieldvalue pv_row_no TYPE lvc_s_roid
      pv_event_data TYPE REF TO cl_alv_event_data
      pv_display.


  READ TABLE gt_cjso_alv ASSIGNING <fs_cjso_alv> INDEX pv_row_no-row_id.
  "Get the corresponding data set
  CASE pv_fieldname.
    WHEN 'ZZDEADREGION'."Shipping Address-Province
      PERFORM frm_callback_f4 USING 1 'ZZDEADREGION' CHANGING <fs_cjso_alv>.
    WHEN 'ZZDEADCITY'."Shipping address - City
      PERFORM frm_callback_f4 USING 2 'ZZDEADCITY' CHANGING <fs_cjso_alv>.
    WHEN 'ZZDEADSTREET'."Shipping address-district and county
      PERFORM frm_callback_f4 USING 3 'ZZDEADSTREET' CHANGING <fs_cjso_alv>.
    WHEN OTHERS.
  ENDCASE.

  PERFORM frm_refresh_alv USING g_grid_9001.

ENDFORM.
"--------------------@General Bin--------------------

Regular updates, welcome to follow