All skills
secondsky avatar

/sapui5

@620a19a
by Eddiesecondsky/sap-skills456 stars
120

This skill should be used when developing SAP UI5 applications, including creating freestyle apps, Fiori Elements apps, custom controls, testing, data binding, OData integration, routing, and troubleshooting. Use when building enterprise web applications with SAP UI5 framework, implementing MVC patterns, configuring manifest.json, creating XML views, writing controllers, setting up data models (JSON, OData v2/v4), implementing responsive UI with sap.m controls, building Fiori Elements apps, writing unit tests with QUnit, integration tests with OPA5, setting up mock servers, handling security (XSS, CSP), optimizing performance, implementing accessibility features, or debugging UI5 applications. Also covers sap.ui.mdc controls and TypeScript control libraries.

Use this Skill: https://skilld.dev/gh/secondsky/sap-skills/sapui5

This session only. Nothing lands on disk.

referencesdata-binding-models.md

≈4.8k tokens on demand. Your agent reads this file only when SKILL.md points to it.

SAPUI5 Data Binding & Models

Source: Official SAP SAPUI5 Documentation Documentation: https://github.com/SAP-docs/sapui5/tree/main/docs/04_Essentials Last Updated: 2025-11-21


Data Binding Overview

Data binding connects UI controls to data sources, automatically synchronizing changes bidirectionally.

Key Benefits:

  • Automatic UI updates when data changes
  • Reduced boilerplate code
  • Clean separation of data and presentation
  • Type conversion and formatting
  • Validation support

Binding Types:

  1. Property Binding: Single value (text, enabled, visible)
  2. Aggregation Binding: Collections (table items, list items)
  3. Element Binding: Object context
  4. Expression Binding: Inline calculations

Documentation: https://github.com/SAP-docs/sapui5/tree/main/docs/04_Essentials (search: binding, data-binding)


Binding Modes

One-Way Binding:

  • Data flows model → view only
  • UI updates when model changes
  • User input doesn't update model
  • Use for read-only data
// In manifest.json
"models": {
    "": {
        "dataSource": "mainService",
        "settings": {
            "defaultBindingMode": "OneWay"
        }
    }
}

Two-Way Binding:

  • Data flows model ↔ view bidirectionally
  • Model updates when user changes input
  • View updates when model changes
  • Use for editable forms
"defaultBindingMode": "TwoWay"

One-Time Binding:

  • Data loaded once at initialization
  • No updates after initial load
  • Best performance for static data
<Text text="{path: '/title', mode: 'OneTime'}"/>

Documentation: https://github.com/SAP-docs/sapui5/tree/main/docs/04_Essentials (search: binding-mode)


Model Types

JSON Model

Client-side model for JavaScript objects. Best for small datasets and local data.

Creation:

// In controller
var oModel = new JSONModel({
    products: [
        { id: 1, name: "Product 1", price: 100 },
        { id: 2, name: "Product 2", price: 200 }
    ],
    selectedProduct: null
});

this.getView().setModel(oModel);

From File:

var oModel = new JSONModel();
oModel.loadData("model/data.json");
this.getView().setModel(oModel);

Usage:

<List items="{/products}">
    <StandardListItem
        title="{name}"
        description="Price: {price}"/>
</List>

Key Methods:

  • setData(oData): Set complete data
  • setProperty(sPath, oValue): Set single property
  • getProperty(sPath): Get property value
  • loadData(sURL): Load from URL

Documentation: https://github.com/SAP-docs/sapui5/tree/main/docs/04_Essentials (search: json-model)


OData V2 Model

Server-side model for OData v2 services. Automatic CRUD operations.

Creation:

// In manifest.json
{
    "sap.app": {
        "dataSources": {
            "mainService": {
                "uri": "/sap/opu/odata/sap/SERVICE_SRV/",
                "type": "OData",
                "settings": {
                    "odataVersion": "2.0",
                    "localUri": "localService/metadata.xml"
                }
            }
        }
    },
    "sap.ui5": {
        "models": {
            "": {
                "dataSource": "mainService",
                "settings": {
                    "defaultBindingMode": "TwoWay",
                    "defaultCountMode": "Inline",
                    "useBatch": true
                }
            }
        }
    }
}

