Mein Icon

SAP MDK: Gezielte Entitätssuche mit clientAPI.read und Action Binding

23. Juli 2025·15 Minuten zu lesen
sap-mdk-gezielte-entitaetssuche-action-binding-clientapi

Einführung: Von der Liste zur gezielten Suche in SAP MDK

In vielen SAP MDK-Anwendungen ist der Standard-Flow klar: Ein komplettes EntitySet, wie eine Produktliste, wird in einer Tabelle oder Liste angezeigt. Der Nutzer wählt einen Eintrag aus, und eine Navigation Action leitet ihn auf eine Detailseite weiter, wobei der Kontext des ausgewählten Eintrags automatisch übergeben wird.

Doch was ist, wenn dieser Umweg über eine Liste nicht gewünscht ist? Was, wenn der Anwender eine bekannte ProductID direkt eingeben und sofort zur Detailseite des spezifischen Produkts springen möchte?

Genau dieses Szenario lösen wir in diesem Tutorial. Ich zeige Ihnen, wie Sie mit der MDK-Schnittstelle clientAPI.read und dem mächtigen Action Binding eine effiziente, gezielte Suche nach einer einzelnen Entität realisieren.

Tipp: Falls Sie neu im Thema MDK sind, empfehlen wir für das grundlegende Setup das offizielle SAP Tutorial: Getting Started with the SAP Mobile Development Kit

Anwendungsfall: Direktsprung zur Produktdetailseite

SAP_MDK_Action_Binding_Read_Entity

Wir entwerfen eine einfache Benutzeroberfläche, die bewusst auf eine vollflächige Liste verzichtet. Stattdessen bieten wir dem Nutzer:

  1. Ein Eingabefeld, um eine ProductID einzugeben.
  2. Einen "Suchen"-Button, der eine MDK-Rule auslöst.
  3. Diese Rule führt einen gezielten Backend-Aufruf mit einem Filter aus (z.B. Products?$filter=ProductID eq 'HT-1000').
  4. Das Ergebnis – idealerweise genau ein Datensatz – wird per Action Binding an die Detailseite übergeben.
  5. Die Detailseite zeigt die Informationen des gefundenen Produkts an.

Dieser Ansatz ist deutlich performanter und benutzerfreundlicher für Anwendungsfälle, in denen die Kennung des gesuchten Objekts bereits bekannt ist (z.B. beim Scannen eines Barcodes).

Der Kern: Die Rule mit clientAPI.read und Action Binding

Das Herzstück unserer Logik ist eine JavaScript-Rule. Diese wird ausgeführt, sobald der Nutzer auf den "Suchen"-Button klickt. Sie liest den Wert aus dem Eingabefeld, führt den read-Aufruf aus und navigiert im Erfolgsfall zur nächsten Seite.

Hier ist der kommentierte Code der Rule Search_Product_Rule.js:

/**
 * Liest eine Produkt-ID aus der UI, ruft das Backend mit einem Filter auf
 * und bindet das Ergebnis an die nächste Action.
 * @param {{ evaluateTargetPath: Function, executeAction: Function, read: Function, getPageProxy: Function }} clientAPI
 */
export default function Search_Product_Rule(clientAPI) {
    
    // 1. Wert aus dem Eingabefeld mit der ID 'ProductIdInput' auslesen
    
    const productId = clientAPI.evaluateTargetPath('#Control:ProductIdInput/#Value');

    // 2. Eingabe validieren: Ist das Feld leer?
    
    if (!productId || productId.length === 0) {  
        // Informative Nachricht für den Benutzer anzeigen
        return clientAPI.executeAction({
            "Name": "/demosampleapp/Actions/GenericToastMessage.action",
            "Properties": {
                "Message": "Bitte geben Sie eine Produkt-ID ein.",
                "Duration": 4
            }
        });
    }

    // 3. Gezielter OData-Read-Aufruf
    // Service-Pfad, Entitätsmenge, leeres Array für alle Properties, und die Filter-Query
    
    return clientAPI.read(
        "/demosampleapp/Services/YourService.service", // Pfad zu Ihrem Service
        "Products", // Name des EntitySets
        [], // Leeres Array, um alle Properties zu laden
        `$filter=ProductID eq ${productId}` // Die OData-Filter-Query
    ).then((data) => {
        const pageProxy = clientAPI.getPageProxy();
        
        // 4. Prüfen, ob Daten zurückgegeben wurden
        
        if (data && data.length > 0) {
            // WICHTIG: Das erste gefundene Element als Kontext für die nächste Action setzen
            pageProxy.setActionBinding(data.getItem(0));
            // Navigations-Action zur Detailseite ausführen
            return clientAPI.executeAction("/demosampleapp/Actions/Navigation_Product_Result.action");
        } else {
            // Kein Produkt gefunden, Benutzer informieren
            return clientAPI.executeAction({
                "Name": "/demosampleapp/Actions/GenericToastMessage.action",
                "Properties": {
                    "Message": `Kein Produkt für die ID '${productId}' gefunden.`,
                    "Duration": 5
                }
            });
        }
    }).catch(error => {
        console.error("Fehler beim Lesen der Produktdaten: ", error);
        // Fehlerbehandlung für den Fall, dass der Backend-Call fehlschlägt
        return clientAPI.executeAction({
            "Name": "/demosampleapp/Actions/GenericToastMessage.action",
            "Properties": {
                "Message": "Fehler beim Abrufen der Produktdaten.",
                "Duration": 5
            }
        });
    });
}

