Skip to content

Commit bea8986

Browse files
authored
Merge pull request #89 from abap2UI5/claude/clever-brown-mVVWw
Reorganize docs: move deprecated features to Obsolete section
2 parents c993e7f + 9976250 commit bea8986

11 files changed

Lines changed: 544 additions & 46 deletions

File tree

docs/.vitepress/config.mjs

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ export default defineConfig({
239239
{
240240
text: "EML, CDS, SQL",
241241
link: "/cookbook/eml_cds_sql/rap",
242+
collapsed: true,
242243
items: [
243244
{ text: "RAP", link: "/cookbook/eml_cds_sql/rap" },
244245
{ text: "EML", link: "/cookbook/eml_cds_sql/eml" },
@@ -248,14 +249,34 @@ export default defineConfig({
248249
],
249250
},
250251
{
251-
text: "Utilities",
252+
text: "Patterns, Helpers",
253+
collapsed: true,
252254
items: [
255+
{ text: "Snippets", link: "/cookbook/expert_more/snippets" },
253256
{ text: "Value Help", link: "/cookbook/expert_more/value_help" },
254257
{ text: "Demo Output", link: "/cookbook/expert_more/demo_output" },
255258
{ text: "E-Mail", link: "/cookbook/expert_more/email" },
256259
{ text: "Fuzzy Search", link: "/cookbook/eml_cds_sql/fuzzy_search" },
257260
],
258261
},
262+
{
263+
text: "Experimental",
264+
items: [
265+
{ text: "Drag & Drop", link: "/advanced/experimental/drag_drop" },
266+
{
267+
text: "Smart Control",
268+
link: "/advanced/experimental/smart_control",
269+
},
270+
],
271+
},
272+
{
273+
text: "Obsolete",
274+
items: [
275+
{ text: "Custom Controls", link: "/cookbook/expert_more/custom_controls" },
276+
{ text: "Custom JS", link: "/cookbook/expert_more/custom_js" },
277+
{ text: "follow_up_action", link: "/cookbook/expert_more/follow_up_action" },
278+
],
279+
},
259280
],
260281
},
261282
],
@@ -310,25 +331,13 @@ export default defineConfig({
310331
text: "User Exit",
311332
link: "/advanced/extensibility/user_exits",
312333
},
313-
{ text: "Custom JavaScript", link: "/advanced/extensibility/custom_js" },
314334
{ text: "Frontend", link: "/advanced/extensibility/frontend" },
315335
{
316336
text: "Custom Control",
317337
link: "/advanced/extensibility/custom_control",
318338
},
319339
],
320340
},
321-
{
322-
text: "Experimental",
323-
collapsed: true,
324-
items: [
325-
{ text: "Drag & Drop", link: "/advanced/experimental/drag_drop" },
326-
{
327-
text: "Smart Control",
328-
link: "/advanced/experimental/smart_control",
329-
},
330-
],
331-
},
332341
],
333342
},
334343
{

docs/advanced/extensibility/custom_js.md

Lines changed: 0 additions & 32 deletions
This file was deleted.

docs/cookbook/eml_cds_sql/eml.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,46 @@ ENDMETHOD.
8686
Key Points:
8787
- EML calls in abap2UI5 apps run outside the RAP framework, so explicit transaction commits (COMMIT ENTITIES) are needed.
8888
- Restrictions inside the RAP framework, like disallowing direct calls to posting function modules or explicit commits, don't apply to abap2UI5 EML operations. You get more flexibility when handling commits and other actions.
89+
90+
### Failure Handling
91+
92+
EML statements (`MODIFY ENTITIES`, `READ ENTITIES`, `COMMIT ENTITIES`) report problems through the `FAILED` and `REPORTED` structures rather than by raising exceptions. They can also raise classic ABAP exceptions for infrastructure-level failures.
93+
94+
What to handle:
95+
- **Business / validation failures** — inspect `FAILED` (which entities failed) and `REPORTED` (the messages explaining why) after each EML call. These are *not* exceptions; an unchecked `FAILED` will look like success in your code while the data was never written.
96+
- **Transactional behavior** — EML modifications stay in the transactional buffer until `COMMIT ENTITIES`. If you skip the commit, nothing is persisted. If `COMMIT ENTITIES` itself reports failures, you must decide whether to retry, roll back, or surface the error to the user.
97+
- **Infrastructure exceptions** — wrap EML calls in `TRY … CATCH` for the cases that *do* raise:
98+
- `cx_root` / `cx_dynamic_check` — catch-all safety net.
99+
- `cx_abap_invalid_value`, `cx_sy_conversion_no_number` — data conversion problems before the EML statement runs.
100+
- `cx_abap_behv` and its subclasses — RAP behavior framework errors (e.g. unknown action, locking issues).
101+
- `cx_abap_lock_failure` — when `COMMIT ENTITIES` cannot acquire locks.
102+
103+
A typical defensive pattern:
104+
105+
```abap
106+
TRY.
107+
MODIFY ENTITIES OF z_i_invoice
108+
ENTITY invoice
109+
UPDATE FIELDS ( amount ) WITH VALUE #( ( %tky = ls_key amount = lv_amount ) )
110+
FAILED DATA(failed)
111+
REPORTED DATA(reported).
112+
113+
IF failed IS NOT INITIAL.
114+
" surface reported messages, do NOT commit
115+
RAISE EXCEPTION NEW cx_abap_behv( ).
116+
ENDIF.
117+
118+
COMMIT ENTITIES RESPONSE OF z_i_invoice
119+
FAILED DATA(commit_failed)
120+
REPORTED DATA(commit_reported).
121+
122+
IF commit_failed IS NOT INITIAL.
123+
RAISE EXCEPTION NEW cx_abap_behv( ).
124+
ENDIF.
125+
126+
CATCH cx_root INTO DATA(lx).
127+
client->nav_app_call( z2ui5_cl_pop_error=>factory( lx ) ).
128+
ENDTRY.
129+
```
130+
131+
For general exception handling and the framework's error popup, see the [Exception](/cookbook/event_navigation/exception) page.

docs/cookbook/event_navigation/exception.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,32 @@ METHOD z2ui5_if_app~main.
4040
4141
ENDMETHOD.
4242
```
43+
44+
## Common Failure Modes
45+
46+
Not every problem raises an ABAP exception. Many failures surface only in the browser, or fail silently. The sections below describe what to look for in three frequent cases.
47+
48+
#### Binding-Path Mismatch
49+
50+
When a `_bind` / `_bind_edit` path does not resolve against the JSON model on the frontend — typically because the public attribute was renamed, the data was never sent, or the path is mistyped — UI5 does **not** raise an ABAP exception. The control simply renders empty or with a default value.
51+
52+
Where to look:
53+
- **Browser console.** UI5 logs a warning like `Binding "/path/to/field" was not found in model` from `sap.ui.model.json.JSONModel`. Open the browser DevTools console and filter by `sap.ui.model`.
54+
- **Network tab.** Inspect the abap2UI5 response payload — the JSON model is included verbatim. If the field is absent or named differently than your binding path, you have your answer.
55+
- **ABAP side.** Nothing. The backend never learns the binding failed. Asserting "no console warnings" is the only way to catch this in tests.
56+
57+
Two-way binding (`_bind_edit`) silently drops the write-back when the path is invalid — your ABAP attribute keeps its old value after the next event. Cross-check the attribute value in the debugger if data is mysteriously not updating.
58+
59+
#### Malformed XML
60+
61+
`Z2UI5_CL_XML_VIEW` produces XML; UI5 parses it on the frontend. A typo in a control name, an unclosed tag, or an aggregation that contains an invalid child can break parsing entirely.
62+
63+
Where the error surfaces depends on what went wrong:
64+
- **Pure XML syntax errors** (unclosed tag, bad escape) — the XML parser fails and UI5 logs a `Parse error` in the browser console. The page renders blank or up to the broken element.
65+
- **Unknown UI5 controls / namespaces** — UI5 logs `failed to load 'sap.m.NotAControl'` (or similar) in the console; the surrounding view may render partially.
66+
- **Wrong aggregation / wrong child type** — see the warning on the [View Definition](/cookbook/view/definition) page. UI5 may log an `aggregation … does not contain` warning or silently drop the child. Layouts can render in unexpected ways without any error.
67+
- **ABAP side** — none of these surface as ABAP exceptions. `view_display( )` accepts any string. The response goes out, and only the browser notices.
68+
69+
When something looks wrong on screen, **always check the browser console first** before re-reading the ABAP code.
70+
71+
For EML-specific failure handling (`FAILED` / `REPORTED`, transactional behavior, `cx_abap_behv`, `cx_abap_lock_failure`, defensive `TRY/CATCH` patterns), see the [EML](/cookbook/eml_cds_sql/eml) page.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
---
2+
outline: [2, 4]
3+
---
4+
# Custom Controls (Obsolete)
5+
6+
::: warning Mostly Not Needed Anymore
7+
Earlier versions of abap2UI5 required custom UI5 controls to cover common browser interactions — setting the page title, moving focus, scrolling, copying to the clipboard, opening new tabs, and so on. These are now built into the framework as **frontend events**, callable from ABAP via `client->action( val = client->cs_event-... )`. The custom controls that used to wrap these behaviors are obsolete.
8+
9+
You can still build your own [Custom Controls](/advanced/extensibility/custom_control) when you need something the framework does not provide, but for everything listed below, use the dedicated built-in action instead.
10+
:::
11+
12+
## Replaced Custom Controls
13+
14+
The table below lists custom controls that are no longer necessary and the built-in action that replaces each one.
15+
16+
| Old Custom Control Purpose | New Built-in Action | Documentation |
17+
| -------------------------- | ---------------------------- | -------------------------------------------------------------------------- |
18+
| Set the browser tab title | `cs_event-set_title` | [Title](/cookbook/browser_interaction/title) |
19+
| Move input focus | `cs_event-set_focus` | [Focus](/cookbook/browser_interaction/focus) |
20+
| Scroll to a position | `cs_event-scroll_to` | [Scrolling](/cookbook/browser_interaction/scrolling) |
21+
| Scroll an element into view| `cs_event-scroll_into_view` | [Scrolling](/cookbook/browser_interaction/scrolling) |
22+
| Copy to clipboard | `cs_event-clipboard_copy` | [Clipboard](/cookbook/browser_interaction/clipboard) |
23+
| Open a URL / new tab | `cs_event-open_new_tab` | [URL Handling](/cookbook/browser_interaction/url_handling) |
24+
| Start a timer | `cs_event-start_timer` | [Timer](/cookbook/browser_interaction/timer) |
25+
| Toggle the soft keyboard | `cs_event-keyboard_set_mode` | [Soft Keyboard](/cookbook/device_capabilities/soft_keyboard) |
26+
| Trigger a file download | `cs_event-download_b` | [Upload, Download](/cookbook/device_capabilities/upload_download) |
27+
| Play an audio file | `cs_event-play_audio` | [Barcode Scanning](/cookbook/device_capabilities/barcode_scanning) |
28+
29+
## Why Prefer the Built-in Actions
30+
31+
- **No frontend code to maintain.** The action runs framework-side JavaScript that ships with abap2UI5 — you do not write or deploy your own JS.
32+
- **Stays in pure ABAP.** Calling `client->action( )` keeps your app logic in one place and one language.
33+
- **Reviewed and tested.** The built-in actions are part of the framework, covered by its tests, and updated alongside it.
34+
- **Safer.** Custom controls usually involve embedding JavaScript via [Custom JS](/cookbook/expert_more/custom_js), which carries the security risks documented on that page.
35+
36+
## Typical Pattern
37+
38+
Instead of writing a custom control, call the matching action after an event:
39+
40+
```abap
41+
client->action( val = client->cs_event-set_title
42+
t_arg = VALUE #( ( `Invoice 4711` ) ) ).
43+
```
44+
45+
See the linked cookbook pages above for the full argument list of each action.
46+
47+
## When Custom Controls Still Make Sense
48+
49+
Building a real [Custom Control](/advanced/extensibility/custom_control) is still appropriate when:
50+
51+
- You need a UI element that UI5 does not ship and no abap2UI5 action covers.
52+
- You are integrating a third-party UI5 library.
53+
- You need behavior beyond simple frontend method calls — e.g. a stateful widget with its own rendering.
54+
55+
In all other cases, prefer the built-in action.
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
---
2+
outline: [2, 4]
3+
---
4+
# Custom JS
5+
6+
::: warning Not Recommended
7+
This functionality is still available, but its use is **strongly discouraged**. Injecting arbitrary JavaScript from the backend into the frontend introduces serious security risks. Only use it if you fully understand the consequences and have no alternative.
8+
:::
9+
10+
## Why It Is a Security Risk
11+
12+
Custom JS works by sending a JavaScript string from the ABAP backend to the frontend, where it is injected into the DOM as an HTML `<script>` tag and executed in the user's browser. This pattern is essentially a **self-inflicted Cross-Site Scripting (XSS) vector** and breaks several security assumptions UI5 normally protects you from:
13+
14+
- **Bypasses output encoding.** UI5 escapes model data by default to prevent XSS. Raw `<script>` injection sidesteps that protection entirely.
15+
- **Executes with full user privileges.** The injected code runs in the same origin as your app and can read cookies, session tokens, the UI5 model, and any data the user has access to — and send it anywhere.
16+
- **Dynamic content is dangerous.** If any part of the injected JavaScript is built from user input, database values, translations, or other non-static sources, an attacker who controls that source can execute arbitrary code in every user's browser.
17+
- **Breaks Content Security Policy (CSP).** A strict CSP — one of the most effective defenses against XSS — typically forbids inline scripts. Custom JS forces you to weaken or disable CSP, removing that protection for the whole app.
18+
- **Hard to audit.** JavaScript assembled in ABAP strings is not covered by frontend linters, static analysis, or code review tools that normally catch dangerous patterns.
19+
- **No sandboxing.** The script has the same DOM and network access as the rest of the app. There is no isolation boundary.
20+
21+
## Safer Alternatives
22+
23+
Before reaching for Custom JS, consider:
24+
25+
- Use the **standard UI5 controls and APIs** — most browser interactions are already covered.
26+
- Build a proper **[Custom Control](/advanced/extensibility/custom_control)** with a defined interface and reviewable frontend code.
27+
- Use the dedicated cookbook pages for [Clipboard](/cookbook/browser_interaction/clipboard), [Focus](/cookbook/browser_interaction/focus), [Scrolling](/cookbook/browser_interaction/scrolling), [Timer](/cookbook/browser_interaction/timer), [URL Handling](/cookbook/browser_interaction/url_handling), and similar.
28+
29+
## How It Works (If You Still Need It)
30+
31+
If you accept the risks and decide to use it anyway, the idea is: send the JavaScript function with the view to the frontend, then call it later when an event fires.
32+
33+
The `_generic` method creates a custom XML/HTML element — here an HTML `<script>` tag (namespace `html`). The `_cc_plain_xml` method inserts raw content into that element — in this case, the JavaScript function definition. On the backend, `client->follow_up_action` then runs the function by name on the frontend:
34+
35+
```abap
36+
METHOD z2ui5_if_app~main.
37+
38+
IF client->check_on_init( ).
39+
DATA(view) = z2ui5_cl_xml_view=>factory( ).
40+
view->_generic( name = `script` ns = `html`
41+
)->_cc_plain_xml(
42+
|function myFunction() \{ console.log( `Hello World` ); \}|
43+
).
44+
view->page(
45+
)->button( text = `call custom JS`
46+
press = client->_event( `CUSTOM_JS` ) ).
47+
client->view_display( view->stringify( ) ).
48+
ENDIF.
49+
50+
IF client->get( )-event = `CUSTOM_JS`.
51+
client->follow_up_action( `myFunction()` ).
52+
ENDIF.
53+
54+
ENDMETHOD.
55+
```
56+
57+
::: danger Never Inject Untrusted Input
58+
If you must use this, ensure the JavaScript content is **entirely static and hardcoded**. Never concatenate user input, database values, translatable texts, or any other dynamic data into the script string — doing so turns the feature into a direct XSS vulnerability.
59+
:::
60+
61+
## Embedding JavaScript Directly in an XML View
62+
63+
::: warning Also Not Recommended
64+
The same security considerations apply: any `<script>` element embedded in an XML view runs with full app privileges and bypasses UI5's output encoding. Prefer a [Custom Control](/advanced/extensibility/custom_control) or one of the built-in actions instead.
65+
:::
66+
67+
If you want to look at — or hand-craft — the raw XML view that abap2UI5 produces, a `<script>` tag is placed in the `html` namespace alongside the regular UI5 controls. The view stringified by `z2ui5_cl_xml_view=>factory( )` ends up looking like this:
68+
69+
```xml
70+
<mvc:View
71+
xmlns:mvc="sap.ui.core.mvc"
72+
xmlns="sap.m"
73+
xmlns:html="http://www.w3.org/1999/xhtml">
74+
<html:script>
75+
function myFunction() { console.log("Hello World"); }
76+
</html:script>
77+
<Page>
78+
<Button text="call custom JS" press="..." />
79+
</Page>
80+
</mvc:View>
81+
```
82+
83+
The browser parses the `html:script` element and executes its content as JavaScript at view render time. The function becomes available globally and can then be triggered from the backend via the obsolete [`follow_up_action`](/cookbook/expert_more/follow_up_action) — or, ideally, replaced entirely with a built-in `client->action( )` call.
84+
85+
This is exactly what the `_generic` + `_cc_plain_xml` helpers shown above produce; the two approaches are equivalent. Both ship raw JavaScript from the backend to the browser, and both carry the security risks described above. Use neither unless there is genuinely no alternative.

0 commit comments

Comments
 (0)