|
| 1 | +--- |
| 2 | +title: HTML Tables |
| 3 | +category: ui |
| 4 | +order: 70 |
| 5 | +--- |
| 6 | + |
| 7 | +_The html-table component is still experimental and may be subject to change. Cross-check with the actual code in the codebase (e.g., `zcl_abapgit_gui_page_codi_base` and its subclasses)._ |
| 8 | + |
| 9 | +## General concept and features |
| 10 | + |
| 11 | +- Create an instance of `zcl_abapgit_html_table` |
| 12 | +- Define column structure with `define_column` |
| 13 | +- Render the component, supplying the data and the _renderer_ |
| 14 | +- While rendering, the html table instance will call the appropriate _renderer_ methods for each row and cell, yet hiding all routine table construction inside |
| 15 | + |
| 16 | +### Features |
| 17 | + |
| 18 | +- styling individual cells and rows |
| 19 | +- auto-marking columns with `column_id` data attribute |
| 20 | +- sorting support |
| 21 | + |
| 22 | +## Simplest table example |
| 23 | + |
| 24 | +Suppose you have a table of this structure: |
| 25 | + |
| 26 | +```abap |
| 27 | + begin of ty_data, |
| 28 | + id type i, |
| 29 | + name type string, |
| 30 | + city type string, |
| 31 | + end of ty_data, |
| 32 | +``` |
| 33 | + |
| 34 | +Define the table structure: |
| 35 | + |
| 36 | +- `column_id` is the id to identify the column in further callbacks, in css styles, and also to be used as _default_ field name to extract the value from a table record. |
| 37 | +- `column_title` is a visual name of the html table column. |
| 38 | + |
| 39 | +```abap |
| 40 | + li_table = zcl_abapgit_html_table=>create( |
| 41 | + )->define_column( |
| 42 | + iv_column_id = 'id' |
| 43 | + iv_column_title = 'ID' |
| 44 | + )->define_column( |
| 45 | + iv_column_id = 'name' |
| 46 | + iv_column_title = 'Name' |
| 47 | + )->define_column( |
| 48 | + iv_column_id = 'city' |
| 49 | + iv_column_title = 'Location' ). |
| 50 | +``` |
| 51 | + |
| 52 | +Implement rendering methods `render_cell` and, optionally, `get_row_attrs`. This can be done directly in a calling component (typically), or in separate local classes (e.g. if there are several tables in the page). |
| 53 | + |
| 54 | +```abap |
| 55 | + method zif_abapgit_html_table~render_cell. |
| 56 | + " This is the simplest form of rendering |
| 57 | + " `iv_value` contains content of `column_id` field of table record |
| 58 | + " `content` attribute of the returning structure |
| 59 | + " is the text value to be rendered in the cell |
| 60 | + rs_render-content = |{ iv_value }|. |
| 61 | + endmethod. |
| 62 | +``` |
| 63 | + |
| 64 | +Finally, call the table `render` method to produce html. Pass the data table to be rendered and the _renderer_ instance. |
| 65 | + |
| 66 | +```abap |
| 67 | + ri_html->add( li_table->render( |
| 68 | + ii_renderer = me |
| 69 | + it_data = value ty_data_tab( |
| 70 | + ( id = 1 name = 'John' city = 'London' ) |
| 71 | + ( id = 2 name = 'Pierre' city = 'Paris' ) |
| 72 | + ) ) ). |
| 73 | +``` |
| 74 | + |
| 75 | + |
| 76 | + |
| 77 | +## CSS styles |
| 78 | + |
| 79 | +There are several options to styling your table: |
| 80 | + |
| 81 | +- First, you can pass the element id, and css class of the table itself to the `render` method. |
| 82 | +- Passing `iv_wrap_in_div` parameter will wrap your table in another `div` with the given css class name, primarily for visual styling purposes (e.g. see padded borders and rounded corners in the screenshot below). |
| 83 | + |
| 84 | +There are default CSS styles in abapGit to reuse if you don't want to bother with any specific styling - `default-table` and `default-table-container`, respectively, for the wrapping `div`. |
| 85 | + |
| 86 | +```abap |
| 87 | + ri_html->add( li_table->render( |
| 88 | + iv_wrap_in_div = 'default-table-container' |
| 89 | + iv_css_class = 'default-table' |
| 90 | + iv_id = 'my-addr-tab' |
| 91 | + it_data = ... ). |
| 92 | +``` |
| 93 | + |
| 94 | + |
| 95 | + |
| 96 | +Rendering methods `render_cell` and `get_row_attrs` allow specifying css classes for individual cells and rows. |
| 97 | + |
| 98 | +```abap |
| 99 | + method zif_abapgit_html_table~get_row_attrs. |
| 100 | + rs_attrs-css_class = 'my-tab-row'. |
| 101 | + endmethod. |
| 102 | +
|
| 103 | + method zif_abapgit_html_table~render_cell. |
| 104 | + " ... |
| 105 | + rs_render-css_class = 'my-cell'. |
| 106 | + endmethod. |
| 107 | +``` |
| 108 | + |
| 109 | +Finally, passing the `iv_with_cids = abap_true` param to `render` will auto-mark cells with data attribute `data-cid` with respecting `column_id`. This enables easy indirect CSS styling or reassembling memory representation of the table in Javascript. |
| 110 | + |
| 111 | +```abap |
| 112 | + ri_html->add( li_table->render( |
| 113 | + iv_with_cids = abap_true |
| 114 | + ... ). |
| 115 | +``` |
| 116 | + |
| 117 | +`get_row_attrs` also allows passing a custom data attribute. Similarly, this can be used in CSS styling or JS. |
| 118 | + |
| 119 | +```abap |
| 120 | + method zif_abapgit_html_table~get_row_attrs. |
| 121 | + rs_attrs-data-name = 'status'. |
| 122 | + rs_attrs-data-value = 'error'. |
| 123 | + endmethod. |
| 124 | +``` |
| 125 | + |
| 126 | +Resulting HTML: |
| 127 | + |
| 128 | +```html |
| 129 | + <table id="my-addr-tab" class="default-table"> |
| 130 | + <thead> |
| 131 | + <tr> |
| 132 | + <th data-cid="id">ID</th> |
| 133 | + <th data-cid="name">Name</th> |
| 134 | + <th data-cid="city">Location</th> |
| 135 | + </tr> |
| 136 | + </thead> |
| 137 | + <tbody> |
| 138 | + <tr data-status="error"> |
| 139 | + <td data-cid="id">1</td> |
| 140 | + <td data-cid="name">John</td> |
| 141 | + <td data-cid="city">London</td> |
| 142 | + </tr> |
| 143 | + ... |
| 144 | + </tbody> |
| 145 | + </table> |
| 146 | + |
| 147 | +``` |
| 148 | + |
| 149 | +CSS example: |
| 150 | + |
| 151 | +```css |
| 152 | +table td[data-cid="id"] { font-weight: bold; } |
| 153 | +table tr[data-kind="error"] { background-color: red; } |
| 154 | +``` |
| 155 | + |
| 156 | +## Cell rendering |
| 157 | + |
| 158 | +You can define your column so that the `column_id` and the field to take a value from have different names. In the example below the `iv_value` in `render_cell` will be taken from the `person_id` field in the table structure. |
| 159 | + |
| 160 | +```abap |
| 161 | + li_table->define_column( |
| 162 | + iv_column_id = 'id' |
| 163 | + iv_column_title = 'ID' |
| 164 | + iv_from_field = 'person_id' ). |
| 165 | +``` |
| 166 | + |
| 167 | +You are not obliged to use `iv_value` in `render_cell`. Among the parameters of `render_cell` and `get_row_attrs` you will find also: |
| 168 | + |
| 169 | +- `is_row` - full table record being processed, to access the data flexibly and/or conditionally |
| 170 | +- `iv_row_index` - ... its index |
| 171 | +- `iv_table_id` - table id passed to the `render` (in case you want to render several tables with the same _renderer_ instance. Though it is generally not the best practice, better avoid it and create separate local classes for each renderer) |
| 172 | +- `iv_column_id` - column id of the current table column (for `render_cell` only) |
| 173 | + |
| 174 | +Using the `html` attribute, you can return an instance of `zif_abapgit_html`. Use this if you want to return more complex HTML content. |
| 175 | + |
| 176 | +```abap |
| 177 | + method zif_abapgit_html_table~render_cell. |
| 178 | + rs_render-html = zcl_abapgit_html=>create( )->add_a( ... ). |
| 179 | + endmethod. |
| 180 | +``` |
| 181 | + |
| 182 | +## Sorting |
| 183 | + |
| 184 | +`html_table` component does not manage sorting over the data itself but rather provides helpers to visualize it and process appropriate events. The sorting itself should be done externally. |
| 185 | + |
| 186 | + |
| 187 | + |
| 188 | +The sorting UI is triggered by passing `is_sorting_state` to the `render`. This is a structure consisting of two fields - `column_id` and `descending` value - which A) tells the component to visualize sorting B) tells which column is sorted and in which direction ( `descending = true/false` ). |
| 189 | + |
| 190 | +In terms of CSS styles all sorting arrow are styled with `sort-arrow` class and the active one has additionally `sort-active` class. When designing an own CSS style, please don't create `.sort-arrow` names classes, but rather specify a more complete path `table.my-tab th span.sort-arrow` to avoid conflicts with the `default-table` style. |
| 191 | + |
| 192 | +You can also pass `iv_sortable = abap_false` to `define_column` to remove the sorting possibility for a fiven column (by default all collumns are sortable). |
| 193 | + |
| 194 | +Technical-wise sorting markers are links with events defined like `sapevent:sort_by:id:dsc` where `id` is a column id. This event must be properly processed in the host component. To simplify handling there is a helper method to identify and parse such an event. So the easiest way to handle sorting would be placing this code to the `on_event`: |
| 195 | + |
| 196 | +```abap |
| 197 | + data ls_sorting_request type zif_abapgit_html_table=>ty_sorting_state. |
| 198 | + ls_sorting_request = zcl_abapgit_html_table=>detect_sorting_request( ii_event->mv_action ). |
| 199 | + if ls_sorting_request is not initial. |
| 200 | + ms_sorting_state = ls_sorting_request. |
| 201 | + rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render. |
| 202 | + endif. |
| 203 | +``` |
| 204 | + |
| 205 | +... and then applying the `ms_sorting_state` elsewhere before rendering the table |
0 commit comments