Die Implementierung im Detail: Seiten und Controls

Seite 1: Die Suchmaske (ProductSearch.page)

Der Aufbau dieser Seite ist minimal und fokussiert sich auf die Eingabe:

  • FormCell.SimpleProperty: Ein Eingabefeld zur Aufnahme der Produkt-ID.
    • Wichtig: Vergeben Sie unter der Eigenschaft _Name eine eindeutige ID, zum Beispiel ProductIdInput. Nur so können Sie mit clientAPI.evaluateTargetPath('#Control:ProductIdInput/#Value') sicher darauf zugreifen.
  • Button: Ein einfacher Button, der die Suche auslöst.
    • OnPress-Ereignis: Binden Sie hier als auszuführende Aktion Ihre MDK-Rule (/demosampleapp/Rules/Search_Product_Rule.js).

Seite 2: Die Detailanzeige (ProductDetail.page)

Diese Seite dient der reinen Darstellung der Produktdetails. Sie benötigt kein explizites Target auf das EntitySet in ihren Metadaten, da der Kontext dynamisch durch die setActionBinding()-Methode aus der Rule gesetzt wird.

  • Verwenden Sie UI-Controls wie ObjectHeader, FormCell.Title, FormCell.SimpleProperty, etc., um die Daten ansprechend darzustellen.

  • Binden Sie die Value-Eigenschaft (oder eine entsprechende Eigenschaft des Controls) direkt an die Properties des Produkts. Das Binding erfolgt automatisch auf den Kontext, den setActionBinding bereitgestellt hat.

    • Beispiel für den Produktnamen: {Name}
    • Beispiel für den Preis: {Price}
    • Beispiel für die Beschreibung: {ShortDescription}

Dank setActionBinding steht der Datenkontext des einzelnen, gelesenen Produkts auf der Zielseite zur Verfügung – genau so, als hätten Sie den Eintrag aus einer Liste ausgewählt.

Wichtiger Hinweis: Falls die Navigation Action zur ProductDetail.page eine Validation Rule enthält, kann dadurch das ActionBinding gestört werden und es werden keine Daten angezeigt. Am besten validierst du die Eingaben ausschließlich in der Search_Product_Rule.js

Fazit: Volle Kontrolle und bessere Performance

Die Kombination aus clientAPI.read und pageProxy.setActionBinding() ist ein extrem mächtiges Werkzeug im SAP MDK. Sie ermöglicht es Ihnen, von Standard-Listenmustern abzuweichen und hochspezifische, performante und benutzerfreundliche Abläufe zu erstellen.

Ihre Vorteile:

  • Gezielte Datenabrufe: Sie laden nur die Daten, die wirklich benötigt werden, was die Netzwerklast und die Verarbeitungszeit reduziert.
  • Schlanke UI: Vermeiden Sie unnötige Zwischenschritte über Listenansichten und bieten Sie einen direkteren Weg zum Ziel.
  • Hohe Flexibilität: Sie haben die volle programmatische Kontrolle über die Daten, die Sie lesen und an die nächste Seite übergeben.

Dieser Ansatz ist ideal für Suchfunktionen, Barcode-Scanning-Integrationen oder jeden Prozess, bei dem eine Entität über ihre eindeutige ID direkt angesprungen werden soll.

FAQ: Häufige Fragen

F: Was genau macht setActionBinding()? A: setActionBinding(object) setzt den Binding-Kontext für die unmittelbar danach ausgeführte Action. Wenn diese Action eine Navigation zu einer neuen Seite ist, wird das übergebene object (in unserem Fall der gefundene Produktdatensatz) zum Binding-Kontext dieser neuen Seite. Dies erspart die manuelle Übergabe von Parametern über die Action-Properties.

F: Kann ich mit clientAPI.read auch mehrere Filterkriterien übergeben? A: Ja, Sie können die OData-Filter-Query beliebig komplex gestalten. Verbinden Sie mehrere Kriterien einfach mit and oder or. Beispiel: $filter=SupplierName eq 'SAP' and Category eq 'Software'.

F: Ist dieser Ansatz auch für Offline-Anwendungen geeignet? A: Ja, absolut. clientAPI.read funktioniert nahtlos mit dem Offline-OData-Store. Die Methode liest die Daten automatisch aus der lokalen SQLite-Datenbank, sofern die Anwendung offline ist und die entsprechenden Entitäten zuvor erfolgreich synchronisiert wurden.

F: Was passiert, wenn der Filter mehr als einen Datensatz zurückgibt? A: Der Code data.getItem(0) sorgt dafür, dass immer nur der erste Datensatz aus dem Ergebnisarray verwendet wird. In einem Szenario, in dem ein Filter potenziell mehrere Ergebnisse liefern kann (z.B. bei einer Suche nach Namen), sollten Sie die Logik anpassen – entweder um dem Benutzer eine Auswahl zu präsentieren oder um sicherzustellen, dass die Filterlogik immer eindeutig ist.

© Felix Stiffel 2025 | Alle Rechte vorbehalten