The Tables documentation describes the general table technique of the S10 framework. In this tutorial we want to get to know the technique by means of an example: Damaged stock items are to be entered in a table. The input mask looks as follows:  

To enter the material number, a barcode or QR code can be photographed in addition to the keyboard input. The columns "Quantity" (number of damaged items) and "Damage type" (dropdown list) are entered manually. The material short text, stockkeeping unit and warehouse stock are read from the SAP system.

The application can be operated on the smartphone in landscape format as shown above or also in portrait format. In portrait mode, the display columns "Material short text", "Stock" and "ME" (unit of measure) are hidden, but data entry is still possible without any problems:

If additional information is to be displayed or entered, such as a batch or serial number or the exact storage location, the table can be supplemented with a multi-line output or a separately callable detail screen per line. We limit ourselves here to the single-line view.

We start the development by defining a local ABAP class to describe the table row. In general, the table representation in the S10 framework is based on assigning an ABAP object to each table row. This has the advantage that the techniques of the "build" and "validate" methods (tutorials 2 and 4) are now available per table row, to which we will use in a moment.

We can either enter the local class for the table rows by hand or use the class generator from the S10 utilities. The class looks like this:

class mdr definition inheriting from /s10/any.

  public section.

    data:
      matnr type mard-matnr,  " Material number
      werks type mard-werks,  " Plant
      lgort type mard-lgort,  " Storage location
      speme type mard-speme,  " Number of damaged items
      meins type mara-meins,  " Unit
      labst type mard-labst,  " Stock
      ecode type string.      " Damage code

*  Assign units
    constants:
      unit_speme type string value 'meins',
      unit_labst type string value 'meins'.
endclass.

The class name, here "mdr" for "Material Damage Report" is freely selectable. The constants "unit_speme" and "unit_labst" ensure that the output is made with the appropriate number of decimal places for the unit of measure.

Compared to the displayed table, we have

We can output the material text directly in HTML using the notation "matnr@text", see  s10standardname, so we do not need a separate class attribute for this.

The information "Plant" and "Storage location" are intended for database access to the storage location data of the material (SAP table MARD). Alternatively, we could also place a reference to the header object in each table line and access the plant and storage location via this.

The stockkeeping unit and the current stock level are read from SAP tables. For this purpose, we implement two "build" methods as described in Tutorial 2, which we give the names "build_meins" and "build_labst":

   methods:
      build_meins
        importing
          matnr type mard-matnr
        exporting
          meins type mara-meins,

      build_labst
        importing
          matnr type mard-matnr
        exporting
          labst type mard-labst.
...

class mdr implementation.

  method build_meins.
    clear meins.
    if matnr is initial.
      return.
    endif.

    select single meins from mara into meins
      where matnr = matnr.

  endmethod.


  method build_labst.
    clear labst.
    if matnr is initial.
      return.
    endif.

    select single labst from mard into labst
      where matnr = matnr
      and   werks = werks
      and  lgort = lgort.

  endmethod.

The two build methods are automatically called by the S10 framework per table row. This ensures that the unit of measure and the stock level are each correctly obtained and displayed for the material number entered.

Each material number entered is to be checked for validity, which we achieve by implementing the following method "validate_matnr" (see Tutorial 4):

  methods:
      validate_matnr
        importing
          matnr type mard-matnr.
...

class mdr implementation.

  method validate_matnr.
    data: mymatnr type mara-matnr.
    select single matnr from mard into mymatnr
       where matnr = matnr
       and   werks = werks
       and   lgort = lgort.
    if sy-subrc ne 0.
      s10errormessage( |Material number | && s10getuservalue( 'matnr' ) && 
                | does not exist in this plant/storage location| ).
    endif.

  endmethod.

In the error message we work with the S10 method "s10getuservalue" to display the material number correctly formatted, for example "98" instead of the internal format "00000000000098". Positioning the message on the correct line and setting the input focus on the invalid material number is done automatically by the S10 framework, which knows the connection between the table line and the mdr object:

Now for the definition of the table in ABAP. It is done in a separate class, which we call "mdr_manager"; the name can be chosen arbitrarily.

class mdr_manager definition inheriting from /s10/any.

  public section.

    data:
      werks  type mard-werks,
      lgort  type mard-lgort,
 
       tabmdr type table of ref to mdr.

    methods:
      start,
      addrow,
      delrow,
       check, 
      save.

endclass.


The actual application consists of the methods start, addrow, delrow, check and save.
The method "start" is called from the logon method.  It reads the SAP user parameters for plant and location, initializes the entry table with five empty rows and calls the "create" screen:
  method start.

* user parameters
    get parameter:
     id 'WRK' field werks,
     id 'LAG' field lgort.

