Skip to main content

sap-ui5-fiori

SAPUI5 and Fiori application development skill. Use when building Fiori apps, writing XML views, creating UI5 controllers, binding OData models, configuring manifest.json, implementing routing, using Fiori Elements (LROP/OVP/ALP), or working with SAP Fiori design guidelines. If the user mentions SAPUI5, Fiori, XML view, UI5 controller, manifest, Fiori Elements, sap.m, sap.ui.table, JSONModel, ODataModel, or Fiori launchpad, use this skill.

الانتقال إلى التثبيت

معلومات المصدر

المستودع
efeumutaslan/SAP-SKILLS
آخر نشاط في المصدر
٨ أبريل ٢٠٢٦ في ١٤:٠٥
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٥
التفرعات
١

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

مستكشف الملفات
6 ملفات

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
sap-ui5-fiori
description
SAPUI5 and Fiori application development skill. Use when building Fiori apps, writing XML views, creating UI5 controllers, binding OData models, configuring manifest.json, implementing routing, using Fiori Elements (LROP/OVP/ALP), or working with SAP Fiori design guidelines. If the user mentions SAPUI5, Fiori, XML view, UI5 controller, manifest, Fiori Elements, sap.m, sap.ui.table, JSONModel, ODataModel, or Fiori launchpad, use this skill.
license
MIT
metadata
{"author":"SAP Skills Community","version":"1.0.0","last_verified":"2026-04-08"}
# 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):** ```bash 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):** ```bash yo @sap/fiori # Select: SAPUI5 Fiori Elements → List Report Object Page (LROP) ``` **Run locally with live-reload:** ```bash npm start # Starts ui5 serve with local OData mock or proxy ``` **Build for deployment:** ```bash 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 ```xml <!-- Property binding: single value --> <Text text="{Name}" /> <!-- Element binding: bind a context (entity) to a control --> <Form binding="{/Products('HT-1001')}"> <!-- Aggregation binding: list of items --> <List items="{/Products}"> <StandardListItem title="{Name}" description="{Category}" /> </List> <!-- Expression binding: computed values --> <ObjectStatus text="{= ${Price} > 100 ? 'Expensive' : 'Cheap' }" /> <!-- i18n binding --> <Button text="{i18n>buttonSave}" /> ``` ### Routing (manifest.json) ```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: ```javascript this.getOwnerComponent().getRouter().navTo("object", { productId: "HT-1001" }); ``` ## Common Patterns ### Pattern 1: Basic controller skeleton ```javascript 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) ```xml <mvc:View controllerName="my.app.controller.Worklist" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Page title="{i18n>worklistTitle}"> <subHeader> <Toolbar> <SearchField width="100%" search=".onSearch" /> </Toolbar> </subHeader> <content> <List id="productsList" items="{path: '/Products', parameters: {$count: true}}" growing="true" growingThreshold="20" growingScrollToLoad="true"> <ObjectListItem title="{Name}" number="{ parts: [{path: 'Price'}, {path: 'CurrencyCode'}], type: 'sap.ui.model.type.Currency', formatOptions: {showMeasure: false} }" numberUnit="{CurrencyCode}" type="Navigation" press=".onItemPress"> <attributes> <ObjectAttribute text="{Category}" /> </attributes> </ObjectListItem> </List> </content> </Page> </mvc:View> ``` ### 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`. ```cds // 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) ```xml <!-- view/Dialog.fragment.xml --> <core:FragmentDefinition xmlns="sap.m" xmlns:core="sap.ui.core"> <Dialog title="{i18n>dialogTitle}"> <content> <Input value="{/newValue}" /> </content> <beginButton> <Button text="OK" press=".onDialogOk" /> </beginButton> <endButton> <Button text="Cancel" press=".onDialogCancel" /> </endButton> </Dialog> </core:FragmentDefinition> ``` ```javascript // 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 ```json { "_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 ```javascript // 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: ```xml <Text text="{path: 'Status', formatter: '.formatter.statusText'}" /> ``` ## 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 |
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub