AgentStack
SKILL verified MIT Self-run

Sap Ui5 Fiori

skill-efeumutaslan-sap-skills-sap-ui5-fiori · by efeumutaslan

>

No reviews yet
0 installs
3 views
0.0% view→install

Install

$ agentstack add skill-efeumutaslan-sap-skills-sap-ui5-fiori

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Sap Ui5 Fiori? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

SAPUI5 and Fiori Application Development

Related Skills

  • sap-fiori-testing — OPA5, wdi5, accessibility testing for the apps built here
  • sap-odata — OData v2/v4 service design and consumption (the backend for most Fiori apps)
  • sap-rap-comprehensive — RAP backends that auto-generate OData for UI5 consumption
  • sap-cap-advanced — CAP backends with CDS-based OData services
  • sap-build-apps — Low-code alternative when full UI5 is overkill

Quick Start

Scaffold a new freestyle UI5 app (Fiori Tools):

npm install -g @sap/generator-fiori
yo @sap/fiori
# Select: SAPUI5 freestyle → Basic → OData V4 service → project details

Scaffold a Fiori Elements app (zero-code UI):

yo @sap/fiori
# Select: SAPUI5 Fiori Elements → List Report Object Page (LROP)

Run locally with live-reload:

npm start                     # Starts ui5 serve with local OData mock or proxy

Build for deployment:

npm run build                 # Produces dist/ folder
npm run deploy                # Deploys to ABAP, CF, or HTML5 repo

Core Concepts

MVC architecture

app/
├── webapp/
│   ├── Component.js          # Component: root, manifest, models, router
│   ├── manifest.json         # App descriptor (routes, models, data sources)
│   ├── view/                 # XML views (declarative UI)
│   │   ├── App.view.xml
│   │   ├── Worklist.view.xml
│   │   └── Object.view.xml
│   ├── controller/           # Controller logic (event handlers, business logic)
│   │   ├── App.controller.js
│   │   ├── Worklist.controller.js
│   │   └── Object.controller.js
│   ├── model/                # Formatters, grouping, custom models
│   │   └── formatter.js
│   ├── i18n/                 # Translations
│   │   └── i18n.properties
│   ├── css/                  # Custom styles
│   └── test/                 # QUnit/OPA5 tests
├── ui5.yaml                  # UI5 tooling config
└── package.json

Models (critical to understand)

| Model | Use case | Binding syntax | |-------|----------|----------------| | JSONModel | Client-side state, mock data, view state | {/path/to/value} | | ODataModel (v4) | Primary for SAPUI5 + modern SAP backends | {propertyName} or {BindingPath} | | ODataModel (v2) | Legacy OData services, Gateway services | {propertyName} | | ResourceModel | i18n texts from .properties files | {i18n>textKey} | | DeviceModel | Device info (phone/tablet/desktop, orientation) | {device>/system/phone} |

Binding modes


  

 100 ? 'Expensive' : 'Cheap' }" />

buttonSave}" />

Routing (manifest.json)

"routing": {
  "config": {
    "routerClass": "sap.m.routing.Router",
    "viewType": "XML",
    "viewPath": "my.app.view",
    "controlId": "app",
    "controlAggregation": "pages"
  },
  "routes": [
    { "name": "worklist", "pattern": "", "target": "worklist" },
    { "name": "object", "pattern": "Products/{productId}", "target": "object" }
  ],
  "targets": {
    "worklist": { "viewName": "Worklist" },
    "object":   { "viewName": "Object" }
  }
}

Navigate from a controller:

this.getOwnerComponent().getRouter().navTo("object", { productId: "HT-1001" });

Common Patterns

Pattern 1: Basic controller skeleton