* add 5 empty rows
    do 5 times.
      addrow( ).
    enddo.

* display main screen
    s10nextscreen( 'create').
  endmethod.



With "addrow" an empty row is added to the entry table. We can call the method internally as in "start" above, but the user can also add a blank row by clicking on the "New row" button.


* add row in item table
  method addrow.
    data: mymdr type ref to mdr.
    create object mymdr.

* set general key values
    mymdr->werks =  werks.
    mymdr->lgort =  lgort.

    append mymdr to tabmdr.
  endmethod.

 

"delrow" is called by the user by clicking on the icon on the right side of the table row. In the method, to delete the correct row, we need to know in which row the user clicked. This can be done by calling s10contextinfo( ):

* delete row in item table
  method delrow.
    delete tabmdr index s10contextinfo( )->rownumber.
  endmethod.

At "check" we check for all occupied rows of the table whether quantity and damage type have been entered:

 method check.
    loop at tabmdr assigning field-symbol(<mdr>)
      where table_line->matnr is not initial.

      if <mdr>->speme le 0.
        <mdr>->s10setfocus( 'speme' ).
        s10errormessage( 'Please enter the quantity' ).
      endif.

      if <mdr>->ecode is initial.
        <mdr>->s10setfocus( 'ecode' ).
        s10errormessage( 'Please select the type of damage' ).
      endif.

    endloop.

    s10infomessage( 'Data checked' ).
  endmethod.

Two details are interesting here:

 

The "save" method is not detailed for the tutorial, as we are concerned with the dialog technique of the entry table at the moment:

* save data
  method save.

* check data first
    check( ).

    s10infomessage( 'Save: to be implemented' ).
  endmethod.

Conceivable here is the call of the SAP-BAPI "BAPI_GOODSMVT_CREATE" to create a material document.

The HTML page "create" contains the header with title, the pushbuttons "Check", "Save" and "Logoff", the plant and the storage location, then the entry table and the "New row" button. Since creating the HTML file involves some typing, you can use the S10 generation tool to do this and have it generate a reasonably suitable table as a starting point. Almost all HTML options are HTML5 standard. The S10 framework only interprets the specific CSS classes of the elements to connect to the ABAP objects.

   1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta name="viewport" content="width=400">
    <link rel='stylesheet' type='text/css' href='../../../style/s10.style.css'>
    <link rel='stylesheet' type='text/css' href='../../../style/custom.style.css'>
    <script src='../../synactiveS10/synactiveS10.java.js'></script>
    <title>Stock material: Record damage</title>
</head>

<body style="width: 100%; margin: 0px; padding: 0px;"
    onload='init();' class="colorscheme9">

    <div class="headerarea"
        style="width: 100%; font-size: 20px; font-weight: bold; padding: 10px;">
        Stock material: Record damage
    </div>

    <div class="toolbar">

        <button type="button" class="toolbarbutton" onclick="S10Apply('check');">
            Check
        </button>

        <button type="button" class="toolbarbutton" onclick="S10Apply('save');">
            Save
        </button>

        <button type="button" class="toolbarbutton" style="float: right;"
            onclick="S10Logoff();">
            Logoff
        </button>

    </div>


    <!-- header fields -->
    <div style="background-color: lightgray;">

        <div class="infoblock" style="width: 200px; height: 50px;">
            <label class="label output" for="werks" name="werks"></label>
            <br>
            <span class='output' name="werks"></span>
            <span class='output' name='werks@text'></span>
        </div>


        <div class="infoblock" style="width: 200px; height: 50px;">
            <label class="label output" for="lgort" name="lgort"></label>
            <br>
            <span class='output' name="lgort"></span>
            <span class='output' name='lgort@text'></span>
        </div>
    </div>



    <!-- column headers -->
    <div class="colheaders nosort">

        <!-- Material -->
        <div class='colhead output ' style="width: 100px;" name="matnr"></div>
        <div class='colhead output landscape'
            style="width: 180px;" name="matnr@text">
        </div>

        <!-- Quantity -->
        <div class='colhead' style="width: 60px;" name="speme">
            Quantity
        </div>

        <!-- Damage code-->
        <div class='colhead' style="width: 170px;" name="ecode">
            Damage code
        </div>

        <!-- Stock -->
        <div class='colhead landscape'
            style="width: 60px;" name="labst">
            Stock
        </div>

        <!-- Unit -->
        <div class='colhead  landscape' style="width: 60px;" name="meins">
            Unit
        </div>


    </div>

    <!-- entry table -->
    <form class='table' name='tabmdr'>

        <div class="tablerow">
            <input type="text" class="inputcell valuehelp" name="matnr"
                style="float: left; width: 100px;">

            <div class='outputcelldiv landscape'
                style="width: 180px; font-size: 13px; font-weight: normal;"
                name="matnr@text">
            </div>

            <input type="text" class="inputcell" name="speme"
                style="float: left; width: 60px;">

            <select class="inputcellselect" name="ecode"
                style="float: left; width: 170px;">
                <optgroup label="Water damage">
                    <option value="W01">Water damage</option>
                    <option value="W02">Water traces</option>
                </optgroup>
                <optgroup label="Packing">
                    <option value="V01">Packing damaged</option>
                    <option value="V02">Packing dirty</option>
                    <option value="V03">Packing missing</option>
                    <option value="V04">Packing empty</option>
                </optgroup>
                <optgroup label="Others">
                    <option value="S01">Other damage</option>
                </optgroup>
            </select>


            <div class='outputcelldiv landscape'
                style="width: 60px;" name="labst">
            </div>

            <div class='outputcelldiv landscape'
                style="width: 60px;" name="meins@text">
            </div>

            <!-- delete row -->
            <img style="width: 16px; height: 16px; margin-left: 10px;"
                src="../../../icons/delete_64x64.png"
                onclick="S10Apply('delrow')" />

        </div>

    </form>

    <button type="button" class="button-small"
        style='margin: 4px; background-color: #937a7a; color: white;'
        onclick="S10Apply('addrow'); ">
       Add row
    </button>