Reading Data:

// Simple read
this.getView().getModel().read("/Products", {
    success: function(oData) {
        console.log(oData);
    },
    error: function(oError) {
        MessageBox.error("Failed to load data");
    }
});

// With filters and sorters
this.getView().getModel().read("/Products", {
    filters: [new Filter("Price", FilterOperator.GT, 100)],
    sorters: [new Sorter("Name", false)],
    urlParameters: {
        "$expand": "Category"
    },
    success: function(oData) {
        console.log(oData);
    }
});

Creating Entries:

var oModel = this.getView().getModel();
oModel.create("/Products", {
    Name: "New Product",
    Price: 150,
    CategoryID: 1
}, {
    success: function() {
        MessageToast.show("Product created");
    },
    error: function(oError) {
        MessageBox.error("Failed to create product");
    }
});

Updating Entries:

var oModel = this.getView().getModel();
oModel.update("/Products(1)", {
    Price: 200
}, {
    success: function() {
        MessageToast.show("Product updated");
    }
});

Deleting Entries:

oModel.remove("/Products(1)", {
    success: function() {
        MessageToast.show("Product deleted");
    }
});

Batch Requests:

oModel.setUseBatch(true);
oModel.setDeferredGroups(["myGroup"]);

// Add to batch
oModel.create("/Products", oData, { groupId: "myGroup" });
oModel.create("/Products", oData2, { groupId: "myGroup" });

// Submit batch
oModel.submitChanges({
    groupId: "myGroup",
    success: function() {
        MessageToast.show("Batch successful");
    }
});

Key Settings:

  • useBatch: Enable batch requests
  • defaultCountMode: How to get counts (Inline, Request, None)
  • refreshAfterChange: Auto-refresh after updates
  • defaultBindingMode: One-way or two-way

Documentation: https://github.com/SAP-docs/sapui5/tree/main/docs/04_Essentials (search: odata-v2-model)


OData V4 Model

Modern OData v4 model with improved performance and features.

Creation:

// In manifest.json
{
    "sap.app": {
        "dataSources": {
            "mainService": {
                "uri": "/sap/opu/odata4/sap/service/srvd/sap/api/0001/",
                "type": "OData",
                "settings": {
                    "odataVersion": "4.0"
                }
            }
        }
    },
    "sap.ui5": {
        "models": {
            "": {
                "dataSource": "mainService",
                "settings": {
                    "synchronizationMode": "None",
                    "operationMode": "Server",
                    "autoExpandSelect": true,
                    "earlyRequests": true
                }
            }
        }
    }
}

Key Differences from V2:

  • Server-side operations (filter, sort, page)
  • Automatic $expand and $select
  • Better performance
  • Stricter adherence to OData standard
  • No client-side models

Reading with List Binding:

<Table items="{
    path: '/Products',
    parameters: {
        $expand: 'Category',
        $select: 'ID,Name,Price',
        $filter: 'Price gt 100',
        $orderby: 'Name'
    }
}">

Creating Entries:

var oListBinding = this.byId("table").getBinding("items");
var oContext = oListBinding.create({
    Name: "New Product",
    Price: 150
});

// Save
oContext.created().then(function() {
    MessageToast.show("Product created");
});

Updating:

var oContext = this.byId("table").getSelectedItem().getBindingContext();
oContext.setProperty("Price", 200);

// Save changes
oContext.getModel().submitBatch("$auto").then(function() {
    MessageToast.show("Updated");
});

Deleting:

var oContext = this.byId("table").getSelectedItem().getBindingContext();
oContext.delete("$auto").then(function() {
    MessageToast.show("Deleted");
});

Documentation: https://github.com/SAP-docs/sapui5/tree/main/docs/04_Essentials (search: odata-v4-model)


Resource Model (i18n)

Model for internationalization texts.

Setup:

// In manifest.json
{
    "sap.ui5": {
        "models": {
            "i18n": {
                "type": "sap.ui.model.resource.ResourceModel",
                "settings": {
                    "bundleName": "com.mycompany.myapp.i18n.i18n",
                    "supportedLocales": ["en", "de", "fr"],
                    "fallbackLocale": "en"
                }
            }
        }
    }
}

