Skip to content

Commit 9856e5e

Browse files
authored
Merge pull request #76 from abap2UI5/claude/add-xml-templating-page-ryNJf
Reorganize documentation: split tables/trees and add templating guides
2 parents a638a44 + b5efe45 commit 9856e5e

5 files changed

Lines changed: 281 additions & 73 deletions

File tree

docs/.vitepress/config.mjs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,9 @@ export default defineConfig({
144144
collapsed: true,
145145
items: [
146146
{ text: "Binding", link: "/development/model/binding" },
147-
{ text: "Table, Tree", link: "/development/model/tables" },
147+
{ text: "Tables", link: "/development/model/tables" },
148+
{ text: "Trees", link: "/development/model/trees" },
148149
{ text: "Device Model", link: "/development/model/device" },
149-
{ text: "OData", link: "/development/model/odata" },
150150
],
151151
},
152152
{
@@ -265,6 +265,9 @@ export default defineConfig({
265265
{ text: "Value Help", link: "/development/specific/value_help" },
266266
{ text: "E-Mail", link: "/development/specific/email" },
267267
{ text: "Demo Output", link: "/development/specific/demo_output" },
268+
{ text: "XML Templating", link: "/development/specific/xml_templating" },
269+
{ text: "Nested Views", link: "/development/view/nested" },
270+
{ text: "OData", link: "/development/model/odata" },
268271
],
269272
},
270273
],

docs/development/model/tables.md

Lines changed: 2 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
---
22
outline: [2, 4]
33
---
4-
# Tables, Trees
5-
This section walks through rendering nested data structures — tables, trees, and nested records — in views.
4+
# Tables
5+
This section walks through rendering tabular and nested data in views.
66

77
### Tables
88
The example below binds a simple table to a UI5 control:
@@ -82,75 +82,6 @@ To make a table editable, switch the binding to `bind_edit`:
8282
ENDMETHOD.
8383
```
8484

85-
### Tree
86-
For trees, use nested structures:
87-
```abap
88-
CLASS z2ui5_cl_sample_tree DEFINITION PUBLIC.
89-
90-
PUBLIC SECTION.
91-
INTERFACES z2ui5_if_app.
92-
TYPES:
93-
BEGIN OF ty_prodh_node_level3,
94-
is_selected TYPE abap_bool,
95-
text TYPE string,
96-
prodh TYPE string,
97-
END OF ty_prodh_node_level3,
98-
BEGIN OF ty_prodh_node_level2,
99-
is_selected TYPE abap_bool,
100-
text TYPE string,
101-
prodh TYPE string,
102-
nodes TYPE STANDARD TABLE OF ty_prodh_node_level3 WITH DEFAULT KEY,
103-
END OF ty_prodh_node_level2,
104-
BEGIN OF ty_prodh_node_level1,
105-
is_selected TYPE abap_bool,
106-
text TYPE string,
107-
prodh TYPE string,
108-
nodes TYPE STANDARD TABLE OF ty_prodh_node_level2 WITH DEFAULT KEY,
109-
END OF ty_prodh_node_level1,
110-
ty_prodh_nodes TYPE STANDARD TABLE OF ty_prodh_node_level1 WITH DEFAULT KEY.
111-
DATA prodh_nodes TYPE ty_prodh_nodes.
112-
113-
ENDCLASS.
114-
115-
CLASS z2ui5_cl_sample_tree IMPLEMENTATION.
116-
METHOD z2ui5_if_app~main.
117-
118-
prodh_nodes = VALUE #( (
119-
text = `Machines`
120-
prodh = `00100`
121-
nodes = VALUE #( (
122-
text = `Pumps`
123-
prodh = `0010000100`
124-
nodes = VALUE #( (
125-
text = `Pump 001`
126-
prodh = `001000010000000100` ) (
127-
text = `Pump 002`
128-
prodh = `001000010000000105` ) )
129-
) ) ) (
130-
text = `Paints`
131-
prodh = `00110`
132-
nodes = VALUE #( (
133-
text = `Gloss paints`
134-
prodh = `0011000105`
135-
nodes = VALUE #( (
136-
text = `Paint 001`
137-
prodh = `001100010500000100` ) (
138-
text = `Paint 002`
139-
prodh = `001100010500000105` )
140-
) ) ) ) ).
141-
142-
DATA(tree) = z2ui5_cl_xml_view=>factory( )->page(
143-
)->tree( items = client->_bind_edit( prodh_nodes )
144-
)->items( )->standard_tree_item(
145-
selected = `{IS_SELECTED}`
146-
title = `{TEXT}` ).
147-
148-
client->view_display( tree->stringify( ) ).
149-
150-
ENDMETHOD.
151-
ENDCLASS.
152-
```
153-
15485
### Nested Structures
15586
You can also bind nested structures — use `structure/component` as the binding path:
15687
```abap

