From cf1d67bbcc3b668fe860222054bc9daf57a93118 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 21 Aug 2026 09:51:28 +0000 Subject: [PATCH] Grow the walkthrough to ten steps and fold Full Example into it Full Example was a step-by-step tutorial living outside the tutorial. It is now inside it: the two things it taught that the walkthrough did not became steps of their own, and the page is gone. Step 8 Selection Screen - a SimpleForm with DatePickers over the list, a Read button, and the SELECT the reader would write in their own system as the comment above the demo data Step 9 Tables - sap.m.List becomes sap.m.Table: columns, cells, the end( ) that makes the next Column a sibling, and a row action in a 10%-wide column of its own Step 10 App Structure - what was step 8, now assembling all of it: dispatcher, named methods, data_read / data_update as the only places a SELECT or an UPDATE appears, and the back button One overview page, not two. The walkthrough's Introduction folded into the Tutorial overview - a section whose landing page is followed by a second landing page makes the reader click twice to reach step 1. Hello World gains a second example rather than losing its content: the message-box class, then a class with a view, a bound input and an event - the whole shape of an app on one page - and the developer tools, which are too useful to be three clicks away. What it does NOT do any more is explain all of it; that is what the walkthrough is for, and the page says so and links there. Also, from reading it over: - Tutorials -> Tutorial in the nav and the sidebar - step 1 is "The App Class"; "Hello World" was standing twice, once per section, meaning two different things - the Walkthrough group has no `collapsed` key at all, like Quickstart: that is what makes a group a plain list rather than a foldable one - Getting Started's "Introduction" is "In a Nutshell" - the page is an elevator pitch with a Hello World in it, not a preface - Tooling moves to Advanced Topics > Developer Setup. Which editor and client tooling you develop WITH is not a question a newcomer has yet The AI page is rewritten from the other end. It opened by explaining what a model gets wrong; it now opens with why abap2UI5 suits an agent in the first place - one class and no generated services, an app that is text end to end, hundreds of tested samples to copy from, and a linter that verifies the result with no SAP system. The frozen-builder framing is out of the page, prompt included. Verified in a playground built from source: all ten steps and both Hello World classes carry a Run button, all ten start and render, and the behaviour each page promises was driven - the toast, the bound greeting, the five rows, the row-specific event, the supplier filter reaching the read, the table's four headers and its row action, the dialog editing the clicked row, Save updating the table and Cancel leaving it alone. The preview image is the finished app, recaptured. Gates green in both repositories; the samples pairing holds in both directions (47 pages, 118 links). Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01PwxPfiy5WE8fVxfnToFeWk --- docs/.vitepress/config.mjs | 46 +- docs/.vitepress/playground.mjs | 2 +- docs/cookbook/event_navigation/life_cycle.md | 6 +- .../troubleshooting/common_failures.md | 2 +- docs/get_started/about.md | 2 +- docs/get_started/ai.md | 50 +- docs/get_started/full_example.md | 580 ------------------ docs/get_started/hello_world.md | 73 ++- docs/public/tutorials/walkthrough-preview.png | Bin 37760 -> 65128 bytes docs/tutorials/overview.md | 66 +- docs/tutorials/walkthrough/overview.md | 45 -- docs/tutorials/walkthrough/step-1.md | 4 +- docs/tutorials/walkthrough/step-10.md | 316 ++++++++++ docs/tutorials/walkthrough/step-2.md | 11 +- docs/tutorials/walkthrough/step-8.md | 257 ++++---- docs/tutorials/walkthrough/step-9.md | 190 ++++++ 16 files changed, 809 insertions(+), 841 deletions(-) delete mode 100644 docs/get_started/full_example.md delete mode 100644 docs/tutorials/walkthrough/overview.md create mode 100644 docs/tutorials/walkthrough/step-10.md create mode 100644 docs/tutorials/walkthrough/step-9.md diff --git a/docs/.vitepress/config.mjs b/docs/.vitepress/config.mjs index 7f0bc354..f4ff492a 100644 --- a/docs/.vitepress/config.mjs +++ b/docs/.vitepress/config.mjs @@ -123,7 +123,7 @@ export default defineConfig({ // The section is called Getting Started in the sidebar this opens; // "Introduction" was the first PAGE in it, one level down. { text: "Getting Started", link: "/get_started/about" }, // nav - { text: "Tutorials", link: "/tutorials/overview" }, // nav + { text: "Tutorial", link: "/tutorials/overview" }, // nav { text: "Cookbook", link: "/cookbook/view/definition" }, { text: "Configuration", link: "/configuration/setup" }, // Technical Insight is not a line of its own here any more: it is a @@ -179,7 +179,7 @@ export default defineConfig({ link: "/get_started/about", collapsed: true, items: [ - { text: "Introduction", link: "/get_started/about" }, // sidebar + { text: "In a Nutshell", link: "/get_started/about" }, // sidebar { // Install it, and see one app run. The step-by-step tutorials - // Full Example among them - are a section of their own now; what @@ -190,8 +190,7 @@ export default defineConfig({ { text: "Hello World", link: "/get_started/hello_world" }, ], }, - { text: "Tooling", link: "/get_started/tooling" }, - { text: "Building with AI", link: "/get_started/ai" }, + { text: "Developing with AI", link: "/get_started/ai" }, { text: `What's Next?`, link: "/get_started/next" }, ], }, @@ -199,39 +198,37 @@ export default defineConfig({ // Between Getting Started and the Cookbook on purpose: a tutorial is // read after the framework is installed and before the reference // chapters, and that is the order the three sections stand in. - text: "Tutorials", + text: "Tutorial", link: "/tutorials/overview", collapsed: true, items: [ { text: "Overview", link: "/tutorials/overview" }, // sidebar { - // NOT collapsed: the eight steps are the section's content, and a - // reader who is working through them needs to see where they are - // in the sequence on every page. A tutorial whose steps are behind - // one more click reads as a single page that happens to be long. + // No `collapsed` key at all, like Quickstart above: that is what + // makes a group a plain labelled list instead of a collapsible + // one. `collapsed: false` would still render the toggle and still + // let the steps be folded away - and the sequence IS the tutorial, + // so a reader working through it has to see where they are on + // every page. text: "Walkthrough", - link: "/tutorials/walkthrough/overview", - collapsed: false, items: [ - { text: "Introduction", link: "/tutorials/walkthrough/overview" }, // sidebar - { text: "1. Hello World", link: "/tutorials/walkthrough/step-1" }, + { text: "1. The App Class", link: "/tutorials/walkthrough/step-1" }, { text: "2. A First View", link: "/tutorials/walkthrough/step-2" }, { text: "3. Events", link: "/tutorials/walkthrough/step-3" }, { text: "4. Data Binding", link: "/tutorials/walkthrough/step-4" }, { text: "5. List Binding", link: "/tutorials/walkthrough/step-5" }, { text: "6. Row Events", link: "/tutorials/walkthrough/step-6" }, { text: "7. Popups", link: "/tutorials/walkthrough/step-7" }, - { text: "8. App Structure", link: "/tutorials/walkthrough/step-8" }, + { text: "8. Selection Screen", link: "/tutorials/walkthrough/step-8" }, + { text: "9. Tables", link: "/tutorials/walkthrough/step-9" }, + { text: "10. App Structure", link: "/tutorials/walkthrough/step-10" }, ], }, - // Both keep the URL they were published under - only the entry that - // navigates to them moved. Full Example is a step-by-step tutorial - // ("Step 1" to "Step 5") and was the second half of a Quickstart - // group that no longer had a tutorial section to hand it to; the - // Cheat Sheet is the sheet you keep open WHILE working through one. - // Neither is listed twice: an entry standing in two sidebar sections - // makes its own search results ambiguous. - { text: "Full Example", link: "/get_started/full_example" }, + // The sheet you keep open WHILE working through the steps. It keeps + // the URL it was published under - only the entry that navigates to + // it moved out of the Cookbook, and it is not listed twice: an entry + // standing in two sidebar sections makes its own search results + // ambiguous. { text: "Cheat Sheet", link: "/cookbook/cheat_sheet" }, ], }, @@ -517,6 +514,11 @@ export default defineConfig({ text: "Developer Setup", collapsed: true, items: [ + // Moved out of Getting Started: which editor, transpiler and + // client tools you develop WITH is a question a newcomer does + // not have yet, and on the entry path it read as a required + // step. It belongs next to the local setup it describes. + { text: "Tooling", link: "/get_started/tooling" }, { text: "Local Setup", link: "/advanced/local" }, { text: "Project Tools", diff --git a/docs/.vitepress/playground.mjs b/docs/.vitepress/playground.mjs index ecd98289..fdb040ac 100644 --- a/docs/.vitepress/playground.mjs +++ b/docs/.vitepress/playground.mjs @@ -107,7 +107,7 @@ const NEEDS_MORE_THAN_A_BROWSER = [ * ABAP with its comments taken out and its text blanked, so a rule can only be * tripped by code. Both halves were put here by a false positive: * - * - `get_started/full_example.md` shows the SELECT a reader would write, as a + * - `tutorials/walkthrough/step-10.md` shows the SELECT a reader would write, as a * comment, above the demo data it uses instead — and it runs perfectly * well. * - `clipboard.md` says `mv_text = \`Hello from abap2UI5\``, and a rule diff --git a/docs/cookbook/event_navigation/life_cycle.md b/docs/cookbook/event_navigation/life_cycle.md index ff87256c..341256b9 100644 --- a/docs/cookbook/event_navigation/life_cycle.md +++ b/docs/cookbook/event_navigation/life_cycle.md @@ -45,13 +45,13 @@ CLASS z2ui5_cl_demo_app_001 IMPLEMENTATION. ENDCLASS. ``` -Whether you dispatch with `CASE abap_true` (as above) or with an equivalent `IF` / `ELSEIF` chain (as the [Hello World](/get_started/hello_world) and [Full Example](/get_started/full_example) tutorials do) is a matter of taste — the structure is what counts. Three things make this the recommended shape: +Whether you dispatch with `CASE abap_true` (as above) or with an equivalent `IF` / `ELSEIF` chain (as the [Hello World](/get_started/hello_world) page and the first steps of the [Walkthrough](/tutorials/overview) do) is a matter of taste — the structure is what counts. Three things make this the recommended shape: 1. **Store `client` on `me->client`** so handler methods can use it without passing it around. -2. **Dispatch by event name** — `` check_on_event( `POST` ) `` rather than a generic `` CASE client->get( )-event `` with a second dispatch level. Each event gets its own `WHEN`. (With many events or extracted handler methods, the `CASE client->get( )-event` form is a fine alternative — the [Full Example](/get_started/full_example) uses it.) +2. **Dispatch by event name** — `` check_on_event( `POST` ) `` rather than a generic `` CASE client->get( )-event `` with a second dispatch level. Each event gets its own `WHEN`. (With many events or extracted handler methods, the `CASE client->get( )-event` form is a fine alternative — the walkthrough's [last step](/tutorials/walkthrough/step-10) uses it.) 3. **One render method per view** — call it from any `WHEN` that should rebuild the screen (`check_on_init`, after a search, after a navigation return). Event handlers that only mutate state and reuse the existing view (a button press inside a popup, a toast) skip it — see [The View Is Only Sent When You Call `view_display`](#the-view-is-only-sent-when-you-call-view-display) below. -For a tiny app with one or two events, inline the view and the handler directly in the `WHEN` branches and skip the handler methods entirely. [Hello World](/get_started/hello_world) shows this variant; [Full Example](/get_started/full_example) shows the full version with multiple handler methods, a popup, and persistence. Both follow the same pattern — only the amount of code inside each branch differs. +For a tiny app with one or two events, inline the view and the handler directly in the `WHEN` branches and skip the handler methods entirely. [Hello World](/get_started/hello_world) shows this variant; the walkthrough's [last step](/tutorials/walkthrough/step-10) shows the full version with multiple handler methods, a popup, and persistence. Both follow the same pattern — only the amount of code inside each branch differs. ## Lifecycle Pitfalls diff --git a/docs/cookbook/troubleshooting/common_failures.md b/docs/cookbook/troubleshooting/common_failures.md index 28950ad7..9d49cbdb 100644 --- a/docs/cookbook/troubleshooting/common_failures.md +++ b/docs/cookbook/troubleshooting/common_failures.md @@ -94,7 +94,7 @@ Where to look: - **Symptom**: a button on the main page "does nothing" right after a popup workflow, or a second open reopens the same popup on top of the first. - **Pair every `popup_display( )` with an explicit `popup_destroy( )`** in **every** branch that ends the dialog — Save and Cancel both need it, not just the happy path. -See [Popup](/cookbook/popup_popover/popup) and the worked example in [Full Example](/get_started/full_example). +See [Popup](/cookbook/popup_popover/popup) and the worked example in the walkthrough's [Popups step](/tutorials/walkthrough/step-7). ## Event-Name Casing Mismatch diff --git a/docs/get_started/about.md b/docs/get_started/about.md index d7144506..ba8abaf2 100644 --- a/docs/get_started/about.md +++ b/docs/get_started/about.md @@ -1,7 +1,7 @@ --- outline: [2, 4] --- -# Introduction +# In a Nutshell **Build UI5 Apps Purely in ABAP** diff --git a/docs/get_started/ai.md b/docs/get_started/ai.md index bce600b0..9c73d6d9 100644 --- a/docs/get_started/ai.md +++ b/docs/get_started/ai.md @@ -1,34 +1,46 @@ --- outline: [2, 4] --- -# Building with AI - -An AI assistant writing abap2UI5 starts at a disadvantage nothing about your -project causes. Almost every abap2UI5 example on the public web builds its view -with `z2ui5_cl_xml_view`, the frozen predecessor of -`z2ui5_cl_ui5_view_builder` — so that is what a model writes when asked for an -app, confidently, and in an API that is no longer the one to use. - -Everything below is a way of telling it otherwise, in rising order of effort. +# Developing with AI + +abap2UI5 is unusually well suited to being written by an AI assistant, and the +reason is structural rather than lucky: + +- **An app is one ABAP class — source code, and nothing else.** No service to + generate, no OData artifacts, no frontend project, no manifest, no + deployment pipeline. There is exactly one file for an agent to write, and + the thing it writes is the thing that runs. +- **The whole app is text.** View, logic, state and data flow live in the same + class, in one language. An agent never has to keep an ABAP backend and a + JavaScript frontend in step, because there is no second half to drift. +- **There are hundreds of working examples to learn from.** The three sample + catalogues hold complete, tested apps — one per pattern, every one linted and + rendered — so "has somebody already built a value help, a tree, navigation + between two apps?" is a question with a real answer instead of a guess. +- **The result can be checked without an SAP system.** The + [abap2UI5 linter](/advanced/linter) reconstructs the UI5 view out of the ABAP + that builds it and reports what UI5 does not have. An agent that can verify + its own work stops handing you apps that do not render. + +Everything below turns those properties into a setup, in rising order of +effort. Start at the top; each level is useful on its own. ## Paste the essentials The zero-setup version, for any assistant with web access: paste this ahead of -your task. It corrects the four things a model most reliably gets wrong about -abap2UI5: +your task. ```text Before writing any abap2UI5 code, read https://abap2ui5.github.io/docs/llms.txt and follow it to the pages you need. -Four things that override whatever you remember about abap2UI5: +The shape of an abap2UI5 app: 1. An app is ONE ABAP class implementing z2ui5_if_app. Everything enters main( ), which dispatches on client->check_on_navigated( ) (the display branch, true on first start too), client->check_on_event( `X` ) and - for one-time setup only - client->check_on_init( ). 2. Build the view with z2ui5_cl_ui5_view_builder and its verbs ele / tag / a / end / - stringify. z2ui5_cl_xml_view is the FROZEN predecessor - it is what most examples - online show, and it is not what to write. + stringify. 3. Bind with client->_bind( ). It is bidirectional; only what the user edited comes back. 4. Every roundtrip is a fresh ABAP session. Nothing survives on the server except the app class itself, which is serialized. @@ -51,9 +63,9 @@ questions: | [`abap2ui5.github.io/docs/llms.txt`](https://abap2ui5.github.io/docs/llms.txt) | the map of the **prose** — every chapter of this site with one line of what it covers, and [`llms-full.txt`](https://abap2ui5.github.io/docs/llms-full.txt) for all of it in one fetch | | [`github.com/abap2UI5/abap2UI5/llms.txt`](https://github.com/abap2UI5/abap2UI5/blob/main/llms.txt) | the map of the **code** — the interface files to read instead of guessing at a signature, and the guide for building apps that ships with the framework | -Both are short and both are free to give an assistant that has web access. It -is the cheapest correction available: an agent that has read either one does -not reach for the frozen builder. +Both are short and both are free to give an assistant that has web access. +This is the cheapest step on the page: an agent that has read either one is +working from what abap2UI5 is today rather than from what it recalls. ## Put the conventions in the repository @@ -79,8 +91,8 @@ npm run check The [abap2UI5 linter](/advanced/linter) half is the one that matters here: it reconstructs the view from the builder chain and reports the names UI5 -does not have, the bindings that point at nothing — and a class still built on -the frozen builder. +does not have, the properties that do not exist on the release you target, and +the bindings that point at nothing. ## Give it the loop diff --git a/docs/get_started/full_example.md b/docs/get_started/full_example.md deleted file mode 100644 index f82b5ff0..00000000 --- a/docs/get_started/full_example.md +++ /dev/null @@ -1,580 +0,0 @@ ---- -outline: [2, 4] -samples: - - z2ui5_cl_smp_app_070 - - z2ui5_cl_smp_app_011 ---- -# Full Example - - -This tutorial walks through a complete app that follows a typical ABAP flow: a small selection screen, reading data from the database, showing the result in a table, opening a popup to edit a row, and posting the changes back. It ties together everything from the [Hello World](/get_started/hello_world) page and shows how the pieces fit into a real screen. - -The example uses sales-order-like data but keeps the SELECTs and updates as plain ABAP so you can adapt them to your own tables. Drop the class into your system and launch it the same way as the Hello World app. - -## What You Will Build - -1. **Selection screen** — date range and a customer filter. -2. **Read data** — fetch matching orders into an internal table on button press. -3. **Result table** — show the orders, with one row editable via popup. -4. **Popup** — open a dialog that lets the user change the delivery date. -5. **Post** — confirm in the popup, write the change back, refresh the table. - -## Tutorial - -### Step 1 — State: Types and Attributes - -The whole app is one class. Public attributes hold everything the framework needs to remember between roundtrips: the selection criteria, the order table, and the row currently being edited. abap2UI5 serializes and restores them automatically — no session handling on your side. - -```abap -CLASS zcl_app_full_example DEFINITION PUBLIC. - - PUBLIC SECTION. - INTERFACES z2ui5_if_app. - - TYPES: - BEGIN OF ty_s_order, - order_id TYPE string, - customer TYPE string, - order_date TYPE string, - delivery_date TYPE string, - END OF ty_s_order. - - DATA: - BEGIN OF s_search, - date_from TYPE string, - date_to TYPE string, - customer TYPE string, - END OF s_search. - - DATA t_orders TYPE STANDARD TABLE OF ty_s_order WITH EMPTY KEY. - DATA s_edit TYPE ty_s_order. - - PROTECTED SECTION. - DATA client TYPE REF TO z2ui5_if_client. - - METHODS on_event. - METHODS view_display. - METHODS popup_edit_display. - METHODS data_read. - METHODS data_update. - - PRIVATE SECTION. -ENDCLASS. -``` - -The `main` method is a pure dispatcher — the same pattern as in [Hello World](/get_started/hello_world), just with the branches extracted into methods. We stash `client` in a protected attribute first, so the handler methods below can use it without passing it around: - -```abap - METHOD z2ui5_if_app~main. - - me->client = client. - IF client->check_on_navigated( ). - view_display( ). - ELSEIF client->check_on_event( ). - on_event( ). - ENDIF. - - ENDMETHOD. -``` - -### Step 2 — The View: Selection Screen and Table - -`view_display` builds the entire screen: a form with the selection criteria on top and the result table below. It is called exactly once, on the first roundtrip — every later interaction only updates data on this view. - -Two things are new compared to Hello World: `shell( )` wraps the page in the standard UI5 app frame, and the `navbuttonpress` / `shownavbutton` parameters add a back button when the app was called from another app (details under [Navigation](/cookbook/event_navigation/navigation)). Further down, `get_parent( )` moves one level back up in the builder tree, so the next `column( )` becomes a sibling instead of a child — see [View → Definition](/cookbook/view/definition). - -The two date pickers and the customer input are bound with `_bind`, so whatever the user types travels back to the ABAP attributes automatically. The table is bound with `_bind` too; since its cells are display-only, nothing syncs back: - -```abap - METHOD view_display. - - DATA(view) = z2ui5_cl_ui5_view_builder=>factory( - )->ele( n = `View` ns = `mvc` - )->a( n = `xmlns` v = `sap.m` - )->a( n = `xmlns:mvc` v = `sap.ui.core.mvc` - )->a( n = `xmlns:form` v = `sap.ui.layout.form` ). - - DATA(page) = view->ele( `Shell` - )->ele( `Page` - )->a( n = `title` v = `abap2UI5 - Full Example` - )->a( n = `navButtonPress` v = client->_event_nav_app_leave( ) - )->a( n = `showNavButton` b = client->check_app_prev_stack( ) ). - - page->ele( n = `SimpleForm` ns = `form` - )->a( n = `title` v = `Order Selection` - )->a( n = `editable` v = `true` - - )->ele( n = `content` ns = `form` - - )->tag( `Label` - )->a( n = `text` v = `Order Date From` - )->tag( `DatePicker` - )->a( n = `value` v = client->_bind( s_search-date_from ) - )->a( n = `valueFormat` v = `yyyy-MM-dd` - )->tag( `Label` - )->a( n = `text` v = `Order Date To` - )->tag( `DatePicker` - )->a( n = `value` v = client->_bind( s_search-date_to ) - )->a( n = `valueFormat` v = `yyyy-MM-dd` - )->tag( `Label` - )->a( n = `text` v = `Customer` - )->tag( `Input` - )->a( n = `value` v = client->_bind( s_search-customer ) - )->tag( `Button` - )->a( n = `text` v = `Read Orders` - )->a( n = `press` v = client->_event( `READ` ) ). - - DATA(tab) = page->ele( `Table` - )->a( n = `items` v = client->_bind( t_orders ) ). - - tab->ele( `columns` - - )->ele( `Column` - )->tag( `Text` - )->a( n = `text` v = `Order` - - )->end( - )->ele( `Column` - )->tag( `Text` - )->a( n = `text` v = `Customer` - - )->end( - )->ele( `Column` - )->tag( `Text` - )->a( n = `text` v = `Order Date` - - )->end( - )->ele( `Column` - )->tag( `Text` - )->a( n = `text` v = `Delivery Date` - - )->end( - )->ele( `Column` - )->a( n = `width` v = `10%` ). - - tab->ele( `items` - )->ele( `ColumnListItem` - )->ele( `cells` - - )->tag( `Text` - )->a( n = `text` v = `{ORDER_ID}` - )->tag( `Text` - )->a( n = `text` v = `{CUSTOMER}` - )->tag( `Text` - )->a( n = `text` v = `{ORDER_DATE}` - )->tag( `Text` - )->a( n = `text` v = `{DELIVERY_DATE}` - )->tag( `Button` - )->a( n = `icon` v = `sap-icon://edit` - )->a( n = `tooltip` v = `Edit delivery date` - )->a( n = `press` v = client->_event( val = `EDIT` - t_arg = VALUE #( ( `${ORDER_ID}` ) ) ) ). - - client->view_display( view->stringify( ) ). - - ENDMETHOD. -``` - -Two details worth a second look: - -- **Cell bindings** like `{ORDER_ID}` are plain UI5 binding paths relative to the table row — the framework maps the ABAP field names for you. -- **The edit button** sends the row's key along with the event: ``t_arg = VALUE #( ( `${ORDER_ID}` ) )``. The `${...}` syntax is resolved *per row* in the browser, so the backend later knows exactly which order was clicked. -- **The fifth column** has no header text and a fixed `10%` width — it only holds the edit button defined in the row cells. - -### Step 3 — Reading Data - -When the user presses **Read Orders**, the `READ` event arrives in `on_event`. Reading is plain ABAP — in a real system this is a `SELECT` on your own tables; the tutorial fakes it with demo data and applies the selection criteria the same way a `WHERE` clause would: - -```abap - METHOD data_read. - - " demo data — in your system, replace this with a SELECT, e.g.: - " SELECT order_id, customer, order_date, delivery_date - " FROM zsd_order - " WHERE order_date BETWEEN @s_search-date_from AND @s_search-date_to - " INTO TABLE @t_orders. - t_orders = VALUE #( - ( order_id = `1000` customer = `Ace Manufacturing` order_date = `2026-05-04` delivery_date = `2026-07-15` ) - ( order_id = `1001` customer = `Bright Retail` order_date = `2026-05-12` delivery_date = `2026-07-20` ) - ( order_id = `1002` customer = `Ace Manufacturing` order_date = `2026-06-01` delivery_date = `2026-08-01` ) - ( order_id = `1003` customer = `Corner Logistics` order_date = `2026-06-18` delivery_date = `2026-08-10` ) ). - - IF s_search-date_from IS NOT INITIAL. - DELETE t_orders WHERE order_date < s_search-date_from. - ENDIF. - - IF s_search-date_to IS NOT INITIAL. - DELETE t_orders WHERE order_date > s_search-date_to. - ENDIF. - - IF s_search-customer IS NOT INITIAL. - " NS = `contains no string` — remove rows whose customer does not contain the filter text - DELETE t_orders WHERE customer NS s_search-customer. - ENDIF. - - ENDMETHOD. -``` - -Back in `on_event`, note what is **not** there: no second `view_display( )`. -The view already exists in the browser and only the data changed, so the -framework sends the new model by itself — every roundtrip that changed -something bound pushes it. There is nothing to call: - -```abap - WHEN `READ`. - data_read( ). -``` - -::: tip You may see `client->view_model_update( )` in older code -It still compiles, and it still does nothing: the method is deliberately -empty, because the model push is queued by the framework rather than asked -for. Leaving it in is harmless; writing it in new code teaches a step that -does not exist. -::: - -### Step 4 — The Edit Popup - -Pressing the edit icon fires the `EDIT` event, and `client->get_event_arg( )` returns the `ORDER_ID` we attached to the button in Step 2. The handler copies the matching row into `s_edit` and opens the dialog: - -```abap - WHEN `EDIT`. - s_edit = VALUE #( t_orders[ order_id = client->get_event_arg( ) ] OPTIONAL ). - popup_edit_display( ). -``` - -A popup is built exactly like the main view — same builder, same verbs. The only differences are the root element (`core:FragmentDefinition` instead of `mvc:View`) and that it is handed to `popup_display( )`. The main view stays untouched in the background: - -```abap - METHOD popup_edit_display. - - DATA(popup) = z2ui5_cl_ui5_view_builder=>factory( - )->ele( n = `FragmentDefinition` ns = `core` - )->a( n = `xmlns` v = `sap.m` - )->a( n = `xmlns:core` v = `sap.ui.core` - )->a( n = `xmlns:form` v = `sap.ui.layout.form` ). - - DATA(dialog) = popup->ele( `Dialog` - )->a( n = `title` v = |Order { s_edit-order_id } - { s_edit-customer }| ). - - dialog->ele( n = `SimpleForm` ns = `form` - )->a( n = `editable` v = `true` - - )->ele( n = `content` ns = `form` - - )->tag( `Label` - )->a( n = `text` v = `Delivery Date` - )->tag( `DatePicker` - )->a( n = `value` v = client->_bind( s_edit-delivery_date ) - )->a( n = `valueFormat` v = `yyyy-MM-dd` ). - - dialog->ele( `buttons` - - )->tag( `Button` - )->a( n = `text` v = `Cancel` - )->a( n = `press` v = client->_event( `CANCEL` ) - )->tag( `Button` - )->a( n = `text` v = `Post` - )->a( n = `press` v = client->_event( `POST` ) - )->a( n = `type` v = `Emphasized` ). - - client->popup_display( popup->stringify( ) ). - - ENDMETHOD. -``` - -The date picker in the dialog binds to `s_edit-delivery_date` with `_bind` — when the user picks a new date, the attribute is already updated by the time the next event reaches your ABAP code. - -### Step 5 — Posting the Change - -**Post** writes the change back, closes the popup, and refreshes the table — again without rebuilding the view. **Cancel** just closes the popup: - -```abap - WHEN `POST`. - data_update( ). - client->popup_destroy( ). - client->message_toast_display( |Delivery date of order { s_edit-order_id } updated.| ). - WHEN `CANCEL`. - client->popup_destroy( ). -``` - -Updating is plain ABAP once more — the tutorial changes the internal table, a real app runs an `UPDATE`: - -```abap - METHOD data_update. - - " in your system, persist the change with an UPDATE, e.g.: - " UPDATE zsd_order SET delivery_date = @s_edit-delivery_date - " WHERE order_id = @s_edit-order_id. - t_orders[ order_id = s_edit-order_id ]-delivery_date = s_edit-delivery_date. - - ENDMETHOD. -``` - -### The Complete Class - -Copy this into your system and launch it like the Hello World app: - -::: details Full source code -```abap -CLASS zcl_app_full_example DEFINITION PUBLIC. - - PUBLIC SECTION. - INTERFACES z2ui5_if_app. - - TYPES: - BEGIN OF ty_s_order, - order_id TYPE string, - customer TYPE string, - order_date TYPE string, - delivery_date TYPE string, - END OF ty_s_order. - - DATA: - BEGIN OF s_search, - date_from TYPE string, - date_to TYPE string, - customer TYPE string, - END OF s_search. - - DATA t_orders TYPE STANDARD TABLE OF ty_s_order WITH EMPTY KEY. - DATA s_edit TYPE ty_s_order. - - PROTECTED SECTION. - DATA client TYPE REF TO z2ui5_if_client. - - METHODS on_event. - METHODS view_display. - METHODS popup_edit_display. - METHODS data_read. - METHODS data_update. - - PRIVATE SECTION. -ENDCLASS. - - -CLASS zcl_app_full_example IMPLEMENTATION. - - METHOD z2ui5_if_app~main. - - me->client = client. - IF client->check_on_navigated( ). - view_display( ). - ELSEIF client->check_on_event( ). - on_event( ). - ENDIF. - - ENDMETHOD. - - - METHOD on_event. - - " client->get( )-event holds the name passed to _event( ); - " get_event_arg( ) returns the extra argument attached via t_arg - CASE client->get( )-event. - WHEN `READ`. - data_read( ). - WHEN `EDIT`. - s_edit = VALUE #( t_orders[ order_id = client->get_event_arg( ) ] OPTIONAL ). - popup_edit_display( ). - WHEN `POST`. - data_update( ). - client->popup_destroy( ). - client->message_toast_display( |Delivery date of order { s_edit-order_id } updated.| ). - WHEN `CANCEL`. - client->popup_destroy( ). - ENDCASE. - - ENDMETHOD. - - - METHOD view_display. - - DATA(view) = z2ui5_cl_ui5_view_builder=>factory( - )->ele( n = `View` ns = `mvc` - )->a( n = `xmlns` v = `sap.m` - )->a( n = `xmlns:mvc` v = `sap.ui.core.mvc` - )->a( n = `xmlns:form` v = `sap.ui.layout.form` ). - - DATA(page) = view->ele( `Shell` - )->ele( `Page` - )->a( n = `title` v = `abap2UI5 - Full Example` - )->a( n = `navButtonPress` v = client->_event_nav_app_leave( ) - )->a( n = `showNavButton` b = client->check_app_prev_stack( ) ). - - page->ele( n = `SimpleForm` ns = `form` - )->a( n = `title` v = `Order Selection` - )->a( n = `editable` v = `true` - - )->ele( n = `content` ns = `form` - - )->tag( `Label` - )->a( n = `text` v = `Order Date From` - )->tag( `DatePicker` - )->a( n = `value` v = client->_bind( s_search-date_from ) - )->a( n = `valueFormat` v = `yyyy-MM-dd` - )->tag( `Label` - )->a( n = `text` v = `Order Date To` - )->tag( `DatePicker` - )->a( n = `value` v = client->_bind( s_search-date_to ) - )->a( n = `valueFormat` v = `yyyy-MM-dd` - )->tag( `Label` - )->a( n = `text` v = `Customer` - )->tag( `Input` - )->a( n = `value` v = client->_bind( s_search-customer ) - )->tag( `Button` - )->a( n = `text` v = `Read Orders` - )->a( n = `press` v = client->_event( `READ` ) ). - - DATA(tab) = page->ele( `Table` - )->a( n = `items` v = client->_bind( t_orders ) ). - - tab->ele( `columns` - - )->ele( `Column` - )->tag( `Text` - )->a( n = `text` v = `Order` - - )->end( - )->ele( `Column` - )->tag( `Text` - )->a( n = `text` v = `Customer` - - )->end( - )->ele( `Column` - )->tag( `Text` - )->a( n = `text` v = `Order Date` - - )->end( - )->ele( `Column` - )->tag( `Text` - )->a( n = `text` v = `Delivery Date` - - )->end( - )->ele( `Column` - )->a( n = `width` v = `10%` ). - - tab->ele( `items` - )->ele( `ColumnListItem` - )->ele( `cells` - - )->tag( `Text` - )->a( n = `text` v = `{ORDER_ID}` - )->tag( `Text` - )->a( n = `text` v = `{CUSTOMER}` - )->tag( `Text` - )->a( n = `text` v = `{ORDER_DATE}` - )->tag( `Text` - )->a( n = `text` v = `{DELIVERY_DATE}` - )->tag( `Button` - )->a( n = `icon` v = `sap-icon://edit` - )->a( n = `tooltip` v = `Edit delivery date` - )->a( n = `press` v = client->_event( val = `EDIT` - t_arg = VALUE #( ( `${ORDER_ID}` ) ) ) ). - - client->view_display( view->stringify( ) ). - - ENDMETHOD. - - - METHOD popup_edit_display. - - DATA(popup) = z2ui5_cl_ui5_view_builder=>factory( - )->ele( n = `FragmentDefinition` ns = `core` - )->a( n = `xmlns` v = `sap.m` - )->a( n = `xmlns:core` v = `sap.ui.core` - )->a( n = `xmlns:form` v = `sap.ui.layout.form` ). - - DATA(dialog) = popup->ele( `Dialog` - )->a( n = `title` v = |Order { s_edit-order_id } - { s_edit-customer }| ). - - dialog->ele( n = `SimpleForm` ns = `form` - )->a( n = `editable` v = `true` - - )->ele( n = `content` ns = `form` - - )->tag( `Label` - )->a( n = `text` v = `Delivery Date` - )->tag( `DatePicker` - )->a( n = `value` v = client->_bind( s_edit-delivery_date ) - )->a( n = `valueFormat` v = `yyyy-MM-dd` ). - - dialog->ele( `buttons` - - )->tag( `Button` - )->a( n = `text` v = `Cancel` - )->a( n = `press` v = client->_event( `CANCEL` ) - )->tag( `Button` - )->a( n = `text` v = `Post` - )->a( n = `press` v = client->_event( `POST` ) - )->a( n = `type` v = `Emphasized` ). - - client->popup_display( popup->stringify( ) ). - - ENDMETHOD. - - - METHOD data_read. - - " demo data — in your system, replace this with a SELECT, e.g.: - " SELECT order_id, customer, order_date, delivery_date - " FROM zsd_order - " WHERE order_date BETWEEN @s_search-date_from AND @s_search-date_to - " INTO TABLE @t_orders. - t_orders = VALUE #( - ( order_id = `1000` customer = `Ace Manufacturing` order_date = `2026-05-04` delivery_date = `2026-07-15` ) - ( order_id = `1001` customer = `Bright Retail` order_date = `2026-05-12` delivery_date = `2026-07-20` ) - ( order_id = `1002` customer = `Ace Manufacturing` order_date = `2026-06-01` delivery_date = `2026-08-01` ) - ( order_id = `1003` customer = `Corner Logistics` order_date = `2026-06-18` delivery_date = `2026-08-10` ) ). - - IF s_search-date_from IS NOT INITIAL. - DELETE t_orders WHERE order_date < s_search-date_from. - ENDIF. - - IF s_search-date_to IS NOT INITIAL. - DELETE t_orders WHERE order_date > s_search-date_to. - ENDIF. - - IF s_search-customer IS NOT INITIAL. - " NS = `contains no string` — remove rows whose customer does not contain the filter text - DELETE t_orders WHERE customer NS s_search-customer. - ENDIF. - - ENDMETHOD. - - - METHOD data_update. - - " in your system, persist the change with an UPDATE, e.g.: - " UPDATE zsd_order SET delivery_date = @s_edit-delivery_date - " WHERE order_id = @s_edit-order_id. - t_orders[ order_id = s_edit-order_id ]-delivery_date = s_edit-delivery_date. - - ENDMETHOD. - -ENDCLASS. -``` -::: - -## What to Take Away - -- One controller class, one `main` method, all state in public attributes — that is the whole app -- The view is rebuilt only when the structure changes. Edits, saves, and popup open/close do not need a fresh `view_display( )` -- Popups use the same builder as the view — a `core:FragmentDefinition` root instead of `mvc:View` — displayed via `popup_display` / `popup_destroy` while the main view stays in place -- Reading and writing the database is plain ABAP — abap2UI5 does not abstract that layer, which is what makes it easy to plug into existing code - -From here, look at the [Cookbook](/cookbook/event_navigation/life_cycle) for value helps, navigation between apps, message handling, and other patterns you will need next. - - - -## Working Samples - -Complete apps from the [sample catalogue](https://github.com/abap2UI5/samples/blob/main/SAMPLES.md) -that use what this page describes. Each is a single class — pull the repository with -[abapGit](https://abapgit.org) and start it with `?app_start=`. - -| Sample | Class | -|---|---| -| Full Example with sap.ui.table | [`Z2UI5_CL_SMP_APP_070`](https://github.com/abap2UI5/samples/blob/main/src/01/z2ui5_cl_smp_app_070.clas.abap) | -| Editable Cells, Add and Delete Rows | [`Z2UI5_CL_SMP_APP_011`](https://github.com/abap2UI5/samples/blob/main/src/01/z2ui5_cl_smp_app_011.clas.abap) | - - diff --git a/docs/get_started/hello_world.md b/docs/get_started/hello_world.md index f3c3ee97..dd59f04d 100644 --- a/docs/get_started/hello_world.md +++ b/docs/get_started/hello_world.md @@ -28,12 +28,77 @@ That is a complete abap2UI5 app: one class, one method, no frontend project and While the HTTP handler has to distinguish between Standard ABAP and ABAP for Cloud, the apps themselves are independent. You're free to choose whether to build your apps with ABAP Cloud compatibility. ::: +## A Real Screen + +A message box is not an app. This second class is still one class, and it has +everything a real one has — a view, data travelling both ways, and an event: + +```abap +CLASS zcl_app_hello_screen DEFINITION PUBLIC. + PUBLIC SECTION. + INTERFACES z2ui5_if_app. + DATA name TYPE string. +ENDCLASS. + +CLASS zcl_app_hello_screen IMPLEMENTATION. + METHOD z2ui5_if_app~main. + + IF client->check_on_navigated( ). + + name = `World`. + + DATA(view) = z2ui5_cl_ui5_view_builder=>factory( + )->ele( n = `View` ns = `mvc` + )->a( n = `xmlns` v = `sap.m` + )->a( n = `xmlns:mvc` v = `sap.ui.core.mvc` + + )->ele( `Shell` + )->ele( `Page` + )->a( n = `title` v = `abap2UI5 - Hello World` + + )->tag( `Input` + )->a( n = `value` v = client->_bind( name ) + )->tag( `Button` + )->a( n = `text` v = `Say Hello` + )->a( n = `press` v = client->_event( `SAY_HELLO` ) ). + + client->view_display( view->stringify( ) ). + + ELSEIF client->check_on_event( `SAY_HELLO` ). + + client->message_toast_display( |Hello { name }!| ). + + ENDIF. + + ENDMETHOD. +ENDCLASS. +``` + +Type a name, press the button, and the toast greets it. Three things are +happening, and none of them needed any code you had to write yourself: + +- the **view** is a UI5 XML view, built in ABAP with `z2ui5_cl_ui5_view_builder` +- `client->_bind( name )` ties the input to the public attribute, so what the + user types is in `name` on the next roundtrip +- `client->_event( )` sends the button press back to `main`, and + `check_on_event( )` catches it + +## Jump into the Code + +Press `Ctrl+F12` in any running app to open the **Developer Tools** — tabs for +the app's source code, the rendered view XML, the model data, the +request/response pair and the error log. It is the first place to look when +something does not render the way you expected: + +![Developer Tools opened with Ctrl+F12 showing code, view, and model](/get_started/image-2.png) + ## Next: Build Something -The [Walkthrough](/tutorials/walkthrough/overview) takes this class and grows it -into a small invoice app in eight steps — views, events, data binding, lists and -popups, each step a complete class you can run in the browser. It starts exactly -where this page stops. +Want all of that explained rather than just shown? The +[Walkthrough](/tutorials/overview) takes these two classes apart and grows them +into a complete app, one concept per step — views, events, binding, lists, +tables, a selection screen and popups. Every step is a complete class you can +run in the browser. diff --git a/docs/public/tutorials/walkthrough-preview.png b/docs/public/tutorials/walkthrough-preview.png index eb2f4d917beb2e691af7d94e4984b6916ce72be5..efde42950cb8acba4b4d1497420e288bba178238 100644 GIT binary patch literal 65128 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⩰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 RK59S%Id{eeQF8iv)UTH*dHetX diff --git a/docs/tutorials/overview.md b/docs/tutorials/overview.md index c930cb5c..36e94875 100644 --- a/docs/tutorials/overview.md +++ b/docs/tutorials/overview.md @@ -1,29 +1,61 @@ --- outline: [2, 4] -description: Learn abap2UI5 by building — step-by-step tutorials where every step is a complete class you can run in the browser. +description: Learn abap2UI5 by building — a step-by-step walkthrough where every step is a complete class you can run in the browser. --- -# Tutorials +# Tutorial -Learn abap2UI5 by building something. A tutorial is a sequence of steps, and -every step is one **complete class**: run it directly under its code with the -Run button, or copy it into your system and start it like any abap2UI5 app -(see the [Quickstart](/get_started/quickstart)). +Learn abap2UI5 by building something. The **Walkthrough** grows a small invoice +app from a single message box into a complete application, one concept per +step: the app class and its lifecycle, views written in ABAP, events, data +binding, lists, tables, a selection screen and popups. -## Learning Path +Each step is a **complete, runnable class** — the whole app as it stands at +that point, not a fragment. Press the Run button under the code to start it in +the browser, or copy the class into your system and launch it like any +abap2UI5 app (see the [Quickstart](/get_started/quickstart)). No step depends +on anything outside its own code, so you can also jump straight to the step +you are interested in. -| Tutorial | Type | Content | -|---|---|---| -| [Walkthrough](/tutorials/walkthrough/overview) | Foundation | Builds a small invoice app from scratch in eight steps — the app class and its lifecycle, views built in ABAP, events, data binding, lists, popups, and the structure real apps use. | -| [Full Example](/get_started/full_example) | Deep dive | The same structure applied to a realistic ABAP flow: a selection screen, a `SELECT`, a result table, a popup that edits a row, and the change written back. | +## Preview -Keep the [Cheat Sheet](/cookbook/cheat_sheet) open while you work through -them — it is every recurring construct on one page, from binding syntax to -the popup calls. +![The finished walkthrough app: a table of invoices with a selection form above it, and a dialog editing one row](/tutorials/walkthrough-preview.png) -## After the Tutorials +This is the app after the last step — a few hundred lines of ABAP, no frontend +project, no OData service. -The [Cookbook](/cookbook/view/definition) covers each topic again as a reference -chapter, and three catalogues of complete, tested apps continue from there: +## Steps + +- **[Step 1: The App Class](/tutorials/walkthrough/step-1)** — the smallest possible app: one class, one method, one message. +- **[Step 2: A First View](/tutorials/walkthrough/step-2)** — render a UI5 view built entirely in ABAP. +- **[Step 3: Events](/tutorials/walkthrough/step-3)** — a button, a press event, and the lifecycle behind them. +- **[Step 4: Data Binding](/tutorials/walkthrough/step-4)** — an input field whose value reaches the server by itself. +- **[Step 5: List Binding](/tutorials/walkthrough/step-5)** — show an internal table as a UI5 list. +- **[Step 6: Row Events](/tutorials/walkthrough/step-6)** — react to a click on a row, and know which row it was. +- **[Step 7: Popups](/tutorials/walkthrough/step-7)** — edit a row in a dialog. +- **[Step 8: Selection Screen](/tutorials/walkthrough/step-8)** — a form above the list, and reading the data it asks for. +- **[Step 9: Tables](/tutorials/walkthrough/step-9)** — swap the list for a real table with columns, cells and row actions. +- **[Step 10: App Structure](/tutorials/walkthrough/step-10)** — refactor into the structure real apps use. + +## What You Should Know + +No prior abap2UI5 or UI5 experience is needed — the tutorial introduces every +concept as it appears. Basic ABAP (classes, methods, internal tables) is +assumed, and [Hello World](/get_started/hello_world) is the one page worth +reading first: it starts the smallest possible app in your own system, which is +where this tutorial picks up. + +The Run button works without any installation at all, so you can also simply +begin at [Step 1](/tutorials/walkthrough/step-1). + +Keep the [Cheat Sheet](/cookbook/cheat_sheet) open while you work through the +steps — it is every recurring construct on one page, from binding syntax to the +popup calls. + +## After the Tutorial + +The [Cookbook](/cookbook/view/definition) covers each topic again as a +reference chapter, and three catalogues of complete, tested apps continue from +there: - [Samples](https://abap2ui5.github.io/samples/) — one app per pattern, along a guided learning path - [Controls](https://abap2ui5.github.io/samples-controls/) — UI5 demo kit samples rebuilt as abap2UI5 apps, searchable by control diff --git a/docs/tutorials/walkthrough/overview.md b/docs/tutorials/walkthrough/overview.md deleted file mode 100644 index c9bb29a9..00000000 --- a/docs/tutorials/walkthrough/overview.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -outline: [2, 4] -description: Build a small invoice app from scratch in eight steps — every step a complete, runnable abap2UI5 class. ---- -# Walkthrough - -In this tutorial we build a small invoice app from scratch and meet every -paradigm an abap2UI5 app is made of along the way: the app class and its -lifecycle, views written in ABAP, events, data binding, lists and popups. - -## Preview - -![The finished walkthrough app: a list of invoices with supplier and quantity, and a dialog editing the quantity of one row](/tutorials/walkthrough-preview.png) - -This is the app after the last step — about a hundred lines of ABAP, no -frontend project, no OData service. - -Each step is a **complete, runnable class** — the whole app as it stands at -that point, not a fragment. Press the Run button under the code to start it in -the browser, or copy the class into your system and launch it like any -abap2UI5 app (see the [Quickstart](/get_started/quickstart)). No step depends -on anything outside its own code, so you can also jump straight to the step -you are interested in. - -## Steps - -- **[Step 1: Hello World](/tutorials/walkthrough/step-1)** — the smallest possible app: one class, one method, one message. -- **[Step 2: A First View](/tutorials/walkthrough/step-2)** — render a UI5 view built entirely in ABAP. -- **[Step 3: Events](/tutorials/walkthrough/step-3)** — a button, a press event, and the lifecycle behind them. -- **[Step 4: Data Binding](/tutorials/walkthrough/step-4)** — an input field whose value reaches the server by itself. -- **[Step 5: List Binding](/tutorials/walkthrough/step-5)** — show an internal table as a UI5 list. -- **[Step 6: Row Events](/tutorials/walkthrough/step-6)** — react to a click on a row, and know which row it was. -- **[Step 7: Popups](/tutorials/walkthrough/step-7)** — edit a row in a dialog. -- **[Step 8: App Structure](/tutorials/walkthrough/step-8)** — refactor into the structure real apps use. - -## What You Should Know - -No prior abap2UI5 or UI5 experience is needed — the tutorial introduces every -concept as it appears. Basic ABAP (classes, methods, internal tables) is -assumed, and [Hello World](/get_started/hello_world) is the one page worth -reading first: it starts the smallest possible app in your own system, which -is where this tutorial picks up. - -The Run button works without any installation at all, so you can also simply -begin at [Step 1](/tutorials/walkthrough/step-1). diff --git a/docs/tutorials/walkthrough/step-1.md b/docs/tutorials/walkthrough/step-1.md index fcbabda1..51c1897f 100644 --- a/docs/tutorials/walkthrough/step-1.md +++ b/docs/tutorials/walkthrough/step-1.md @@ -1,10 +1,10 @@ --- outline: [2, 4] -description: The smallest possible abap2UI5 app — one class, one method, one message. +description: The smallest possible abap2UI5 app — one class implementing z2ui5_if_app, and the one method the framework calls. samples: - z2ui5_cl_smp_app_493 --- -# Step 1: Hello World +# Step 1: The App Class Every abap2UI5 app is one ABAP class implementing the interface `z2ui5_if_app`. That interface has a single method, `main`, and the framework diff --git a/docs/tutorials/walkthrough/step-10.md b/docs/tutorials/walkthrough/step-10.md new file mode 100644 index 00000000..07508fd1 --- /dev/null +++ b/docs/tutorials/walkthrough/step-10.md @@ -0,0 +1,316 @@ +--- +outline: [2, 4] +description: Put everything into the structure real apps use — a dispatcher, named methods, protected state, and the SELECT and UPDATE in one place. +samples: + - z2ui5_cl_smp_app_070 + - z2ui5_cl_smp_app_011 +--- +# Step 10: App Structure + +Everything so far lived in one `main` method, and by now that method does five +different jobs. Real apps — the framework's own, and the sample catalogues' — +separate the phases into methods. This last step changes no behavior at all: it +puts the code where a reader expects it, and assembles every part of the +tutorial into the complete app. + +## What It Does + +1. **Selection screen** — supplier and a delivery-date range ([Step 8](/tutorials/walkthrough/step-8)). +2. **Read** — fetch the matching invoices on button press ([Step 8](/tutorials/walkthrough/step-8)). +3. **Result table** — columns, cells and a row action ([Step 9](/tutorials/walkthrough/step-9)). +4. **Popup** — edit the delivery date of one row ([Step 7](/tutorials/walkthrough/step-7)). +5. **Post** — write the change back and refresh the table. + +## The Class + +```abap +CLASS zcl_app_walkthrough DEFINITION PUBLIC. + + PUBLIC SECTION. + INTERFACES z2ui5_if_app. + + TYPES: + BEGIN OF ty_s_invoice, + product TYPE string, + supplier TYPE string, + quantity TYPE string, + delivery_date TYPE string, + END OF ty_s_invoice. + + DATA: + BEGIN OF s_search, + supplier TYPE string, + date_from TYPE string, + date_to TYPE string, + END OF s_search. + + DATA t_invoices TYPE STANDARD TABLE OF ty_s_invoice WITH EMPTY KEY. + DATA s_edit TYPE ty_s_invoice. + + PROTECTED SECTION. + DATA client TYPE REF TO z2ui5_if_client. + + METHODS on_event. + METHODS view_display. + METHODS popup_edit_display. + METHODS data_read. + METHODS data_update. + + PRIVATE SECTION. +ENDCLASS. + +CLASS zcl_app_walkthrough IMPLEMENTATION. + + METHOD z2ui5_if_app~main. + + me->client = client. + IF client->check_on_navigated( ). + view_display( ). + ELSEIF client->check_on_event( ). + on_event( ). + ENDIF. + + ENDMETHOD. + + + METHOD on_event. + + " get_event( ) holds the name passed to _event( ); + " get_event_arg( ) returns the extra argument attached via t_arg + CASE client->get_event( ). + WHEN `READ`. + data_read( ). + WHEN `EDIT`. + s_edit = VALUE #( t_invoices[ product = client->get_event_arg( ) ] OPTIONAL ). + popup_edit_display( ). + WHEN `SAVE`. + data_update( ). + client->popup_destroy( ). + client->message_toast_display( |{ s_edit-product } updated.| ). + WHEN `CANCEL`. + client->popup_destroy( ). + ENDCASE. + + ENDMETHOD. + + + METHOD view_display. + + DATA(view) = z2ui5_cl_ui5_view_builder=>factory( + )->ele( n = `View` ns = `mvc` + )->a( n = `xmlns` v = `sap.m` + )->a( n = `xmlns:mvc` v = `sap.ui.core.mvc` + )->a( n = `xmlns:form` v = `sap.ui.layout.form` ). + + DATA(page) = view->ele( `Shell` + )->ele( `Page` + )->a( n = `title` v = `Walkthrough - Step 10` + )->a( n = `navButtonPress` v = client->_event_nav_app_leave( ) + )->a( n = `showNavButton` b = client->check_app_prev_stack( ) ). + + page->ele( n = `SimpleForm` ns = `form` + )->a( n = `title` v = `Selection` + )->a( n = `editable` v = `true` + + )->ele( n = `content` ns = `form` + + )->tag( `Label` + )->a( n = `text` v = `Supplier` + )->tag( `Input` + )->a( n = `value` v = client->_bind( s_search-supplier ) + )->tag( `Label` + )->a( n = `text` v = `Delivery Date From` + )->tag( `DatePicker` + )->a( n = `value` v = client->_bind( s_search-date_from ) + )->a( n = `valueFormat` v = `yyyy-MM-dd` + )->tag( `Label` + )->a( n = `text` v = `Delivery Date To` + )->tag( `DatePicker` + )->a( n = `value` v = client->_bind( s_search-date_to ) + )->a( n = `valueFormat` v = `yyyy-MM-dd` + )->tag( `Button` + )->a( n = `text` v = `Read Invoices` + )->a( n = `press` v = client->_event( `READ` ) + )->a( n = `type` v = `Emphasized` ). + + DATA(tab) = page->ele( `Table` + )->a( n = `headerText` v = `Invoices` + )->a( n = `items` v = client->_bind( t_invoices ) ). + + tab->ele( `columns` + + )->ele( `Column` + )->tag( `Text` + )->a( n = `text` v = `Product` + + )->end( + )->ele( `Column` + )->tag( `Text` + )->a( n = `text` v = `Supplier` + + )->end( + )->ele( `Column` + )->tag( `Text` + )->a( n = `text` v = `Quantity` + + )->end( + )->ele( `Column` + )->tag( `Text` + )->a( n = `text` v = `Delivery Date` + + )->end( + )->ele( `Column` + )->a( n = `width` v = `10%` ). + + tab->ele( `items` + )->ele( `ColumnListItem` + )->ele( `cells` + + )->tag( `Text` + )->a( n = `text` v = `{PRODUCT}` + )->tag( `Text` + )->a( n = `text` v = `{SUPPLIER}` + )->tag( `Text` + )->a( n = `text` v = `{QUANTITY}` + )->tag( `Text` + )->a( n = `text` v = `{DELIVERY_DATE}` + )->tag( `Button` + )->a( n = `icon` v = `sap-icon://edit` + )->a( n = `tooltip` v = `Edit delivery date` + )->a( n = `press` v = client->_event( val = `EDIT` + t_arg = VALUE #( ( `${PRODUCT}` ) ) ) ). + + client->view_display( view->stringify( ) ). + + ENDMETHOD. + + + METHOD popup_edit_display. + + DATA(popup) = z2ui5_cl_ui5_view_builder=>factory( + )->ele( n = `FragmentDefinition` ns = `core` + )->a( n = `xmlns` v = `sap.m` + )->a( n = `xmlns:core` v = `sap.ui.core` + + )->ele( `Dialog` + )->a( n = `title` v = |Edit { s_edit-product }| + + )->ele( `content` + + )->tag( `Label` + )->a( n = `text` v = `Delivery Date` + )->tag( `DatePicker` + )->a( n = `value` v = client->_bind( s_edit-delivery_date ) + )->a( n = `valueFormat` v = `yyyy-MM-dd` + + )->end( + + )->ele( `buttons` + + )->tag( `Button` + )->a( n = `text` v = `Cancel` + )->a( n = `press` v = client->_event( `CANCEL` ) + )->tag( `Button` + )->a( n = `text` v = `Save` + )->a( n = `press` v = client->_event( `SAVE` ) + )->a( n = `type` v = `Emphasized` ). + + client->popup_display( popup->stringify( ) ). + + ENDMETHOD. + + + METHOD data_read. + + " demo data — in your system, replace this with a SELECT, e.g.: + " SELECT product, supplier, quantity, delivery_date + " FROM zinvoice + " WHERE supplier LIKE @s_search-supplier + " AND delivery_date BETWEEN @s_search-date_from AND @s_search-date_to + " INTO TABLE @t_invoices. + t_invoices = VALUE #( + ( product = `Pineapple` supplier = `ACME` quantity = `21` delivery_date = `2026-07-15` ) + ( product = `Milk` supplier = `Green Growers` quantity = `4` delivery_date = `2026-07-20` ) + ( product = `Canned Beans` supplier = `Corner Deli` quantity = `3` delivery_date = `2026-08-01` ) + ( product = `Salad` supplier = `Green Growers` quantity = `2` delivery_date = `2026-08-10` ) + ( product = `Bread` supplier = `Corner Deli` quantity = `1` delivery_date = `2026-08-12` ) ). + + IF s_search-supplier IS NOT INITIAL. + " NS = `contains no string` — drop the rows whose supplier does not match + DELETE t_invoices WHERE supplier NS s_search-supplier. + ENDIF. + + IF s_search-date_from IS NOT INITIAL. + DELETE t_invoices WHERE delivery_date < s_search-date_from. + ENDIF. + + IF s_search-date_to IS NOT INITIAL. + DELETE t_invoices WHERE delivery_date > s_search-date_to. + ENDIF. + + ENDMETHOD. + + + METHOD data_update. + + " in your system, persist the change with an UPDATE, e.g.: + " UPDATE zinvoice SET delivery_date = @s_edit-delivery_date + " WHERE product = @s_edit-product. + t_invoices[ product = s_edit-product ]-delivery_date = s_edit-delivery_date. + + ENDMETHOD. + +ENDCLASS. +``` + +## The Structure + +- **`main` is a pure dispatcher.** It stashes `client` in a protected attribute + — so the handler methods can use it without passing it around — and routes + each roundtrip to the method for its phase. `check_on_event( )` without an + argument is true for *any* event; the `CASE` in `on_event` decides which one. + Both dispatch shapes are fine, and + [Life Cycle](/cookbook/event_navigation/life_cycle) compares them: dispatch + by event name in the `IF` chain for a small app, this second level once there + are handler methods. +- **State stays public, everything else protected.** Public attributes are the + serialized, browser-visible model — bound data and nothing more. The `client` + reference and the methods are implementation. +- **One method per screen, one per data operation.** `view_display` and + `popup_edit_display` build; `data_read` and `data_update` touch the database. + When an app grows, those are the seams it grows along — and the two data + methods are the only places a `SELECT` or an `UPDATE` ever appears. +- **A back button, when there is somewhere to go.** `navButtonPress` and + `showNavButton` give the page the standard back navigation, shown only when + this app was called from another one — see + [Navigation](/cookbook/event_navigation/navigation). + +## What to Take Away + +- One controller class, one `main` method, all state in public attributes — that is the whole app +- The view is rebuilt only when the structure changes. Reading data, saving, and opening or closing a popup do not need a fresh `view_display( )` +- Popups use the same builder as the view — a `core:FragmentDefinition` root instead of `mvc:View` — shown with `popup_display` / `popup_destroy` while the main view stays in place +- Reading and writing the database is plain ABAP; abap2UI5 does not abstract that layer, which is what makes it easy to plug into existing code + +## Where to Go From Here + +- the [Cookbook](/cookbook/view/definition) — every topic of this walkthrough as a + reference chapter, from [value helps](/cookbook/expert_more/value_help) to + [navigation between apps](/cookbook/event_navigation/navigation), +- the [sample catalogues](https://abap2ui5.github.io/samples/) — complete, + tested apps for nearly every pattern, each one class like here. + + + +## Working Samples + +Complete apps from the [sample catalogue](https://github.com/abap2UI5/samples/blob/main/SAMPLES.md) +that use what this page describes. Each is a single class — pull the repository with +[abapGit](https://abapgit.org) and start it with `?app_start=`. + +| Sample | Class | +|---|---| +| Full Example with sap.ui.table | [`Z2UI5_CL_SMP_APP_070`](https://github.com/abap2UI5/samples/blob/main/src/01/z2ui5_cl_smp_app_070.clas.abap) | +| Editable Cells, Add and Delete Rows | [`Z2UI5_CL_SMP_APP_011`](https://github.com/abap2UI5/samples/blob/main/src/01/z2ui5_cl_smp_app_011.clas.abap) | + + diff --git a/docs/tutorials/walkthrough/step-2.md b/docs/tutorials/walkthrough/step-2.md index 7ee7e9cb..57b67ab6 100644 --- a/docs/tutorials/walkthrough/step-2.md +++ b/docs/tutorials/walkthrough/step-2.md @@ -59,13 +59,8 @@ The indentation mirrors the XML tree — `Text` sits inside `Page` inside full layout rules are on the [View → Definition](/cookbook/view/definition) page. -## Look at What It Built - -Press `Ctrl+F12` in any running app to open the **Developer Tools** — tabs for -the app's source code, the rendered view XML, the model data, the -request/response pair and the error log. The XML tab is the view this chain -produced, which is the quickest way to see what a verb did: - -![Developer Tools opened with Ctrl+F12 showing code, view, and model](/get_started/image-2.png) +Want to see the XML this chain produced? Press `Ctrl+F12` in the running app +and open the view tab — the [developer tools](/get_started/hello_world#jump-into-the-code) +show the generated view, the model and the payload of every roundtrip. Next, the app gets its first button — and with it, the app lifecycle. diff --git a/docs/tutorials/walkthrough/step-8.md b/docs/tutorials/walkthrough/step-8.md index a1d2d3fd..d229ee79 100644 --- a/docs/tutorials/walkthrough/step-8.md +++ b/docs/tutorials/walkthrough/step-8.md @@ -1,169 +1,150 @@ --- outline: [2, 4] -description: Refactor the walkthrough app into the structure real apps use — a dispatcher, named methods, protected state. +description: A selection form above the list, and reading the data it asks for — the shape of a classic ABAP report. samples: - - z2ui5_cl_smp_app_070 + - z2ui5_cl_smp_app_011 --- -# Step 8: App Structure +# Step 8: Selection Screen -The app is complete, but everything lives in one `main` method. Real apps — -the framework's own, and the sample catalogues' — separate the phases into -methods, so this last step changes no behavior at all: it puts the code where -a reader expects it. +Real apps rarely show all the data at once. They ask first: a selection screen +on top, a result below, and a button between them. This step adds that form — +and with it the way a real app reads its data. + +The invoice record gains a delivery date, so there is a date to select on: ```abap CLASS zcl_app_walkthrough DEFINITION PUBLIC. - PUBLIC SECTION. INTERFACES z2ui5_if_app. TYPES: BEGIN OF ty_s_invoice, - product TYPE string, - supplier TYPE string, - quantity TYPE string, + product TYPE string, + supplier TYPE string, + quantity TYPE string, + delivery_date TYPE string, END OF ty_s_invoice. - DATA t_invoices TYPE STANDARD TABLE OF ty_s_invoice WITH EMPTY KEY. - DATA s_edit TYPE ty_s_invoice. - - PROTECTED SECTION. - DATA client TYPE REF TO z2ui5_if_client. - - METHODS on_event. - METHODS view_display. - METHODS popup_edit_display. + DATA: + BEGIN OF s_search, + supplier TYPE string, + date_from TYPE string, + date_to TYPE string, + END OF s_search. + DATA t_invoices TYPE STANDARD TABLE OF ty_s_invoice WITH EMPTY KEY. ENDCLASS. CLASS zcl_app_walkthrough IMPLEMENTATION. - METHOD z2ui5_if_app~main. - me->client = client. IF client->check_on_navigated( ). - view_display( ). - ELSEIF client->check_on_event( ). - on_event( ). - ENDIF. - - ENDMETHOD. - - - METHOD on_event. - - CASE client->get( )-event. - WHEN `EDIT`. - s_edit = VALUE #( t_invoices[ product = client->get_event_arg( ) ] OPTIONAL ). - popup_edit_display( ). - WHEN `SAVE`. - t_invoices[ product = s_edit-product ]-quantity = s_edit-quantity. - client->popup_destroy( ). - client->message_toast_display( |{ s_edit-product } updated.| ). - WHEN `CANCEL`. - client->popup_destroy( ). - ENDCASE. - - ENDMETHOD. - - - METHOD view_display. - - t_invoices = VALUE #( - ( product = `Pineapple` supplier = `ACME` quantity = `21` ) - ( product = `Milk` supplier = `Green Growers` quantity = `4` ) - ( product = `Canned Beans` supplier = `Corner Deli` quantity = `3` ) - ( product = `Salad` supplier = `Green Growers` quantity = `2` ) - ( product = `Bread` supplier = `Corner Deli` quantity = `1` ) ). - - DATA(view) = z2ui5_cl_ui5_view_builder=>factory( - )->ele( n = `View` ns = `mvc` - )->a( n = `xmlns` v = `sap.m` - )->a( n = `xmlns:mvc` v = `sap.ui.core.mvc` - - )->ele( `Shell` - )->ele( `Page` - )->a( n = `title` v = `Walkthrough - Step 8` - )->ele( `List` - )->a( n = `headerText` v = `Invoices` - )->a( n = `items` v = client->_bind( t_invoices ) + DATA(view) = z2ui5_cl_ui5_view_builder=>factory( + )->ele( n = `View` ns = `mvc` + )->a( n = `xmlns` v = `sap.m` + )->a( n = `xmlns:mvc` v = `sap.ui.core.mvc` + )->a( n = `xmlns:form` v = `sap.ui.layout.form` ). + + DATA(page) = view->ele( `Shell` + )->ele( `Page` + )->a( n = `title` v = `Walkthrough - Step 8` ). + + page->ele( n = `SimpleForm` ns = `form` + )->a( n = `title` v = `Selection` + )->a( n = `editable` v = `true` + + )->ele( n = `content` ns = `form` + + )->tag( `Label` + )->a( n = `text` v = `Supplier` + )->tag( `Input` + )->a( n = `value` v = client->_bind( s_search-supplier ) + )->tag( `Label` + )->a( n = `text` v = `Delivery Date From` + )->tag( `DatePicker` + )->a( n = `value` v = client->_bind( s_search-date_from ) + )->a( n = `valueFormat` v = `yyyy-MM-dd` + )->tag( `Label` + )->a( n = `text` v = `Delivery Date To` + )->tag( `DatePicker` + )->a( n = `value` v = client->_bind( s_search-date_to ) + )->a( n = `valueFormat` v = `yyyy-MM-dd` + )->tag( `Button` + )->a( n = `text` v = `Read Invoices` + )->a( n = `press` v = client->_event( `READ` ) + )->a( n = `type` v = `Emphasized` ). + + page->ele( `List` + )->a( n = `headerText` v = `Invoices` + )->a( n = `items` v = client->_bind( t_invoices ) + + )->ele( `items` + )->tag( `StandardListItem` + )->a( n = `title` v = `{PRODUCT}` + )->a( n = `description` v = `{SUPPLIER}` + )->a( n = `info` v = `{DELIVERY_DATE}` ). + + client->view_display( view->stringify( ) ). + + ELSEIF client->check_on_event( `READ` ). + + " demo data — in your system, replace this with a SELECT, e.g.: + " SELECT product, supplier, quantity, delivery_date + " FROM zinvoice + " WHERE supplier LIKE @s_search-supplier + " AND delivery_date BETWEEN @s_search-date_from AND @s_search-date_to + " INTO TABLE @t_invoices. + t_invoices = VALUE #( + ( product = `Pineapple` supplier = `ACME` quantity = `21` delivery_date = `2026-07-15` ) + ( product = `Milk` supplier = `Green Growers` quantity = `4` delivery_date = `2026-07-20` ) + ( product = `Canned Beans` supplier = `Corner Deli` quantity = `3` delivery_date = `2026-08-01` ) + ( product = `Salad` supplier = `Green Growers` quantity = `2` delivery_date = `2026-08-10` ) + ( product = `Bread` supplier = `Corner Deli` quantity = `1` delivery_date = `2026-08-12` ) ). + + IF s_search-supplier IS NOT INITIAL. + " NS = `contains no string` — drop the rows whose supplier does not match + DELETE t_invoices WHERE supplier NS s_search-supplier. + ENDIF. + + IF s_search-date_from IS NOT INITIAL. + DELETE t_invoices WHERE delivery_date < s_search-date_from. + ENDIF. + + IF s_search-date_to IS NOT INITIAL. + DELETE t_invoices WHERE delivery_date > s_search-date_to. + ENDIF. - )->ele( `items` - )->tag( `StandardListItem` - )->a( n = `title` v = `{PRODUCT}` - )->a( n = `description` v = `{SUPPLIER}` - )->a( n = `info` v = `{QUANTITY}` - )->a( n = `type` v = `Active` - )->a( n = `press` v = client->_event( val = `EDIT` - t_arg = VALUE #( ( `${PRODUCT}` ) ) ) ). - - client->view_display( view->stringify( ) ). - - ENDMETHOD. - - - METHOD popup_edit_display. - - DATA(popup) = z2ui5_cl_ui5_view_builder=>factory( - )->ele( n = `FragmentDefinition` ns = `core` - )->a( n = `xmlns` v = `sap.m` - )->a( n = `xmlns:core` v = `sap.ui.core` - - )->ele( `Dialog` - )->a( n = `title` v = |Edit { s_edit-product }| - - )->ele( `content` - - )->tag( `Label` - )->a( n = `text` v = `Quantity` - )->tag( `Input` - )->a( n = `value` v = client->_bind( s_edit-quantity ) - - )->end( - - )->ele( `buttons` - - )->tag( `Button` - )->a( n = `text` v = `Cancel` - )->a( n = `press` v = client->_event( `CANCEL` ) - )->tag( `Button` - )->a( n = `text` v = `Save` - )->a( n = `press` v = client->_event( `SAVE` ) - )->a( n = `type` v = `Emphasized` ). - - client->popup_display( popup->stringify( ) ). + ENDIF. ENDMETHOD. - ENDCLASS. ``` -## The Structure - -- **`main` is a pure dispatcher.** It stashes `client` in a protected - attribute — so the handler methods can use it without passing it around — - and routes each roundtrip to the method for its phase. `check_on_event( )` - without an argument is true for *any* event; the `CASE` in `on_event` - decides which one. -- **State stays public, everything else protected.** Public attributes are - the serialized, browser-visible model — bound data and nothing more. The - `client` reference and the methods are implementation. -- **One method per screen.** `view_display` for the page, `popup_edit_display` - for the dialog. When an app grows, this is the seam it grows along. - -## Where to Go From Here - -You have seen everything an abap2UI5 app is made of. Three places continue -from here: - -- the [Full Example](/get_started/full_example) — the same structure applied - to a realistic selection-screen app with a table and database access, -- the [Cookbook](/cookbook/view/definition) — every topic of this walkthrough as a - reference chapter, from [value helps](/cookbook/expert_more/value_help) to - [navigation between apps](/cookbook/event_navigation/navigation), -- the [sample catalogues](https://abap2ui5.github.io/samples/) — complete, - tested apps for nearly every pattern, each one class like here. +## What Is New + +- **A form, from a second statement.** The chain is split: `view` holds the + root, `page` holds the `Page`, and the form and the list are each filled from + `page` in a statement of their own. That is the shape most abap2UI5 apps use + once a view has more than one part — see + [View → Definition](/cookbook/view/definition). +- **`sap.ui.layout.form` needs its own namespace.** `xmlns:form` is declared on + the root next to `xmlns:mvc`, and `SimpleForm` and its `content` aggregation + are written with `ns = \`form\``. A `SimpleForm` lays out label/field pairs by + itself — no grid, no widths. +- **`DatePicker` with `valueFormat`.** The picker shows the date in the user's + locale and hands your ABAP attribute the format you asked for — here + `yyyy-MM-dd`, so a string comparison sorts correctly. +- **The event handler reads data, and nothing else.** No `view_display( )` in + the `READ` branch: the view already exists in the browser, only `t_invoices` + changed, and every roundtrip that changed bound data pushes the new model by + itself. +- **The `SELECT` is the point.** In your system the demo data and the three + `DELETE`s are one `SELECT` with a `WHERE` clause. abap2UI5 does not abstract + the database layer — reading and writing stays plain ABAP, which is what + makes it easy to plug into code you already have. + +Next, the list becomes a real table. @@ -175,6 +156,6 @@ that use what this page describes. Each is a single class — pull the repositor | Sample | Class | |---|---| -| Full Example with sap.ui.table | [`Z2UI5_CL_SMP_APP_070`](https://github.com/abap2UI5/samples/blob/main/src/01/z2ui5_cl_smp_app_070.clas.abap) | +| Editable Cells, Add and Delete Rows | [`Z2UI5_CL_SMP_APP_011`](https://github.com/abap2UI5/samples/blob/main/src/01/z2ui5_cl_smp_app_011.clas.abap) | diff --git a/docs/tutorials/walkthrough/step-9.md b/docs/tutorials/walkthrough/step-9.md new file mode 100644 index 00000000..6fda9707 --- /dev/null +++ b/docs/tutorials/walkthrough/step-9.md @@ -0,0 +1,190 @@ +--- +outline: [2, 4] +description: Swap the list for a real UI5 table — columns, cells and a row action that opens the editor. +samples: + - z2ui5_cl_smp_app_070 +--- +# Step 9: Tables + +A list shows three fields per row. A table shows columns — with headers, with +a cell per field, and with room for a row action. This step swaps +`sap.m.List` for `sap.m.Table` and puts the edit button from +[Step 7](/tutorials/walkthrough/step-7) back, now in a column of its own: + +```abap +CLASS zcl_app_walkthrough DEFINITION PUBLIC. + PUBLIC SECTION. + INTERFACES z2ui5_if_app. + + TYPES: + BEGIN OF ty_s_invoice, + product TYPE string, + supplier TYPE string, + quantity TYPE string, + delivery_date TYPE string, + END OF ty_s_invoice. + + DATA t_invoices TYPE STANDARD TABLE OF ty_s_invoice WITH EMPTY KEY. + DATA s_edit TYPE ty_s_invoice. +ENDCLASS. + +CLASS zcl_app_walkthrough IMPLEMENTATION. + METHOD z2ui5_if_app~main. + + IF client->check_on_navigated( ). + + t_invoices = VALUE #( + ( product = `Pineapple` supplier = `ACME` quantity = `21` delivery_date = `2026-07-15` ) + ( product = `Milk` supplier = `Green Growers` quantity = `4` delivery_date = `2026-07-20` ) + ( product = `Canned Beans` supplier = `Corner Deli` quantity = `3` delivery_date = `2026-08-01` ) + ( product = `Salad` supplier = `Green Growers` quantity = `2` delivery_date = `2026-08-10` ) + ( product = `Bread` supplier = `Corner Deli` quantity = `1` delivery_date = `2026-08-12` ) ). + + DATA(view) = z2ui5_cl_ui5_view_builder=>factory( + )->ele( n = `View` ns = `mvc` + )->a( n = `xmlns` v = `sap.m` + )->a( n = `xmlns:mvc` v = `sap.ui.core.mvc` ). + + DATA(tab) = view->ele( `Shell` + )->ele( `Page` + )->a( n = `title` v = `Walkthrough - Step 9` + + )->ele( `Table` + )->a( n = `headerText` v = `Invoices` + )->a( n = `items` v = client->_bind( t_invoices ) ). + + tab->ele( `columns` + + )->ele( `Column` + )->tag( `Text` + )->a( n = `text` v = `Product` + + )->end( + )->ele( `Column` + )->tag( `Text` + )->a( n = `text` v = `Supplier` + + )->end( + )->ele( `Column` + )->tag( `Text` + )->a( n = `text` v = `Quantity` + + )->end( + )->ele( `Column` + )->tag( `Text` + )->a( n = `text` v = `Delivery Date` + + )->end( + )->ele( `Column` + )->a( n = `width` v = `10%` ). + + tab->ele( `items` + )->ele( `ColumnListItem` + )->ele( `cells` + + )->tag( `Text` + )->a( n = `text` v = `{PRODUCT}` + )->tag( `Text` + )->a( n = `text` v = `{SUPPLIER}` + )->tag( `Text` + )->a( n = `text` v = `{QUANTITY}` + )->tag( `Text` + )->a( n = `text` v = `{DELIVERY_DATE}` + )->tag( `Button` + )->a( n = `icon` v = `sap-icon://edit` + )->a( n = `tooltip` v = `Edit delivery date` + )->a( n = `press` v = client->_event( val = `EDIT` + t_arg = VALUE #( ( `${PRODUCT}` ) ) ) ). + + client->view_display( view->stringify( ) ). + + ELSEIF client->check_on_event( `EDIT` ). + + s_edit = VALUE #( t_invoices[ product = client->get_event_arg( ) ] OPTIONAL ). + + DATA(popup) = z2ui5_cl_ui5_view_builder=>factory( + )->ele( n = `FragmentDefinition` ns = `core` + )->a( n = `xmlns` v = `sap.m` + )->a( n = `xmlns:core` v = `sap.ui.core` + + )->ele( `Dialog` + )->a( n = `title` v = |Edit { s_edit-product }| + + )->ele( `content` + + )->tag( `Label` + )->a( n = `text` v = `Delivery Date` + )->tag( `DatePicker` + )->a( n = `value` v = client->_bind( s_edit-delivery_date ) + )->a( n = `valueFormat` v = `yyyy-MM-dd` + + )->end( + + )->ele( `buttons` + + )->tag( `Button` + )->a( n = `text` v = `Cancel` + )->a( n = `press` v = client->_event( `CANCEL` ) + )->tag( `Button` + )->a( n = `text` v = `Save` + )->a( n = `press` v = client->_event( `SAVE` ) + )->a( n = `type` v = `Emphasized` ). + + client->popup_display( popup->stringify( ) ). + + ELSEIF client->check_on_event( `SAVE` ). + + t_invoices[ product = s_edit-product ]-delivery_date = s_edit-delivery_date. + client->popup_destroy( ). + client->message_toast_display( |{ s_edit-product } updated.| ). + + ELSEIF client->check_on_event( `CANCEL` ). + + client->popup_destroy( ). + + ENDIF. + + ENDMETHOD. +ENDCLASS. +``` + +## Columns and Cells + +- **A table is two aggregations.** `columns` holds one `Column` per column, + each with its header control; `items` holds the row template, whose `cells` + hold one control per column. The two have to line up — the third cell lands + under the third column, whatever it contains. +- **`end( )` ascends.** After a `Column` has been given its header `Text`, the + chain is standing inside that column. `end( )` — alone, in the column of the + `ele( )` it closes — steps back out so the next `Column` becomes a sibling + rather than a child. +- **`tab` holds the table.** The chain is split again: the `Table` goes into a + variable, and `columns` and `items` are filled from it in two statements. A + single chain would work too, but it would ascend six levels between the last + column and the first cell. +- **The fifth column has no header text and a fixed `10%` width.** It only + carries the edit button defined in the row cells — this is how a row action + gets a column of its own. +- **`sap-icon://edit`** is one of the several hundred icons the UI5 icon font + ships. The tooltip is what a reader of the screen — and a screen reader — + gets instead of a label. + +Everything else is [Step 7](/tutorials/walkthrough/step-7) unchanged: the row +event carries `${PRODUCT}`, the dialog binds `s_edit`, and `SAVE` writes back +into the internal table without rebuilding the view. + +One step remains: putting all of it into the shape a real app has. + + + +## Working Samples + +Complete apps from the [sample catalogue](https://github.com/abap2UI5/samples/blob/main/SAMPLES.md) +that use what this page describes. Each is a single class — pull the repository with +[abapGit](https://abapgit.org) and start it with `?app_start=`. + +| Sample | Class | +|---|---| +| Full Example with sap.ui.table | [`Z2UI5_CL_SMP_APP_070`](https://github.com/abap2UI5/samples/blob/main/src/01/z2ui5_cl_smp_app_070.clas.abap) | + +