i18n.properties:

appTitle=My Application
appDescription=A sample SAPUI5 application

# Buttons
btnSave=Save
btnCancel=Cancel
btnDelete=Delete

# Messages
msgSaveSuccess=Data saved successfully
msgDeleteConfirm=Do you want to delete this item?

# Placeholders with parameters
msgItemCount=You have {0} items selected
msgWelcome=Welcome, {0}!

Usage in XML:

<Page title="{i18n>appTitle}">
    <Button text="{i18n>btnSave}" press=".onSave"/>
    <Text text="{i18n>appDescription}"/>
</Page>

Usage in Controller:

var oBundle = this.getView().getModel("i18n").getResourceBundle();
var sTitle = oBundle.getText("appTitle");

// With parameters
var sMessage = oBundle.getText("msgItemCount", [5]);
MessageBox.success(sMessage);

Locale Files:

  • i18n.properties: Default (fallback)
  • i18n_de.properties: German
  • i18n_en.properties: English
  • i18n_fr.properties: French

Documentation: https://github.com/SAP-docs/sapui5/tree/main/docs/04_Essentials (search: resource-model, i18n)


XML Model

Client-side model for XML data structures.

Creation:

var oModel = new XMLModel();
oModel.loadData("model/data.xml");
this.getView().setModel(oModel, "xml");

Usage:

<List items="{xml>/products/product}">
    <StandardListItem
        title="{xml>name}"
        description="{xml>price}"/>
</List>

Use Cases:

  • Legacy XML data sources
  • Configuration files
  • Small datasets

Documentation: https://github.com/SAP-docs/sapui5/tree/main/docs/04_Essentials (search: xml-model)


Binding Syntax

Property Binding

Simple Binding:

<Text text="{/companyName}"/>
<Input value="{/employeeName}"/>

Named Models:

<Text text="{invoice>/company/name}"/>
<Input value="{customer>/email}"/>

Binding Options:

<Text text="{
    path: '/price',
    type: 'sap.ui.model.type.Currency',
    formatOptions: {
        showMeasure: false
    },
    constraints: {
        minimum: 0
    }
}"/>

Composite Binding:

<Text text="{
    parts: [
        {path: '/firstName'},
        {path: '/lastName'}
    ],
    formatter: '.formatFullName'
}"/>

Controller:

formatFullName: function(sFirstName, sLastName) {
    return sFirstName + " " + sLastName;
}

Aggregation Binding

List Binding:

<List items="{/products}">
    <StandardListItem
        title="{name}"
        description="{description}"
        info="{price} EUR"/>
</List>

Table Binding:

<Table items="{
    path: '/products',
    sorter: {
        path: 'name'
    },
    filters: {
        path: 'price',
        operator: 'GT',
        value1: 50
    }
}">
    <columns>
        <Column><Text text="Name"/></Column>
        <Column><Text text="Price"/></Column>
    </columns>
    <items>
        <ColumnListItem>
            <cells>
                <Text text="{name}"/>
                <Text text="{price}"/>
            </cells>
        </ColumnListItem>
    </items>
</Table>

With Parameters:

<Table items="{
    path: '/Products',
    parameters: {
        expand: 'Category',
        select: 'ID,Name,Price'
    }
}">

Element Binding

Sets binding context for entire control:

<Panel binding="{/selectedProduct}">
    <VBox>
        <Text text="{name}"/>
        <Text text="{description}"/>
        <Text text="{price} EUR"/>
    </VBox>
</Panel>
// In controller
onProductSelect: function(oEvent) {
    var oItem = oEvent.getParameter("listItem");
    var sPath = oItem.getBindingContext().getPath();

    this.byId("detailPanel").bindElement({
        path: sPath,
        parameters: {
            expand: "Category"
        }
    });
}

Expression Binding

Inline calculations without formatter:

<!-- Conditional text color -->
<Text
    text="{price}"
    color="{= ${price} > 100 ? 'red' : 'green'}"/>