</body>
</html>
The entry table starts in row 59 with the column headings.

Row 59:    <div class="colheaders nosort"

The "nosort" option ensures that the re-sorting of table rows, which is normally possible by clicking on a column heading, is omitted. With entry tables, it usually doesn't make much sense to offer re-sorting, and the arrow for the sort order uses up some space in the heading.

Row 63:  <div class='colhead output ' style="width: 100px;" name="matnr"></div>

For the CSS class "colhead output" the S10 framework takes the heading from the SAP repository according to the class attribute specified with name= .

Row 64   <div class='colhead output landscape'
                    style="width: 180px;" name="matnr@text">
               </div>

With "landscape" this column is not displayed in portrait format

Row 93   <form class='table' name='tabmdr'>

After the headings now the actual table, which is introduced by a <form> tag with class='table'. With name=  we specify the ABAP name of the table, here "tabmdr". All elements in the following table row are repeated per table row and filled with the values of the table row object.

From line 96 the individual columns of the table. It is important here that the width is exactly the same as the width of the respective column header. For portrait and landscape format you can choose different widths, or suppress columns completely. This is described in the Responsive Webdesign" tutorial.

Row 96 <input type="text" class="inputcell valuehelp" name="matnr"
                style="float: left; width: 100px;">

The column "matnr" is ready for input and allows the selection via a search help, see the instructions "Search help".

Row 99  <div class='outputcelldiv landscape'
                style="width: 180px; font-size: 13px; font-weight: normal;"
                name="matnr@text">
            </div>

The short text for the entered material number is displayed by name="matnr@text" in this column. In portrait format the column is suppressed because of the CSS class "landscape".

Row 107 <select class="inputcellselect" name="ecode"
                style="float: left; width: 170px;">
                <optgroup label="Water damage">
                    <option value="W01">Water damage</option>
                    <option value="W02">Water traces</option>
                </optgroup>
                <optgroup label="Packing">
                    <option value="V01">Packing damaged</option>
                    <option value="V02">Packing dirty</option>
                    <option value="V03">Packing missing</option>
                    <option value="V04">Packing empty</option>
                </optgroup>
                <optgroup label="Others">
                    <option value="S01">Other damage</option>
                </optgroup>
            </select>

Input via a 2-level dropdown list hard-coded in the HTML page. Alternatively, you can also provide dropdown lists in ABAP or take the S10 repository as a basis, see the "Dropdown lists" tutorial. .

 

Row 129  <div class='outputcelldiv landscape'
                   style="width: 60px;" name="meins@text">
               </div>

For the unit of measure, we output the language-dependent label provided by name="meins.text" by the S10 framework.

Row 133  <!-- delete row -->
               <img style="width: 16px; height: 16px; margin-left: 10px;"
                    src="../../../icons/delete_64x64.png"
                   onclick="S10Apply('delrow')" />

Output of an icon for deleting the line. Via S10Apply( "delrow" ) the ABAP method "delrow" is called.

 

Row 142  <button type="button" class="button-small"
                    style='margin: 4px; background-color: #937a7a; color: white;'
                   onclick="S10Apply('addrow'); ">
                     Add row
              </button>

The "Add row" button that appears following the entry table. Alternatively, we can add an icon "Insert new row" in each table row and then insert a new row before the row in question. Since the order of the captured materials is not important in this application, we have limited ourselves to the space-saving variant of always adding rows at the end.