Fiori Elements
RAP / CDS / ODataintermediate

Fiori Elements Part 4: Extending Apps with the Flexible Programming Model

Key takeaway

Learn how to add custom logic, actions, and UI fragments to a generated Fiori Elements app without breaking the annotation-driven contract, using the flexible programming model's controller extensions and extension points.

Explanation

📌 KEY POINTS
✅ The flexible programming model lets you extend Fiori Elements without leaving the floorplan.

✅ Extension points: custom sections, custom columns, custom actions, controller extensions.

✅ Configure extensions in manifest.json; keep code small and in dedicated fragments/controllers.

⚠️ Prefer annotations first — extend only for what annotations cannot express.

━━━━━━━━━━━━━━━━━━━━
▶ WHERE WE ARE

Part 3 covered what annotations can do. Some requirements go beyond them — the flexible programming model handles those without leaving the Fiori Elements floorplan.

━━━━━━━━━━━━━━━━━━━━
▶ 1. WHAT THE FLEXIBLE PROGRAMMING MODEL IS

  • Available for Fiori Elements on OData V4.
  • Mix generated floorplans with custom UI5 fragments and controller code at defined extension points.
  • The app remains a Fiori Elements app: updates of the floorplan still apply.

━━━━━━━━━━━━━━━━━━━━
▶ 2. EXTENSION POINTS

  • Custom section on the object page (a fragment with your own content).
  • Custom column in a table (e.g. a chart or special formatting).
  • Custom action in a toolbar or header (controller handler).
  • Controller extensions (e.g. onBeforeSave hooks) for lifecycle logic.
  • Building blocks (macros) such as Table, Chart, Field for use inside custom sections.

━━━━━━━━━━━━━━━━━━━━
▶ 3. CONFIGURATION

  • Extensions are registered in manifest.json under the page target's settings (content → body → sections / controlConfiguration / actions).
  • SAP Fiori tools Page Map generates the entries and stubs.
  • Keep each extension in its own fragment/controller file.

━━━━━━━━━━━━━━━━━━━━
▶ 4. WHERE LOGIC BELONGS

  • Business rules stay in the RAP BO (validations, determinations, feature control).
  • UI extension code only presents or orchestrates.
  • A custom action that changes data calls a RAP action — it never writes data itself.

━━━━━━━━━━━━━━━━━━━━
▶ 5. ANNOTATIONS FIRST

  • Before extending, check the annotation reference for a standard solution.
  • Every extension is code to test and maintain at each UI5 upgrade.
  • Document why an extension was needed.

━━━━━━━━━━━━━━━━━━━━
▶ STEP BY STEP

  1. Confirm the requirement cannot be met with annotations.
  2. Use the Page Map to add a custom section or action.
  3. Implement the fragment/controller, calling the OData V4 model or a RAP action.
  4. Test with draft and with a user without authorization.

✅ CHECKPOINT: the custom section appears on the object page and the standard Edit/Save flow still works.

Code example

ABAP Code
// ===== manifest.json: custom section on the object page (flexible programming model) ====="sap.ui5": {  "routing": {    "targets": {      "PurchaseRequestObjectPage": {        "type": "Component",        "name": "sap.fe.templates.ObjectPage",        "options": {          "settings": {            "contextPath": "/PurchaseRequest",            "content": {              "body": {                "sections": {                  "approvalHistory": {                        // custom section                    "template": "zpurchreq.ext.fragment.ApprovalHistory",                    "title": "Approval History",                    "position": { "placement": "After", "anchor": "Items" }                  }                }              }            },            "controlConfiguration": {              "_Item/@com.sap.vocabularies.UI.v1.LineItem": {                "actions": {                  "checkStock": {                             // custom table action                    "press": "zpurchreq.ext.controller.ItemActions.onCheckStock",                    "text": "Check Stock",                    "requiresSelection": true                  }                }              }            }          }        }      }    }  }} <!-- ===== ext/fragment/ApprovalHistory.fragment.xml ===== --><core:FragmentDefinition xmlns:core="sap.ui.core" xmlns="sap.m">  <List items="{path: '_ApprovalLog', parameters: {$orderby: 'ChangedAt desc'}}">    <StandardListItem title="{ApprovedBy}" description="{Comment}" info="{ChangedAt}" />  </List></core:FragmentDefinition> // ===== ext/controller/ItemActions.js =====sap.ui.define(["sap/m/MessageToast"], function (MessageToast) {  "use strict";  return {    onCheckStock: function (oContext, aSelectedContexts) {      // keep logic small; business checks belong in a RAP action      MessageToast.show(aSelectedContexts.length + " item(s) checked");    }  };}); // Rule: annotations first -> building blocks / extensions only for the rest

Real project scenario

On a sales order management RAP app, business asked for an 'Escalate to Manager' button that appears only for orders over a threshold value and in 'Pending' status, sends a custom action to update escalation flag and log a note, then automatically refreshes the approval status field and re-evaluates the exception icon in the list report line.

Common mistakes

  • Implementing an entire custom action in JavaScript on the frontend instead of exposing it as a proper RAP custom action, bypassing draft and authorization consistency checks
  • Forgetting Common.SideEffects annotations after a custom action changes dependent fields, leaving the UI showing stale data
  • Modifying generated fragment/controller files directly instead of using controller extensions, which breaks on the next code regeneration or app update
  • Mixing key-user adaptation changes with developer extensions in a way that creates layer conflicts and unpredictable precedence at runtime
  • Not testing custom actions with concurrent drafts, causing lock or ETag conflicts in production that were never seen in single-user dev testing

Best practices

  • Prefer annotation-driven solutions (UI.Applicable, UI.Hidden, Validation, Determination) before reaching for controller extensions
  • Always pair a custom action or determination that changes dependent fields with an explicit Common.SideEffects annotation
  • Keep custom logic in the RAP behavior pool, not scattered in frontend JavaScript, to preserve consistency, authorization checks, and testability
  • Use manifest.json extension points and controller extensions rather than touching generated artifacts directly
  • Document each extension point used and its extensibility category (key user vs developer) for upgrade impact assessments

Interview angle

Interviewers probe whether you understand the difference between annotation-only design and flexible programming model extensions, and whether you know when NOT to extend (i.e., prefer declarative solutions). Be ready to explain SideEffects, extension points in manifest.json, and the layered extensibility model (key user vs developer, cloud vs on-premise) as this signals real hands-on RAP+Fiori Elements delivery experience rather than tutorial-level exposure.

Practice this lesson

Quick check

1. A requirement needs an approval-history section that annotations cannot express. What is the recommended approach?

2. In a RAP-based Fiori Elements application, what is the main purpose of side effects annotations?

3. Which annotation allows a field's editability to be determined dynamically at runtime based on the value of another field, rather than being statically fixed in the UI?

Interview questions

1. Where should business validations live in a RAP-based Fiori Elements application?

Answer it in your own words first, then compare.

2. A requirement cannot be met with annotations alone. How do you extend a Fiori Elements app?

Answer it in your own words first, then compare.

Practice more with Interview AI →

Reference-verified: the steps are checked against official SAP documentation and tutorials, and object and field names in the sample code are checked for consistency. The code has not been compiled or run on an SAP system by ERPClimb. Syntax marked release-dependent varies by SAP release, so check it in your own system.

More lessons in this topic

Interview questions on this topic

Related SAP topics