<!-- Conditional visibility -->
<Button
    visible="{= ${status} === 'approved'}"
    text="Process"/>

<!-- Calculations -->
<Text text="{= ${quantity} * ${price}}"/>

<!-- String operations -->
<Text text="{= ${firstName} + ' ' + ${lastName}}"/>

<!-- Comparisons -->
<Button enabled="{= ${quantity} > 0 &amp;&amp; ${stock} >= ${quantity}}"/>

Supported Operations:

  • Arithmetic: +, -, *, /, %
  • Comparison: ===, !==, >, <, >=, <=
  • Logical: &&, ||, !
  • Ternary: condition ? true : false
  • String concatenation: +

Limitations:

  • Simple expressions only
  • No function calls
  • Use formatters for complex logic

Formatters & Data Types

Custom Formatters

Definition:

// In controller or separate formatter.js
formatPrice: function(sPrice) {
    if (!sPrice) return "";
    return parseFloat(sPrice).toFixed(2) + " EUR";
},

formatStatus: function(sStatus) {
    var mStatusText = {
        "A": "Approved",
        "R": "Rejected",
        "P": "Pending"
    };
    return mStatusText[sStatus] || sStatus;
},

formatDate: function(oDate) {
    if (!oDate) return "";
    var oDateFormat = sap.ui.core.format.DateFormat.getDateInstance({
        pattern: "dd.MM.yyyy"
    });
    return oDateFormat.format(oDate);
}

Usage:

<Text text="{path: 'price', formatter: '.formatPrice'}"/>
<Text text="{path: 'status', formatter: '.formatStatus'}"/>
<Text text="{path: 'createdAt', formatter: '.formatDate'}"/>

Multiple Parameters:

<Text text="{
    parts: ['quantity', 'price'],
    formatter: '.formatTotal'
}"/>
formatTotal: function(iQuantity, fPrice) {
    return (iQuantity * fPrice).toFixed(2) + " EUR";
}

Built-in Data Types

String Type:

<Input value="{
    path: '/name',
    type: 'sap.ui.model.type.String',
    constraints: {
        maxLength: 50,
        minLength: 2
    }
}"/>

Integer Type:

<Input value="{
    path: '/quantity',
    type: 'sap.ui.model.type.Integer',
    constraints: {
        minimum: 1,
        maximum: 999
    }
}"/>

Float Type:

<Input value="{
    path: '/price',
    type: 'sap.ui.model.type.Float',
    constraints: {
        minimum: 0,
        maximum: 99999.99
    },
    formatOptions: {
        minFractionDigits: 2,
        maxFractionDigits: 2
    }
}"/>

Date Type:

<DatePicker value="{
    path: '/orderDate',
    type: 'sap.ui.model.type.Date',
    formatOptions: {
        pattern: 'dd.MM.yyyy'
    }
}"/>

DateTime Type:

<DateTimePicker value="{
    path: '/createdAt',
    type: 'sap.ui.model.type.DateTime',
    formatOptions: {
        pattern: 'dd.MM.yyyy HH:mm:ss'
    }
}"/>

Currency Type:

<Text text="{
    parts: [
        {path: 'price'},
        {path: 'currency'}
    ],
    type: 'sap.ui.model.type.Currency',
    formatOptions: {
        showMeasure: true
    }
}"/>

Boolean Type:

<CheckBox selected="{
    path: '/isActive',
    type: 'sap.ui.model.type.Boolean'
}"/>

Filters & Sorters

Filters

Simple Filter:

var oFilter = new Filter("price", FilterOperator.GT, 100);
var oBinding = this.byId("table").getBinding("items");
oBinding.filter([oFilter]);

Multiple Filters (AND):

var aFilters = [
    new Filter("price", FilterOperator.GT, 100),
    new Filter("category", FilterOperator.EQ, "Electronics")
];
oBinding.filter(aFilters); // AND condition

Multiple Filters (OR):

var aFilters = [
    new Filter("status", FilterOperator.EQ, "Approved"),
    new Filter("status", FilterOperator.EQ, "Pending")
];
var oCombinedFilter = new Filter({
    filters: aFilters,
    and: false // OR condition
});
oBinding.filter([oCombinedFilter]);

