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.
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.
* 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:
In the where condition of the loop statement, we can access the line object in ABAP through "table_line":
loop at tabmdr assigning field-symbol(<mdr>) where table_line->matnr is not initial.
The call to s10setfocus is made via the row object:
<mdr>->s10setfocus( 'speme' ).
If instead we just call s10setfocus( 'speme' ), the S10 framework tries to find an input field "speme" of the current object of the class "mdr_manager", which does not exist. The error message then appears at the triggering "check" button, making it difficult for the user to associate it with the missing quantity input:
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> |
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.