sap.ui.define([
  "sap/ui/core/mvc/Controller",
  "sap/ui/model/json/JSONModel",
  "sap/m/MessageToast"
], function (Controller, JSONModel, MessageToast) {
  "use strict";

  return Controller.extend("my.app.controller.Worklist", {

    onInit: function () {
      const oViewModel = new JSONModel({ busy: false, delay: 0 });
      this.getView().setModel(oViewModel, "viewModel");
    },

    onRefresh: function () {
      const oList = this.byId("productsList");
      oList.getBinding("items").refresh();
    },

    onItemPress: function (oEvent) {
      const sPath = oEvent.getSource().getBindingContext().getPath();
      const sProductId = sPath.match(/'([^']+)'/)[1];
      this.getOwnerComponent().getRouter().navTo("object", { productId: sProductId });
    },

    onSearch: function (oEvent) {
      const sQuery = oEvent.getParameter("query");
      const oBinding = this.byId("productsList").getBinding("items");
      const aFilters = sQuery ? [new sap.ui.model.Filter("Name", "Contains", sQuery)] : [];
      oBinding.filter(aFilters);
    }
  });
});

Pattern 2: Worklist XML view (list + search + pull-to-refresh)


  worklistTitle}">
    
      
        
      
    
    
      
        
          
            
          
        
      
    
  

Pattern 3: Fiori Elements — annotation-driven LROP

With Fiori Elements you write no controller code. The UI is generated from CDS annotations or manifest.json + metadata.xml.

// Backend annotations (CAP/CDS)
annotate Products with @(
  UI.LineItem: [
    { Value: ID },
    { Value: Name },
    { Value: Category },
    { Value: Price }
  ],
  UI.HeaderInfo: {
    TypeName: 'Product',
    TypeNamePlural: 'Products',
    Title: { Value: Name }
  },
  UI.SelectionFields: [ Category, Price ]
);

The UI5 app's manifest.json references sap.fe.templates.ListReport and the OData service — that's it. The app auto-renders a filter bar, table, and detail page.

Pattern 4: Fragments (reusable UI chunks)


  dialogTitle}">
    
      
    
    
      
    
    
      
    
  
// Controller
onOpenDialog: async function () {
  if (!this._oDialog) {
    this._oDialog = await this.loadFragment({ name: "my.app.view.Dialog" });
  }
  this._oDialog.open();
}

Pattern 5: manifest.json essentials

{
  "_version": "1.58.0",
  "sap.app": {
    "id": "my.app",
    "type": "application",
    "dataSources": {
      "mainService": {
        "uri": "/sap/opu/odata/sap/ZMY_SERVICE/",
        "type": "OData",
        "settings": { "odataVersion": "4.0" }
      }
    }
  },
  "sap.ui5": {
    "dependencies": {
      "minUI5Version": "1.120.0",
      "libs": { "sap.m": {}, "sap.ui.core": {}, "sap.f": {} }
    },
    "models": {
      "i18n": { "type": "sap.ui.model.resource.ResourceModel",
                "settings": { "bundleName": "my.app.i18n.i18n" } },
      "": {
        "dataSource": "mainService",
        "preload": true,
        "settings": {
          "synchronizationMode": "None",
          "operationMode": "Server",
          "autoExpandSelect": true,
          "earlyRequests": true
        }
      }
    },
    "routing": { /* ... see Routing section */ }
  }
}

Pattern 6: Custom formatters

// model/formatter.js
sap.ui.define([], function () {
  "use strict";
  return {
    statusText: function (sStatus) {
      const oBundle = this.getOwnerComponent().getModel("i18n").getResourceBundle();
      switch (sStatus) {
        case "A": return oBundle.getText("statusActive");
        case "I": return oBundle.getText("statusInactive");
        default:  return sStatus;
      }
    },
    currencyValue: function (sValue) {
      return sValue ? parseFloat(sValue).toFixed(2) : "";
    }
  };
});

Use in XML:

Error Catalog

| Error | Cause | Fix | |-------|-------|-----| | Cannot read property 'getText' of undefined | i18n model not loaded when controller reads it | Read i18n inside onInit AFTER this.getView().getModel("i18n").getResourceBundle() is available, not at module scope | | The given binding path "/X" is invalid | Path doesn't exist in model or model name is wrong | Use debug tools (Ctrl+Alt+Shift+P) to inspect bindings; check model name prefix (i18n>, device>) | | 404 on /sap/opu/odata/... | Service not activated or wrong path | In SEGW: activate service in /IWFND/MAINT_SERVICE; in RAP: check service binding Publish | | No class sap.m.Xyz | Typo in control name or library not loaded | Check spelling, add the library to sap.ui5.dependencies.libs in manifest.json | | Cannot read properties of null (reading 'getBindingContext') | Control not yet rendered when handler fires | Use onAfterRendering or attachEventOnce instead of onInit | | CSRF token validation failed | Missing X-CSRF-Token on write requests | ODataModel handles this automatically; if using custom fetch, first send GET with X-CSRF-Token: Fetch, reuse token for POST/PUT/DELETE | | sap.ui.model.odata.v4.ODataListBinding: Path does not have a type | autoExpandSelect: true with a path the service doesn't expose | Set autoExpandSelect: false OR make sure every bound property is in the service metadata | | UI5 app works locally but 404 on BTP | destinations not configured in xs-app.json | Add a route pointing to the destination; verify destination exists in BTP cockpit |

