Skip to content

Commit d02ebfb

Browse files
committed
Add PDF, Clipboard, E-Mail, Value Help, WebSocket cookbook pages
Closes coverage gaps for common ABAP-developer scenarios: built-in PDF popup, frontend clipboard copy, BCS-based mail sending, F4-style value help with the selection popup, and WebSocket push via APC/AMC. PDF, Clipboard, E-Mail and Value Help land under "More"; WebSocket joins "Expert Topic" next to Statefulness.
1 parent 27b766d commit d02ebfb

6 files changed

Lines changed: 332 additions & 1 deletion

File tree

docs/.vitepress/config.mjs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,14 +236,19 @@ export default defineConfig({
236236
items: [
237237
{ text: "Lock", link: "/development/specific/locks" },
238238
{ text: "Statefulness", link: "/development/specific/statefulness" },
239+
{ text: "WebSocket", link: "/development/specific/websocket" },
239240
{ text: "Logout", link: "/configuration/logout" },
240241
],
241242
},
242243
{
243244
text: "More",
244-
link: "/development/specific/demo_output",
245+
link: "/development/specific/pdf",
245246
collapsed: true,
246247
items: [
248+
{ text: "PDF", link: "/development/specific/pdf" },
249+
{ text: "Clipboard", link: "/development/specific/clipboard" },
250+
{ text: "E-Mail", link: "/development/specific/email" },
251+
{ text: "Value Help", link: "/development/specific/value_help" },
247252
{ text: "Demo Output", link: "/development/specific/demo_output" },
248253
],
249254
},
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
---
2+
outline: [2, 4]
3+
---
4+
# Clipboard
5+
6+
Copy arbitrary text to the user's clipboard with the frontend event `client->cs_event-clipboard_copy`. The text travels as the first `t_arg` entry and is passed to the browser's `navigator.clipboard.writeText` API — no backend roundtrip on paste.
7+
8+
```abap
9+
CLASS z2ui5_cl_sample_clipboard DEFINITION PUBLIC.
10+
11+
PUBLIC SECTION.
12+
INTERFACES z2ui5_if_app.
13+
DATA mv_text TYPE string.
14+
15+
ENDCLASS.
16+
17+
CLASS z2ui5_cl_sample_clipboard IMPLEMENTATION.
18+
METHOD z2ui5_if_app~main.
19+
20+
CASE abap_true.
21+
22+
WHEN client->check_on_init( ).
23+
mv_text = `Hello from abap2UI5`.
24+
25+
client->view_display( z2ui5_cl_xml_view=>factory(
26+
)->page(
27+
)->input( client->_bind_edit( mv_text )
28+
)->button(
29+
text = `copy to clipboard`
30+
press = client->_event( `COPY` )
31+
)->stringify( ) ).
32+
33+
WHEN client->check_on_event( `COPY` ).
34+
client->follow_up_action( client->_event_client(
35+
val = client->cs_event-clipboard_copy
36+
t_arg = VALUE #( ( mv_text ) ) ) ).
37+
client->message_toast_display( `copied` ).
38+
39+
ENDCASE.
40+
41+
ENDMETHOD.
42+
ENDCLASS.
43+
```
44+
45+
#### Copy the App State URL
46+
47+
To share the current app state instead of a custom string, use `clipboard_app_state` — see [Share, Bookmark](../navigation/share.md).
48+
49+
::: warning
50+
The browser's Clipboard API requires HTTPS (or `localhost`). On plain HTTP the call is silently ignored.
51+
:::

docs/development/specific/email.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
---
2+
outline: [2, 4]
3+
---
4+
# E-Mail
5+
6+
abap2UI5 has no e-mail control of its own — sending mail is plain ABAP via `cl_bcs_message` (or `cl_bcs` on older releases). The UI part is a normal event handler that gathers the form fields and calls the BCS API.
7+
8+
#### Plain Text Mail
9+
10+
```abap
11+
CLASS z2ui5_cl_sample_email DEFINITION PUBLIC.
12+
13+
PUBLIC SECTION.
14+
INTERFACES z2ui5_if_app.
15+
DATA mv_to TYPE string.
16+
DATA mv_subject TYPE string.
17+
DATA mv_body TYPE string.
18+
19+
ENDCLASS.
20+
21+
CLASS z2ui5_cl_sample_email IMPLEMENTATION.
22+
METHOD z2ui5_if_app~main.
23+
24+
CASE abap_true.
25+
26+
WHEN client->check_on_init( ).
27+
client->view_display( z2ui5_cl_xml_view=>factory(
28+
)->page( `Send E-Mail`
29+
)->simple_form( editable = abap_true
30+
)->content( `form`
31+
)->label( `To` )->input( client->_bind_edit( mv_to )
32+
)->label( `Subject` )->input( client->_bind_edit( mv_subject )
33+
)->label( `Body` )->text_area( client->_bind_edit( mv_body )
34+
)->button(
35+
text = `send`
36+
press = client->_event( `SEND` )
37+
)->stringify( ) ).
38+
39+
WHEN client->check_on_event( `SEND` ).
40+
TRY.
41+
DATA(lo_mail) = cl_bcs_message=>create_persistent( ).
42+
lo_mail->set_subject( CONV #( mv_subject ) ).
43+
lo_mail->set_main( cl_bcs_convert=>string_to_soli( mv_body ) ).
44+
lo_mail->add_recipient( i_address = CONV #( mv_to ) i_address_type = `INT` ).
45+
lo_mail->send( i_with_error_screen = abap_false ).
46+
COMMIT WORK.
47+
client->message_toast_display( `mail queued` ).
48+
CATCH cx_root INTO DATA(lx).
49+
client->message_box_display( lx->get_text( ) ).
50+
ENDTRY.
51+
52+
ENDCASE.
53+
54+
ENDMETHOD.
55+
ENDCLASS.
56+
```
57+
58+
#### Attachment
59+
60+
Reuse the [file upload](./files.md) flow to capture an attachment as base64, then hand it to `cl_bcs_message`:
61+
62+
```abap
63+
DATA(lv_xstring) = cl_web_http_utility=>decode_x_base64( mv_attachment_base64 ).
64+
lo_mail->add_attachment(
65+
iv_attachment_type = `PDF`
66+
iv_attachment_subject = mv_attachment_name
67+
iv_attachment_size = CONV #( xstrlen( lv_xstring ) )
68+
i_attachment_content_hex = cl_bcs_convert=>xstring_to_solix( lv_xstring ) ).
69+
```
70+
71+
::: tip
72+
SAPconnect (`SCOT`) must be configured for the mail to actually leave the system. If you do not see anything in `SOST`, that is where to look first.
73+
:::
74+
75+
#### Compatibility
76+
77+
`cl_bcs_message` is the modern API. On older releases or in ABAP Cloud check what is released for your platform — the structure of the example stays the same, only the API class changes.

docs/development/specific/pdf.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
---
2+
outline: [2, 4]
3+
---
4+
# PDF
5+
6+
Render a PDF directly in your app — for printouts from Adobe Forms, SmartForms, archived documents from the Content Server, or anything else that produces an `xstring`.
7+
8+
#### Built-In Popup
9+
10+
The simplest path is the built-in popup `Z2UI5_CL_POP_PDF`. It expects the PDF as a `data:application/pdf;base64,...` URI and embeds it in an iframe:
11+
12+
```abap
13+
METHOD z2ui5_if_app~main.
14+
15+
CASE abap_true.
16+
17+
WHEN client->check_on_init( ).
18+
client->view_display( z2ui5_cl_xml_view=>factory(
19+
)->page(
20+
)->button(
21+
text = `show PDF`
22+
press = client->_event( `SHOW_PDF` )
23+
)->stringify( ) ).
24+
25+
WHEN client->check_on_event( `SHOW_PDF` ).
26+
"lv_xstring contains the binary PDF — e.g. from cl_fp_function_module=>get_pdf, SmartForm OTF
27+
"conversion, or SELECT FROM the SOFFCONT1 archive
28+
DATA(lv_base64) = cl_web_http_utility=>encode_x_base64( lv_xstring ).
29+
DATA(lo_popup) = z2ui5_cl_pop_pdf=>factory(
30+
i_title = `Invoice 4711`
31+
i_pdf = `data:application/pdf;base64,` && lv_base64 ).
32+
client->nav_app_call( lo_popup ).
33+
34+
ENDCASE.
35+
36+
ENDMETHOD.
37+
```
38+
39+
#### Download Instead of Display
40+
41+
To let the user save the PDF rather than view it inline, use the [file download](./files.md) pattern:
42+
43+
```abap
44+
client->follow_up_action( client->_event_client(
45+
val = client->cs_event-download_b64_file
46+
t_arg = VALUE #( ( `data:application/pdf;base64,` && lv_base64 )
47+
( `invoice_4711.pdf` ) ) ).
48+
```
49+
50+
::: tip
51+
On older ABAP releases without `cl_web_http_utility`, use `cl_http_utility=>if_http_utility~encode_x_base64( lv_xstring )` instead.
52+
:::
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
---
2+
outline: [2, 4]
3+
---
4+
# Value Help
5+
6+
A field that asks *"which one?"* is the F4 moment of ABAP. abap2UI5 covers the basics with two built-in popups and lets you build anything custom on top.
7+
8+
#### Suggestions on the Input
9+
10+
The lightest variant — type-ahead from a bound list, no popup, no roundtrip after the initial render. Bind `suggestionitems` to an internal table and pick the columns via the `suggestion_item` template:
11+
12+
```abap
13+
TYPES: BEGIN OF ty_country,
14+
code TYPE c LENGTH 3,
15+
name TYPE string,
16+
END OF ty_country.
17+
DATA mt_countries TYPE STANDARD TABLE OF ty_country.
18+
DATA mv_country TYPE string.
19+
20+
mt_countries = VALUE #( ( code = `DE` name = `Germany` )
21+
( code = `FR` name = `France` )
22+
( code = `IT` name = `Italy` ) ).
23+
24+
client->view_display( z2ui5_cl_xml_view=>factory(
25+
)->page(
26+
)->input(
27+
value = client->_bind_edit( mv_country )
28+
showsuggestion = abap_true
29+
suggestionitems = client->_bind( mt_countries )
30+
)->suggestion_items(
31+
)->list_item( text = `{CODE}` additionaltext = `{NAME}`
32+
)->stringify( ) ).
33+
```
34+
35+
#### Selection Popup
36+
37+
For a *"pick from this list"* dialog use the built-in `Z2UI5_CL_POP_TO_SELECT`. Pass any internal table, navigate to it as a sub-app, and read the result on return:
38+
39+
```abap
40+
CLASS z2ui5_cl_sample_f4 DEFINITION PUBLIC.
41+
42+
PUBLIC SECTION.
43+
INTERFACES z2ui5_if_app.
44+
DATA mv_carrid TYPE string.
45+
46+
ENDCLASS.
47+
48+
CLASS z2ui5_cl_sample_f4 IMPLEMENTATION.
49+
METHOD z2ui5_if_app~main.
50+
51+
CASE abap_true.
52+
53+
WHEN client->check_on_init( ).
54+
client->view_display( z2ui5_cl_xml_view=>factory(
55+
)->page(
56+
)->input(
57+
value = client->_bind_edit( mv_carrid )
58+
showvaluehelp = abap_true
59+
valuehelprequest = client->_event( `F4` )
60+
)->stringify( ) ).
61+
62+
WHEN client->check_on_event( `F4` ).
63+
SELECT carrid, carrname, url FROM scarr INTO TABLE @DATA(lt_carriers).
64+
client->nav_app_call( z2ui5_cl_pop_to_select=>factory(
65+
i_tab = lt_carriers
66+
i_title = `Choose airline` ) ).
67+
68+
WHEN client->check_on_navigated( ).
69+
DATA(lo_prev) = CAST z2ui5_cl_pop_to_select( client->get_app_prev( ) ).
70+
DATA(ls_res) = lo_prev->result( ).
71+
IF ls_res-check_confirmed = abap_true.
72+
FIELD-SYMBOLS <row> TYPE any.
73+
ASSIGN ls_res-row->* TO <row>.
74+
ASSIGN COMPONENT `CARRID` OF STRUCTURE <row> TO FIELD-SYMBOL(<carrid>).
75+
mv_carrid = <carrid>.
76+
ENDIF.
77+
78+
ENDCASE.
79+
80+
ENDMETHOD.
81+
ENDCLASS.
82+
```
83+
84+
Pass `i_multiselect = abap_true` for multi-pick; the result table is then in `ls_res-table`.
85+
86+
#### DDIC Search Help
87+
88+
For value helps that exist as DDIC search help objects (`SE11` → search help), the [generic search help builder](https://github.com/axelmohnen/a2UI5-generic_search_hlp) wraps the F4 framework so you can fire any standard search help by name and get the picked row back. Install it like any other [add-on](../../resources/addons.md).
89+
90+
#### Custom Dialog
91+
92+
When neither popup fits — e.g. a filter bar with multiple columns, ranges, fuzzy search — build the F4 as a separate app with its own view and call it via `nav_app_call`. See [Popup → Separated App](../popups/popup.md#separated-app) for the pattern.
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
---
2+
outline: [2, 4]
3+
---
4+
# WebSocket
5+
6+
Stateless roundtrips are fine for click-driven UIs, but some scenarios need the server to *push* — a news feed, a job-status indicator, a chat. abap2UI5 has no special API for this; you use SAP's standard WebSocket stack and feed the messages into the rendered view via custom JavaScript.
7+
8+
The building blocks:
9+
10+
| Layer | Purpose |
11+
|---|---|
12+
| **APC** (Application Push Channel, `SAPC`) | Exposes the WebSocket endpoint over HTTP/S |
13+
| **AMC** (Application Messaging Channel, `SAMC`) | In-system pub/sub — any ABAP code can broadcast into a channel |
14+
| **Custom JS** in the view | Opens the socket, dispatches incoming messages |
15+
16+
Once both channels are configured, any `COMMIT WORK` that fires an AMC publish reaches every connected browser within milliseconds — no polling, no timer.
17+
18+
#### Server Side
19+
20+
An APC class extending `cl_apc_wsp_ext_stateless_base` binds an AMC consumer when a client connects, so AMC messages are forwarded to that socket. Broadcasting is then a one-liner from anywhere in the system:
21+
22+
```abap
23+
DATA(lo_producer) = cl_amc_channel_manager=>create_message_producer(
24+
i_application_id = `Z2UI5_SAMPLE`
25+
i_channel_id = `/news_feed` ).
26+
lo_producer->send( i_message = `New order arrived` ).
27+
```
28+
29+
A full reference implementation lives in the samples repo — `Z2UI5_CL_DEMO_APP_S_05_WS` for the APC handler and `Z2UI5_CL_DEMO_APP_S_05` for the consuming app.
30+
31+
#### Client Side
32+
33+
The browser opens the socket via [Custom JavaScript](../../advanced/extensibility/custom_js.md) embedded in the view. The connection stays open across normal abap2UI5 roundtrips — incoming messages can update a model, trigger a toast, or fire an abap2UI5 event to pull fresh data from the backend:
34+
35+
```js
36+
const ws = new WebSocket("wss://" + window.location.host + "/sap/bc/apc/sap/z2ui5_sample");
37+
ws.onmessage = (e) => {
38+
sap.m.MessageToast.show(e.data);
39+
};
40+
```
41+
42+
#### When to Reach For It
43+
44+
WebSockets cost a permanent connection per user — comparable to a stateful session in resource terms. Use them when push really matters:
45+
46+
- live dashboards, monitoring screens
47+
- multi-user collaboration (chat, shared editing)
48+
- long-running background jobs reporting status
49+
50+
For *"refresh every few seconds"* the [Timer](./timer.md) is cheaper and simpler.
51+
52+
::: warning
53+
APC/AMC are not available on every ABAP platform — check release notes for your system (ABAP Cloud, S/4 Public Cloud, BTP ABAP Environment) before designing around them.
54+
:::

0 commit comments

Comments
 (0)