You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
abap2UI5 sends views to the browser as XML strings. XML Templating lets you construct those strings dynamically in ABAP — branching on conditions, looping over data, and composing fragments — so that the view the browser receives is already fully resolved without any client-side template engine.
6
+
XML Templating is a **UI5 preprocessor feature**, not an abap2UI5 invention. The UI5 runtime understands a small set of instructions in the `template` XML namespace — `template:repeat`, `template:if`, `template:then`, `template:else`, `template:with` — and expands them into plain XML *before* the control tree is created. abap2UI5 exposes these instructions through the fluent builder so you can drive the expansion from ABAP data.
7
+
8
+
See the official UI5 references for the underlying mechanics:
Every abap2UI5 view is ultimately an XML string. You can build that string however you like: literal assignment, string concatenation, helper method calls, or a dedicated XML builder. The browser never sees template syntax — it only receives the final, rendered XML.
15
+
Templating happens **once**, at view instantiation, against a JSON model. The preprocessor walks the XML, evaluates each `template:` instruction against that model, and replaces the instruction with the resulting XML. After that the control tree is built from the expanded XML and normal data binding takes over.
11
16
12
-
```abap
13
-
METHOD z2ui5_if_app~main.
14
-
IF client->check_on_init( ).
15
-
DATA(xml) = z2ui5_cl_xml_view=>factory( ).
16
-
client->view_display( xml->stringify( ) ).
17
-
ENDIF.
18
-
ENDMETHOD.
19
-
```
17
+
This timing has two consequences:
20
18
21
-
#### Conditional Rendering
19
+
-**Expansion is build-time.** A `template:repeat` over an internal table produces a fixed number of controls; the expanded XML is what UI5 renders.
20
+
-**Data changes do not re-template.** If the data driving the template changes, the existing expansion stays as is. To pick up the change you must rebuild the view (`view_display`) or the templated fragment (`nest_view_display`) — see [Re-rendering](#re-rendering) below.
22
21
23
-
Use ABAP `IF` statements to include or exclude controls depending on runtime state:
22
+
abap2UI5 wires up the templating model for you. Every variable you bind with `client->_bind( ... )` or `client->_bind_edit( ... )` is reachable inside templates via the `template>` model prefix:
The `template>` model is the templating engine's view of the data — distinct from the default model used by runtime bindings like `{MT_DATA}`.
28
30
29
-
IF is_admin = abap_true.
30
-
page->button(
31
-
text = 'Admin Action'
32
-
press = client->_event( 'ADMIN_ACTION' ) ).
33
-
ENDIF.
31
+
#### `template:repeat` — Loops
34
32
35
-
page->text( 'Hello, ' && username ).
36
-
client->view_display( xml->stringify( ) ).
33
+
`template:repeat` clones its children once per row of the bound list. Use it when the **structure** of the view (e.g. which columns a table has) depends on data:
Only the controls added to the builder are serialized — nothing from the skipped branch appears in the XML.
57
+
Notes on the snippet:
40
58
41
-
#### Repeating Controls
59
+
-`list` is the binding path that drives the loop; `var` is the alias used inside the loop body (here `L0` for the column headers, `L1` for the cells).
60
+
- Inside the loop, `{L0>FNAME}` is a templating-time read — it ends up as the literal string `NAME`/`DATE`/`AGE` in the expanded XML.
61
+
-`{= '{' + ${L1>FNAME} + '}' }` is an [expression binding](https://sapui5.hana.ondemand.com/sdk/#/topic/daf6852a04b44d118963968a1239d2c0) that **constructs another binding string at templating time**. With `L1>FNAME = NAME` it expands to `text="{NAME}"`, which becomes a normal runtime binding against the row of `mt_data`. This is the standard pattern for templated tables: outer loop builds the columns, inner loop builds the cells, expression binding wires each cell to the right field of the row.
62
+
-`template_repeat` accepts the same optional attributes as the UI5 instruction (`startIndex`, `length`) plus list-binding extras like sorters and filters.
42
63
43
-
Loop over an internal table to generate repeated controls:
`template:if` evaluates an expression against the templating model and keeps or drops its children accordingly. With a `template:then` / `template:else` pair you get a two-branch switch:
47
69
48
-
LOOP AT items INTO DATA(item).
49
-
list->item(
50
-
title = item-title
51
-
description = item-description ).
52
-
ENDLOOP.
70
+
```abap
71
+
client->_bind_edit( mv_flag ).
72
+
73
+
view->template_if( `{template>/XX/MV_FLAG}`
74
+
)->template_then(
75
+
)->icon( src = `sap-icon://accept`
76
+
color = `green` )->get_parent(
77
+
)->template_else(
78
+
)->icon( src = `sap-icon://decline`
79
+
color = `red` ).
53
80
```
54
81
55
-
Each iteration appends a child node. The resulting XML contains exactly as many `<Item>` elements as there were rows in `items`.
82
+
The test argument follows the same rules as in UI5: any binding expression is fine, and the string `"false"` is treated as boolean `false` (a UI5 convenience). For richer conditions use expression binding, e.g. `` `{= ${template>/XX/MV_COUNT} > 0 }` ``.
83
+
84
+
`template:elseif` is also supported by UI5; check `Z2UI5_CL_XML_VIEW` for the corresponding fluent method or fall back to the generic builder (see [Definition](/cookbook/view/definition#the-fully-generic-builder)).
56
85
57
-
#### Composing Fragments
86
+
#### Re-rendering
58
87
59
-
Break complex views into reusable helper methods that each return a subtree:
88
+
Because templating runs once, the view must be rebuilt for changes in the templating model to take effect. There are two strategies:
89
+
90
+
**Rebuild the whole view** — simplest, works for most apps. After the user toggles a flag, render the view again:
60
91
61
92
```abap
62
-
METHOD build_header.
63
-
rv_header = io_page->toolbar( )->title( title ).
64
-
ENDMETHOD.
65
-
66
-
METHOD build_table.
67
-
DATA(tbl) = io_page->table( ).
68
-
" ... add columns and rows
69
-
rv_table = tbl.
70
-
ENDMETHOD.
93
+
CASE client->get( )-event.
94
+
WHEN `CHANGE_FLAG`.
95
+
view_display( ). " builds and ships the view again
96
+
ENDCASE.
71
97
```
72
98
73
-
Call the helpers in sequence inside `main` to assemble the final view. Because the builder accumulates children as regular ABAP object references, standard ABAP patterns (loops, conditions, method calls, function modules) all apply without restriction.
74
-
75
-
#### Dynamic Column Sets
99
+
This is the pattern used in `Z2UI5_CL_DEMO_APP_173`: the switch fires `CHANGE_FLAG`, `view_display` runs, the new value of `mv_flag` flows through `template:if`, and the icon swaps.
76
100
77
-
A common pattern is selecting which columns to show based on user settings or authorization:
101
+
**Rebuild only the templated fragment** — keeps a stable shell on screen and replaces a nested piece. `Z2UI5_CL_DEMO_APP_176` separates the main view from the templated table:
78
102
79
103
```abap
80
-
DATA(cols) = xml->table( )->columns( ).
81
-
82
-
IF show_price = abap_true.
83
-
cols->column( )->text( 'Price' ).
84
-
ENDIF.
85
-
IF show_stock = abap_true.
86
-
cols->column( )->text( 'Stock' ).
87
-
ENDIF.
104
+
" Main view: built once, stays on screen
105
+
DATA(lo_view) = z2ui5_cl_xml_view=>factory( ).
106
+
lo_view->shell( )->page( title = `Main View` id = `test` ... ).
107
+
client->view_display( lo_view->stringify( ) ).
108
+
109
+
" Nested templated view: inserted into the main view by id
)->template_repeat( list = `{template>/MT_LAYOUT}` var = `LO`
115
+
)->column( ... ) " ...
116
+
117
+
client->nest_view_display( val = lo_view_nested->stringify( )
118
+
id = `test`
119
+
method_insert = `addContent` ).
88
120
```
89
121
90
-
The same loop that drives the column headers can drive the cell binding paths, keeping them in sync.
122
+
`nest_view_display` targets a control in the existing view by id (`test`) and appends/replaces the nested view there. To refresh the templated piece on a data change, call `nest_view_display` again from the event handler — the main view is left untouched.
123
+
124
+
#### Templating vs ABAP-side Composition
125
+
126
+
The two demo apps both build *dynamic* views, but with different mechanics. Pick based on what the dynamic part actually is:
| Whether a control exists at all, decided once per render | ABAP `IF` around the builder call — simpler, no `template:` namespace involved |
131
+
| Number of controls comes from an internal table, computed once | ABAP `LOOP` over the table, calling the builder for each row |
132
+
| Reusable XML fragment that UI5 itself should expand against metadata |`template:repeat` / `template:if` — keeps the templating logic in the view layer |
133
+
| Cells of a table where the column set itself is data-driven |`template:repeat` — UI5 expands columns and cell bindings in one pass, as in app 173 |
134
+
135
+
Plain ABAP control flow covers most cases and is easier to debug. Reach for `template:` when you want the expansion to live in the view (closer to standard UI5 patterns) or when you are mapping a metadata-style structure onto controls.
91
136
92
137
#### Tips
93
138
94
-
- Build the full view on every roundtrip. abap2UI5 is stateless by default, so the view is always reconstructed from the current model state — there is no diff or patch step.
95
-
- Keep view-construction logic out of business-logic methods. A dedicated `build_view` method or a set of small fragment builders keeps `main` readable.
96
-
- Prefer the fluent builder API (`z2ui5_cl_xml_view`) over raw string concatenation. The builder escapes special characters automatically and produces well-formed XML.
139
+
- Always bind the data that drives a template (`client->_bind` / `client->_bind_edit`) **before** the builder call that references it. The binding registers the path that `{template>/...}` resolves against.
140
+
- Inside `template:repeat`, prefer `{var>FIELD}` over deeper paths — it keeps the body readable and lets you nest repeats with distinct `var` names (`L0`, `L1`, ...) without collisions.
141
+
- Use expression binding (`{= ... }`) when the value you need is a binding string itself. Templating-time expressions can read `${var>...}` and concatenate strings, which is how dynamic cell bindings are assembled.
142
+
- If a templated control does not update after a data change, you forgot to rebuild — call `view_display` or `nest_view_display` again.
97
143
98
-
See `Z2UI5_CL_DEMO_APP_032` and `Z2UI5_CL_DEMO_APP_033` for complete examples of conditional and dynamic views.
144
+
See `Z2UI5_CL_DEMO_APP_173` for `template:repeat` + `template:if` in a single view and `Z2UI5_CL_DEMO_APP_176` for the stable-shell / templated-nested-view pattern.
0 commit comments