Complex Filters:

var oPriceFilter = new Filter({
    filters: [
        new Filter("price", FilterOperator.GT, 100),
        new Filter("price", FilterOperator.LT, 500)
    ],
    and: true
});

var oStatusFilter = new Filter({
    filters: [
        new Filter("status", FilterOperator.EQ, "A"),
        new Filter("status", FilterOperator.EQ, "P")
    ],
    and: false
});

var oCombinedFilter = new Filter({
    filters: [oPriceFilter, oStatusFilter],
    and: true
});

oBinding.filter([oCombinedFilter]);

Filter Operators:

  • EQ: Equals
  • NE: Not equals
  • GT: Greater than
  • GE: Greater or equal
  • LT: Less than
  • LE: Less or equal
  • Contains: Contains text
  • StartsWith: Starts with text
  • EndsWith: Ends with text
  • BT: Between (requires value1 and value2)

Custom Filter Function:

var oFilter = new Filter({
    path: "price",
    test: function(oValue) {
        return oValue > 100 && oValue < 500;
    }
});

Sorters

Simple Sort:

var oSorter = new Sorter("name", false); // false = ascending
var oBinding = this.byId("table").getBinding("items");
oBinding.sort(oSorter);

Multiple Sorters:

var aSorters = [
    new Sorter("category", false),
    new Sorter("price", true) // true = descending
];
oBinding.sort(aSorters);

Sort with Grouping:

var oSorter = new Sorter("category", false, true); // third param = group
oBinding.sort(oSorter);

Custom Group Function:

var oSorter = new Sorter("price", false, function(oContext) {
    var fPrice = oContext.getProperty("price");
    if (fPrice < 100) return { key: "low", text: "Low Price" };
    if (fPrice < 500) return { key: "medium", text: "Medium Price" };
    return { key: "high", text: "High Price" };
});

Links to Official Documentation


Note: This document covers data binding and model usage in SAPUI5. For specific implementation details and advanced scenarios, refer to the official documentation links provided.

Source: SKILL.md on GitHub

No alerts1mo3 checks · Risk SAFE
  • Gen Agent Trust Hub1mo

    The sapui5 skill is a high-quality development assistant for building enterprise applications with the SAPUI5 framework. It provides extensive documentation, best practice checklists, and templates for components, controllers, and views. The skill also integrates with official SAP tools like the @ui5/mcp-server for advanced features like live code linting and project scaffolding. No security risks or malicious patterns were found; the skill even includes a dedicated guide on security best practices for developers.

  • Socket1mo

    No alerts

  • Snyk1mo

    Risk: LOW · No issues

Signed by skilld at 620a19a. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 weeks ago.

Activeupdated 2 months ago
Other metadata
metadata
{
  "maintainer": "Eduard Jiglau",
  "maintainer_email": "hello@sap-ai-skills.com",
  "website": "https://sap-ai-skills.com",
  "version": "2.4.1",
  "last_verified": "2026-05-31",
  "framework_version": "1.148.1 latest verified, 1.120.0+ baseline",
  "documentation_source": "https://github.com/SAP-docs/sapui5",
  "documentation_files_analyzed": 1416,
  "reference_files": 15,
  "mcp_integration": true,
  "mcp_tools": 9,
  "specialized_agents": 4,
  "slash_commands": 5,
  "status": "production",
  "keywords": [
    "sapui5",
    "ui5",
    "openui5",
    "sap ui5",
    "ui5 framework",
    "ui5 application",
    "ui5 development",
    "ui5 tooling",
    "ui5 cli",
    "Component.js",
    "manifest.json",
    "xml view",
    "data binding",
    "odata v2",
    "odata v4",
    "fiori elements",
    "sap.m controls",
    "mvc pattern",
    "routing",
    "navigation",
    "qunit",
    "opa5",
    "testing",
    "mock server",
    "sap.ui.mdc",
    "mdc table",
    "typescript",
    "accessibility",
    "security",
    "performance",
    "ui5 inspector"
  ]
}

README badge

README badge for secondsky/sap-skills/sapui5