docs/development/model/trees.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
---
2+
outline: [2, 4]
3+
---
4+
# Trees
5+
For hierarchical data, abap2UI5 uses nested ABAP structures to represent tree levels. Each level holds a table of child nodes, which UI5 traverses to build the expandable tree control.
6+
7+
### Tree
8+
Define a type hierarchy where each node contains a child table of the next level:
9+
```abap
10+
CLASS z2ui5_cl_sample_tree DEFINITION PUBLIC.
11+
12+
PUBLIC SECTION.
13+
INTERFACES z2ui5_if_app.
14+
TYPES:
15+
BEGIN OF ty_prodh_node_level3,
16+
is_selected TYPE abap_bool,
17+
text TYPE string,
18+
prodh TYPE string,
19+
END OF ty_prodh_node_level3,
20+
BEGIN OF ty_prodh_node_level2,
21+
is_selected TYPE abap_bool,
22+
text TYPE string,
23+
prodh TYPE string,
24+
nodes TYPE STANDARD TABLE OF ty_prodh_node_level3 WITH DEFAULT KEY,
25+
END OF ty_prodh_node_level2,
26+
BEGIN OF ty_prodh_node_level1,
27+
is_selected TYPE abap_bool,
28+
text TYPE string,
29+
prodh TYPE string,
30+
nodes TYPE STANDARD TABLE OF ty_prodh_node_level2 WITH DEFAULT KEY,
31+
END OF ty_prodh_node_level1,
32+
ty_prodh_nodes TYPE STANDARD TABLE OF ty_prodh_node_level1 WITH DEFAULT KEY.
33+
DATA prodh_nodes TYPE ty_prodh_nodes.
34+
35+
ENDCLASS.
36+
37+
CLASS z2ui5_cl_sample_tree IMPLEMENTATION.
38+
METHOD z2ui5_if_app~main.
39+
40+
prodh_nodes = VALUE #( (
41+
text = `Machines`
42+
prodh = `00100`
43+
nodes = VALUE #( (
44+
text = `Pumps`
45+
prodh = `0010000100`
46+
nodes = VALUE #( (
47+
text = `Pump 001`
48+
prodh = `001000010000000100` ) (
49+
text = `Pump 002`
50+
prodh = `001000010000000105` ) )
51+
) ) ) (
52+
text = `Paints`
53+
prodh = `00110`
54+
nodes = VALUE #( (
55+
text = `Gloss paints`
56+
prodh = `0011000105`
57+
nodes = VALUE #( (
58+
text = `Paint 001`
59+
prodh = `001100010500000100` ) (
60+
text = `Paint 002`
61+
prodh = `001100010500000105` )
62+
) ) ) ) ).
63+
64+
DATA(tree) = z2ui5_cl_xml_view=>factory( )->page(
65+
)->tree( items = client->_bind_edit( prodh_nodes )
66+
)->items( )->standard_tree_item(
67+
selected = `{IS_SELECTED}`
68+
title = `{TEXT}` ).
69+
70+
client->view_display( tree->stringify( ) ).
71+
72+
ENDMETHOD.
73+
ENDCLASS.
74+
```
75+
76+
The child table field (`nodes` in the example above) is the key: UI5 follows that field name to locate sub-items at each level. The name must match across all levels but can be anything you choose.
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
---
2+
outline: [2, 4]
3+
---
4+
# XML Templating
5+
6+
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.
7+
8+
#### How It Works
9+
10+
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.
11+
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+
```
20+
21+
#### Conditional Rendering
22+
23+
Use ABAP `IF` statements to include or exclude controls depending on runtime state:
24+
25+
```abap
26+
DATA(xml) = z2ui5_cl_xml_view=>factory( ).
27+
DATA(page) = xml->page( 'Conditional View' ).
28+
29+
IF is_admin = abap_true.
30+
page->button(
31+
text = 'Admin Action'
32+
press = client->_event( 'ADMIN_ACTION' ) ).
33+
ENDIF.
34+
35+
page->text( 'Hello, ' && username ).
36+
client->view_display( xml->stringify( ) ).
37+
```
38+
39+
Only the controls added to the builder are serialized — nothing from the skipped branch appears in the XML.
40+
41+
#### Repeating Controls
42+
43+
Loop over an internal table to generate repeated controls:
44+
45+
```abap
46+
DATA(list) = page->list( ).
47+
48+
LOOP AT items INTO DATA(item).
49+
list->item(
50+
title = item-title
51+
description = item-description ).
52+
ENDLOOP.
53+
```
54+
55+
Each iteration appends a child node. The resulting XML contains exactly as many `<Item>` elements as there were rows in `items`.
56+
57+
#### Composing Fragments
58+
59+
Break complex views into reusable helper methods that each return a subtree:
60+
61+
```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.
71+
```
72+
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
76+
77+
A common pattern is selecting which columns to show based on user settings or authorization:
78+
79+
```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.
88+
```
89+
90+
The same loop that drives the column headers can drive the cell binding paths, keeping them in sync.
91+
92+
#### Tips
93+
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.
97+
98+
See `Z2UI5_CL_DEMO_APP_032` and `Z2UI5_CL_DEMO_APP_033` for complete examples of conditional and dynamic views.

docs/development/view/nested.md

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
---
2+
outline: [2, 4]
3+
---
4+
# Nested Views
5+
6+
A nested view is a view that is built from several independent parts. In abap2UI5 there are two main ways to achieve this: composing a single view tree from helper methods, and splitting the app into sub-apps that each own a slice of the view.
7+
8+
#### Composing with Helper Methods
9+
10+
The fluent builder returns each node as an object reference, so you can pass a node into a helper method and let it add children there:
11+
12+
```abap
13+
METHOD z2ui5_if_app~main.
14+
IF client->check_on_init( ).
15+
DATA(xml) = z2ui5_cl_xml_view=>factory( ).
16+
DATA(page) = xml->shell( )->page( 'My App' ).
17+
18+
build_header( page ).
19+
build_content( page ).
20+
build_footer( page ).
21+
22+
client->view_display( xml->stringify( ) ).
23+
ENDIF.
24+
ENDMETHOD.
25+
26+
METHOD build_header.
27+
io_page->toolbar( )->title( 'Header' ).
28+
ENDMETHOD.
29+
30+
METHOD build_content.
31+
io_page->vbox(
32+
)->text( 'Line 1'
33+
)->text( 'Line 2' ).
34+
ENDMETHOD.
35+
36+
METHOD build_footer.
37+
io_page->footer( )->button(
38+
text = 'Save'
39+
press = client->_event( 'SAVE' ) ).
40+
ENDMETHOD.
41+
```
42+
43+
Each helper receives the parent node by reference and attaches its controls to it. The final `stringify( )` call serialises the entire tree — including all nested children — into one XML string.
44+
45+
#### Sub-Apps
46+
47+
For larger apps it is useful to split responsibility across separate ABAP classes. Each sub-app implements `z2ui5_if_app` and manages its own piece of the view. The parent app instantiates the sub-app, passes the client, and merges the returned view fragment into its own view tree.
48+
49+
**Parent app:**
50+
```abap
51+
METHOD z2ui5_if_app~main.
52+
IF client->check_on_init( ).
53+
sub_app = NEW z2ui5_cl_my_sub_app( ).
54+
ENDIF.
55+
56+
DATA(xml) = z2ui5_cl_xml_view=>factory( ).
57+
DATA(page) = xml->shell( )->page( 'Parent' ).
58+
59+
" Let the sub-app render into a container on the page
60+
DATA(container) = page->vbox( ).
61+
sub_app->render( client = client io_node = container ).
62+
63+
client->view_display( xml->stringify( ) ).
64+
ENDMETHOD.
65+
```
66+
67+
**Sub-app:**
68+
```abap
69+
METHOD render.
70+
io_node->text( 'I am the sub-app' ).
71+
io_node->button(
72+
text = 'Sub Action'
73+
press = io_client->_event( 'SUB_ACTION' ) ).
74+
ENDMETHOD.
75+
```
76+
77+
The sub-app appends its controls to whatever node the parent provides. Events fired inside the sub-app are handled by the sub-app's own `main` method on the next roundtrip.
78+
79+
#### Navigation Between Views
80+
81+
When the nested content changes completely — for example, a detail page replacing a list — use `view_display` to swap the entire view rather than nesting:
82+
83+
```abap
84+
CASE client->get_event( ).
85+
WHEN 'OPEN_DETAIL'.
86+
client->view_display( detail_view->stringify( ) ).
87+
WHEN 'BACK'.
88+
client->view_display( list_view->stringify( ) ).
89+
ENDCASE.
90+
```
91+
92+
Reserve true nesting for content that appears side-by-side or in a stable layout shell. Use `view_display` for sequential navigation where one screen fully replaces another.
93+
94+
#### Tips
95+
96+
- Keep each helper or sub-app focused on one logical section. A helper that grows beyond ~30 lines is a candidate for its own sub-app class.
97+
- Sub-apps can hold their own instance attributes for local state. Because the whole app tree is reconstructed on every roundtrip, each sub-app re-renders from its current state automatically.
98+
- Pass only the node the sub-app needs, not the whole view root. This limits the sub-app's scope and makes the boundary explicit.
99+
100+
See `Z2UI5_CL_DEMO_APP_160` for an end-to-end example of parent and sub-app composition.

0 commit comments

Comments
 (0)