Performance Tips

  1. autoExpandSelect: true (OData v4) — UI5 automatically adds $select and $expand based on bindings, reducing payload size by 60–80%.
  2. growing="true" with growingThreshold — never load thousands of rows; let the user scroll to fetch more.
  3. Preload components — set "preload": true on critical models in manifest for parallel loading.
  4. Use sap.ui.table.Table for 1000+ rows — it virtualizes rows, unlike sap.m.Table.
  5. Avoid forceUpdate() — prefer binding refresh over full re-render.
  6. Lazy-load fragments — load dialogs/popovers on first open, not in onInit.
  7. async: true in Component — enable async routing and view loading.
  8. Use sap-ui-compatVersion=edge — removes legacy code paths.
  9. Minify + preload in buildui5 build --clean-dest --all produces Component-preload.js (single-file bundle).
  10. Avoid deep $expand — prefer separate batch requests; deeply nested expands kill response time.

Gotchas

  • this binding in async callbacks — use arrow functions or .bind(this); regular function expressions lose this.
  • OData v2 vs v4 path syntax — v2: /Products('HT-1001'); v4: /Products(ID='HT-1001'). They are NOT interchangeable.
  • Two-way binding requires change events — without them, the model is updated but the server is not.
  • sap.ui.getCore().byId() is deprecated — use this.byId() inside controllers or view's byId().
  • Fragments share the controller of the view that loaded them — event handlers refer to the view controller, not a separate one.
  • Duplicate IDs across fragments — when a fragment is loaded multiple times, prefix IDs with this.createId() or use addDependent().
  • manifest.json changes need a full app reload — hot-reload doesn't pick them up.
  • sap.m.Table vs sap.ui.table.Table — the first is responsive (mobile-first), the second is desktop-only. Pick based on target devices.

Fiori Elements (when to use it)

Use Fiori Elements when:

  • The UI is mostly CRUD over a well-modeled entity
  • You want consistent Fiori look without custom code
  • You can annotate the backend (CAP/CDS) with UI.* annotations
  • The template (LROP/OVP/ALP) matches the use case

Avoid Fiori Elements when:

  • The UI needs heavy customization (custom visualizations, wizards)
  • The data model is flat or non-standard
  • You need pixel-perfect design control

Templates:

  • LROP (List Report Object Page): filter → table → detail — the most common pattern
  • OVP (Overview Page): card-based dashboard
  • ALP (Analytical List Page): chart + table analytics
  • Worklist: focused task lists

Custom extensions:

  • Extension points: @sap/ux-specification defines where you can inject custom fragments/controllers
  • Flexible programming model: sap.fe.core.controllerextensions.* for lifecycle hooks

References

  • references/bindings-cheatsheet.md — Complete binding syntax reference
  • references/fiori-elements-annotations.md — UI.* annotation catalog for LROP/OVP/ALP
  • references/controls-catalog.md — When to use which UI5 control
  • templates/controller-template.js — Copy-paste controller skeleton
  • templates/xml-view-template.xml — Copy-paste XML view skeleton
  • templates/manifest-template.json — Copy-paste manifest.json

MCP Server Integration

For live UI5 development assistance, pair this skill with:

  • @ui5/mcp-server — UI5 control info, API lookup, sample code
  • @sap-ux/fiori-mcp-server — Fiori Tools operations (generate app, build, deploy)
  • @sap/mdk-mcp-server — MDK for mobile-first scenarios

Install via mcp-configs/fullstack-btp.json.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.