**TITLE**: Replace Standard Chevron Navigation in List Report Table (OData V2 & V4)

**INTRODUCTION**: Step-by-step instructions to override the default chevron/navigation behavior in a Fiori elements List Report responsive table. Shows how to add outbound navigation targets in manifest.json, register controller extensions, and implement extension hooks to route navigation to external or internal targets (examples for OData V2 and OData V4).

**TAGS**: fiori-elements-framework, sapui5, odata-v2, odata-v4, list-report, navigation, extension, manifest.json, controller-extension, extensionAPI

**STEP**: Caution and prerequisites

**DESCRIPTION**: Use app extensions only when manifest settings or annotations cannot provide the needed behavior. Integrate with SAP Fiori elements using only extensionAPI functions. After creating an app extension the application is responsible for display and system behavior. Do not access internal framework controls, properties, or models directly.

**LANGUAGE**: Text

**CODE**:
```Text
Caution:
Use app extensions with caution and only if you cannot produce the required behavior by other means, such as manifest settings or annotations. To correctly integrate your app extension coding with SAP Fiori elements, use only the `extensionAPI` of SAP Fiori elements. For more information, see Using the extensionAPI.
After you've created an app extension, its display (for example, control placement and layout) and system behavior (for example, model and binding usage, busy handling) lies within the application's responsibility. SAP Fiori elements provides support only for the official `extensionAPI` functions. Don't access or manipulate controls, properties, models, or other internal objects created by the SAP Fiori elements framework.
```

**STEP**: OData V2 — Add outbound navigation target to manifest.json

**DESCRIPTION**: Add an outbound entry under sap.app -> crossNavigation -> outbounds in your application's manifest.json to define an external target (launchpad outbound). Place this JSON fragment into manifest.json where your sap.app configuration is defined.

**LANGUAGE**: JSON

**CODE**:
```JSON
sap.app": {

...
  "crossNavigation": {
     "inbounds": {},
     "outbounds": {
       "EPMProductManageSt": {
         "semanticObject": "EPMProduct",
         "action": "manage",
         "parameters": {
            "preferredMode": {
               "value": {
                  "value": "display"
               }
            }
         }
      }
   }
 }

....

```

**STEP**: OData V2 — Register the controller extension in manifest.json

**DESCRIPTION**: Register your List Report controller extension under sap.ui5 -> extends -> extensions -> sap.ui.controllerExtensions. Map the ListReport controller to your custom controller name. Add this to your manifest.json.

**LANGUAGE**: JSON

**CODE**:
```JSON
"extends": {
   "extensions": {
      ...
      "sap.ui.controllerExtensions": {
         ...
         "sap.suite.ui.generic.template.ListReport.view.ListReport": {
            ...
            "controllerName": "STTA_MP.ext.controller.ListReportExtension",
            ...
         }
      }
      ...
```

**STEP**: OData V2 — Implement onListNavigationExtension in your list report controller extension

**DESCRIPTION**: Implement the onListNavigationExtension handler in your registered controller. Use this.extensionAPI.getNavigationController() to obtain navigation functions. Return true to prevent default internal navigation when you perform external navigation; return false to allow default internal navigation.

- Behavior in example: If ProductCategory == "Notebooks" navigate externally to outbound "EPMProductManageSt"; otherwise allow default internal navigation.

**LANGUAGE**: JavaScript

**CODE**:
```JavaScript
onListNavigationExtension: function(oEvent) {
 var oNavigationController = this.extensionAPI.getNavigationController();
 var oBindingContext = oEvent.getSource().getBindingContext();
 var oObject = oBindingContext.getObject();
 // for notebooks we trigger external navigation for all others we use internal navigation
 if (oObject.ProductCategory == "Notebooks") {
    oNavigationController.navigateExternal("EPMProductManageSt");
 } else {
    // return false to trigger the default internal navigation
    return false;
 }
 // return true is necessary to prevent further default navigation
 return true;
 },
```

**STEP**: OData V2 — Ensure an object page exists (or disable navigation if not desired)

**DESCRIPTION**: For navigation to be available to users, an object page target must be defined. If you don’t want the user to navigate to the object page, follow the Enable External Navigation procedure in the “Changing Navigation to Object Page” documentation to prevent default navigation to the object page.

**LANGUAGE**: Text

**CODE**:
```Text
To ensure that this navigation can be triggered by the user, you must have defined an object page. If you do not want the user to be able to navigate to this object page, follow the procedure described in the Enable External Navigation section in the Changing Navigation to Object Page topic.
```

**STEP**: OData V4 — Add outbound navigation target to manifest.json

**DESCRIPTION**: Define an outbound navigation under sap.app -> crossNavigation -> outbounds to point to the target application. Add the JSON snippet into manifest.json.

**LANGUAGE**: JSON

**CODE**:
```JSON
sap.app": {
    ...
    "crossNavigation": {
        "inbounds": {},
        "outbounds": {
            "FreestyleNav1": {
                "semanticObject": "v4Freestyle",
                "action": "Inbound",
                "parameters": {
                    "SoldToParty": {
                        "value": {
                            "value": "7P100001",
                            "format": "plain"
                        }
                    }
                }
            }
        }
    }
}
```

**STEP**: OData V4 — Configure controller extensions in manifest.json

**DESCRIPTION**: Register controller extensions for the List Report and Object Page controllers under sap.ui5 -> extends -> extensions -> sap.ui.controllerExtensions. Point to your custom controllers (e.g., SalesOrder.ext.LRExtend and SalesOrder.ext.OPExtend).

**LANGUAGE**: JSON

**CODE**:
```JSON
"sap.ui5": {
    "extends": {
        "extensions": {
            "sap.ui.controllerExtensions": {
                "sap.fe.templates.ListReport.ListReportController": {
                    "controllerName": "SalesOrder.ext.LRExtend"
                },
                "sap.fe.templates.ObjectPage.ObjectPageController": {
                    "controllerName": "SalesOrder.ext.OPExtend"
                }
            }
        }
    }
}
```

**STEP**: OData V4 — Implement onBeforeNavigation in the controller extension

**DESCRIPTION**: Implement the override routing.onBeforeNavigation extension method in your List Report controller extension. Use this.base.getExtensionAPI().intentBasedNavigation to navigate outbound. Return true to stop default internal navigation when you perform external navigation; return false to allow default behavior.

- Example: For SalesOrder "6437" navigate outbound to "FreestyleNav" with parameter Customer = "10001". oContextInfo contains lineItem binding context for list report navigation.

**LANGUAGE**: JavaScript

**CODE**:
```JavaScript
override: {
    routing: {
        onBeforeNavigation: function(oContextInfo) {
            var oLineContext = oContextInfo.bindingContext,
            oNav = this.base.getExtensionAPI().intentBasedNavigation;
            // for salesOrder 6437 navigate to FreeStyle App
            if (oLineContext.SalesOrder === "6437") {
                oNav.navigateOutbound("FreestyleNav", { "Customer": "10001" });
            } else {
                // return false to trigger the default internal navigation
                return false;
            }
            // return true is necessary to prevent further default navigation
            return true;
        }
    }
}
```


**TITLE**: Replace Standard Chevron Navigation in Object Page Responsive Table (OData V2 & V4)

**INTRODUCTION**: This guide shows how to replace the default chevron navigation from a responsive table on the Object Page with a custom external or internal target. It covers required manifest.json changes and controller extension implementations for both OData V2 and OData V4 SAP Fiori elements apps. Use only the SAP Fiori elements extensionAPI when integrating custom code.

**TAGS**: fiori-elements, extensionAPI, manifest.json, navigation, object-page, responsive-table, OData V2, OData V4, controller-extension, intent-based-navigation, paginator

STEP: Caution / Integration Context
DESCRIPTION: Important integration notes. Use app extensions only if equivalent behavior cannot be achieved by annotations or manifest settings. Integrate only via the official extensionAPI. After adding an extension, the app is responsible for display and system behavior (model/bindings/busy handling). Do not access or manipulate SAP Fiori elements internal controls, properties, models, or other internal objects.
LANGUAGE: text
CODE:
```text
Caution:
Use app extensions with caution and only if you cannot produce the required behavior by other means, such as manifest settings or annotations. To correctly integrate your app extension coding with SAP Fiori elements, use only the `extensionAPI` of SAP Fiori elements. For more information, see Using the extensionAPI.

After you've created an app extension, its display (for example, control placement and layout) and system behavior (for example, model and binding usage, busy handling) lies within the application's responsibility. SAP Fiori elements provides support only for the official `extensionAPI` functions. Don't access or manipulate controls, properties, models, or other internal objects created by the SAP Fiori elements framework.
```

STEP: OData V2 — Add navigation target (outbound) to manifest.json
DESCRIPTION: Add an outbound navigation target (intent) to sap.app > crossNavigation > outbounds in manifest.json to enable external navigation via the FLP outbound/inbound configuration.
LANGUAGE: JSON
CODE:
```json
manifest.json

sap.app": {
...
  "crossNavigation": {
     "inbounds": {},
     "outbounds": {
       "EPMProductManageSt": {
         "semanticObject": "EPMProduct",
         "action": "manage",
         "parameters": {
            "preferredMode": {
               "value": {
                  "value": "display"
               }
            }
         }
      }
   }
 }
....
```

STEP: OData V2 — Register controller extension in manifest.json
DESCRIPTION: Register your object page controller extension in sap.ui5 > extends > extensions > sap.ui.controllerExtensions so SAP Fiori elements uses your custom controller for the ObjectPage view.
LANGUAGE: JSON
CODE:
```json
manifest.json

"extends": {
   "extensions": {
      ...
      "sap.ui.controllerExtensions": {
         ...
         "sap.suite.ui.generic.template.ObjectPage.view.Details": {
            ...
            "controllerName": "STTA_MP.ext.controller.DetailsExtension",
            ...
         }
      }
      ...
```

STEP: OData V2 — Implement onListNavigationExtension in controller extension
DESCRIPTION: Implement onListNavigationExtension in your Object Page controller extension. Use the extensionAPI to get the navigation controller and call navigateExternal for external navigation; return false to allow default internal navigation; return true to suppress default navigation.
LANGUAGE: JavaScript
CODE:
```javascript
onListNavigationExtension: function(oEvent) {
 var oNavigationController = this.extensionAPI.getNavigationController();
 var oBindingContext = oEvent.getSource().getBindingContext();
 var oObject = oBindingContext.getObject();
 // for notebooks we trigger external navigation for all others we use internal navigation
 if (oObject.ProductCategory == "Notebooks") {
    oNavigationController.navigateExternal("EPMProductManageSt");
 } else {
    // return false to trigger the default internal navigation
    return false;
 }
 // return true is necessary to prevent further default navigation
 return true;
 },
```

STEP: OData V4 — Add outbound navigation configuration to manifest.json
DESCRIPTION: Add outbound navigation (intent) to sap.app > crossNavigation > outbounds in manifest.json for OData V4 apps. Specify semanticObject, action and optional parameters or formats required by the target app.
LANGUAGE: JSON
CODE:
```json
manifest.json

sap.app": {
    ...
    "crossNavigation": {
        "inbounds": {},
        "outbounds": {
            "FreestyleNav1": {
                "semanticObject": "v4Freestyle",
                "action": "Inbound",
                "parameters": {
                    "SoldToParty": {
                        "value": {
                            "value": "7P100001",
                            "format": "plain"
                        }
                    }
                }
            }
        }
    }
}
```

STEP: OData V4 — Configure controller extensions in manifest.json
DESCRIPTION: Register list-report and object-page controller extensions under sap.ui5 > extends > extensions > sap.ui.controllerExtensions so your custom controllers receive navigation lifecycle hooks like onBeforeNavigation.
LANGUAGE: JSON
CODE:
```json
manifest.json

"sap.ui5": {
    "extends": {
        "extensions": {
            "sap.ui.controllerExtensions": {
                "sap.fe.templates.ListReport.ListReportController": {
                    "controllerName": "SalesOrder.ext.LRExtend"
                },
                "sap.fe.templates.ObjectPage.ObjectPageController": {
                    "controllerName": "SalesOrder.ext.OPExtend"
                }
            }
        }
    }
}
```

STEP: OData V4 — Implement onBeforeNavigation in controller extension
DESCRIPTION: Implement the onBeforeNavigation routing override to inspect the clicked line item (oContextInfo.bindingContext), decide whether to navigate outbound, and call the intent-based navigation API via this.base.getExtensionAPI().intentBasedNavigation. Return false to use default internal navigation; return true to suppress default navigation.
LANGUAGE: JavaScript
CODE:
```javascript
override: {
    routing: {
        onBeforeNavigation: function(oContextInfo) {
            var oLineContext = oContextInfo.bindingContext.getObject( ),
            oNav = this.base.getExtensionAPI().intentBasedNavigation;
            // for salesOrder 6437 navigate to FreeStyle App
            if (oLineContext.SalesOrder === "6437") {
                oNav.navigateOutbound("FreestyleNav", { "Customer": "10001" });
            } else {
                // return false to trigger the default internal navigation
                return false;
            }
            // return true is necessary to prevent further default navigation
            return true;
        }
    }
}
```

STEP: Paginator behavior — implement determineContextNavigationType()
DESCRIPTION: If you replace standard navigation with external navigation or suppress navigation, implement determineContextNavigationType() per the Paginator API so the framework can skip contexts with ContextNavigationType.None or ContextNavigationType.External when using paginator buttons in the detailed view. See API reference for details.
LANGUAGE: text
CODE:
```text
Note:
When replacing the standard navigation for any record by configuring it to navigate to an external application or suppressing the navigation option, you must implement the determineContextNavigationType() method. This ensures that SAP Fiori elements for OData V4 recognizes this special navigation flow configured for such contexts and enables the correct behavior while using paginator buttons in the detailed view. Contexts that return ContextNavigationType.None or ContextNavigationType.External are skipped when using paginators.

For information about the determineContextNavigationType method, see the API Reference:
https://ui5.sap.com/#/api/sap.fe.core.controllerextensions.Paginator%23methods/determineContextNavigationType
```

fiori-elements
extensionAPI
manifest.json
navigation
object-page
responsive-table
OData V2
OData V4
controller-extension
intent-based-navigation
paginator


**TITLE**: Extending SAP Fiori Elements Apps with a Canvas Page (OData V2)

**INTRODUCTION**: How to embed a custom Canvas page into a SAP Fiori elements (OData V2) app via manifest configuration, wire required controls, enable routing, and implement navigation and data handling in controller and component lifecycle methods. Includes sample manifest snippets and JavaScript examples for extensionAPI usage and implementing component lifecycle hooks.

**TAGS**: fiori-elements-framework, SAPUI5, manifest.json, canvas, routing, extensionAPI, OData V2, navigation, component, controller

**STEP**: 1 - Declare a Canvas Page in manifest (basic structure)

**DESCRIPTION**: Add a canvas page entry under "sap.ui.generic.app.pages" in the app manifest. Use "sap.suite.ui.generic.template.Canvas" as the embedding component and set "implementingComponent.componentName" to your implementing component qualified name. This snippet shows the minimal structure; preserve surrounding manifest context as needed.

**LANGUAGE**: JSON

**CODE**:
```json
...
 "sap.ui.generic.app": {
    ...
        "pages": {
            "thePageName": {
                "component": {
                    "name": "sap.suite.ui.generic.template.Canvas",
                    "settings": {
                    }
                },
                "implementingComponent": {
                    "componentName": "theImplementingComponentQualifiedName",
                        "settings": {
                        ...
                    }
                }
            }
        },
        ...
}
...
```

**STEP**: 2 - Use componentUsage instead of componentName (alternate manifest pattern)

**DESCRIPTION**: If you define a component usage in the manifest, reference it from "implementingComponent" using "componentUsage" instead of "componentName" to create the implementing component via a manifest component usage entry.

**LANGUAGE**: JSON

**CODE**:
```json
...
 "sap.ui.generic.app": {
    ...
        "pages": {
            "thePageName": {
                "component": {
                    "name": "sap.suite.ui.generic.template.Canvas",
                    "settings": {
                    }
                },
                "implementingComponent": {
                    "componentUsage": "theComponentUsageKey",
                        "settings": {
                        ...
                    }
                }
            }
        },
        ...
}
...
```

**STEP**: 3 - Request standard controls from Canvas (footerBar or flexibleColumnLayoutActions)

**DESCRIPTION**: Configure the Canvas component's "requiredControls" in the "component.settings" section to request standard controls. Use "footerBar": true to allow the implementing component to add the standard footer bar via extension API; or use "flexibleColumnLayoutActions" for flexible column action buttons. You may combine both flags.

**LANGUAGE**: JSON

**CODE**:
```json
...
"sap.ui.generic.app": {
    ...
        "pages": {
            "thePageName": {
                "component": {
                    "name": "sap.suite.ui.generic.template.Canvas",
                    "settings": {
                        "requiredControls": {
                            "footerBar": true
                        }
                    }
                },
                "implementingComponent": {
                    "componentName": "theImplementingComponentQualifiedName",
                            "settings": {
                        ...
                    }
                }
            }
        },
        ...
}
...
```

**STEP**: 4 - Add routingSpec to enable navigation to the Canvas page

**DESCRIPTION**: Add a "routingSpec" object to the canvas page manifest entry to enable navigation via extensionAPI. Set "noOData", and choose "noKey" depending on whether the routing should carry a key. "routeName" is used to build a unique route name within the app. Do not reuse routeName within the app or match entity set/navigation property names unless intentionally overriding (see below).

**LANGUAGE**: JSON

**CODE**:
```json
...
"sap.ui.generic.app": {
    ...
        "pages": {
            "thePageName": {
                "component": {
                    "name": "sap.suite.ui.generic.template.Canvas",
                    "settings": {
                        "requiredControls": {
                            "footerBar": true
                        }
                    }
                },
                "implementingComponent": {
                    "componentName": "theImplementingComponentQualifiedName",
                            "settings": {
                        ...
                    }
                },
                "routingSpec": {
                    "noOData": true,
                    "noKey": true,
                    "routeName": "theRouteName"
                }
            }
        },
        ...
}
...
```

**STEP**: 5 - Example parent-child manifest structure (context passed from parent)

**DESCRIPTION**: When the Canvas page is a child of a parent object page, declare it under the parent's "pages" block. The parent page's context (for example entitySet binding) is passed to the Canvas page and also to the implementing component lifecycle methods. Only the parent's extension API instance can be used to navigate to this child canvas page.

**LANGUAGE**: JSON

**CODE**:
```json
...
"sap.ui.generic.app": {
...
    "pages": {
        "theParentPageName": {
            "entitySet": "theMainEntitySet",
            "component": {
                "name": "sap.suite.ui.generic.template.ObjectPage",
                "settings": {
                    ...
                }
            }
            "pages": {
                "thePageName": {
                    "component": {
                        "name": "sap.suite.ui.generic.template.Canvas",
                        "settings": {
                            ...
                        }
                    },
                    "implementingComponent": {
                        "componentName": "theImplementingComponentQualifiedName",
                                "settings": {
                            ...
                        }
                    },
                    "routingSpec": {
                        "noOData": true,
                        "noKey": true,
                        "routeName": "theRouteName"
                    }
                },
                ...
            }

        },
        ...
    }
...
}
```

**STEP**: 6 - Trigger navigation to a Canvas page from parent extension API (noKey = true)

**DESCRIPTION**: Use the parent page's extensionAPI in an event handler to navigate to the canvas page. This example calls navigateInternal with an empty key because routingSpec.noKey is true. Ensure the extensionAPI instance belongs to the parent page of the target canvas page.

**LANGUAGE**: JavaScript

**CODE**:
```javascript
...
var oApi = this.extensionAPI;
var oNavigationController = oApi.getNavigationController();
oNavigationController.navigateInternal("", {     routeName: "theRouteName"   });

...
```

**STEP**: 7 - Navigate with a user choice (pass single string key) when noKey = false

**DESCRIPTION**: When routingSpec.noKey is false, pass a single string (the user's choice or key) to the canvas page via navigateInternal. Only one string can be passed; complex data must be encoded. Use this code in an event handler (e.g., button press or list navigation extension) on the source page.

**LANGUAGE**: JavaScript

**CODE**:
```javascript
...
var oApi = this.extensionAPI;
var oNavigationController = oApi.getNavigationController();
var sUsersChoice = ... // do whatever is necessary to determine the users choice
oNavigationController.navigateInternal(sUsersChoice, {     routeName: "theRouteName"   });

...
```

**STEP**: 8 - Evaluate the passed user choice in the implementing component (stRefresh)

**DESCRIPTION**: In the implementing component's stRefresh lifecycle method, get current navigation keys via the provided oExtensionAPI, extract the last key as the user's choice, and set it on the component model for binding.

**LANGUAGE**: JavaScript

**CODE**:
```javascript
...

  stRefresh: function(oModel, oBindingContext, oExtensionAPI) {
    var oNavigationController = oExtensionAPI.getNavigationController();
    var aKeys = oNavigationController.getCurrentKeys();
    var sUserChoice = aKeys[aKeys.length - 1];
    var oComponentModel = this.getComponentModel();
    oComponentModel.setProperty("/UsersChoice", sUserChoice);
  }

...
```

**STEP**: 9 - Bind a navigation context from a list report to the Canvas view (stStart example)

**DESCRIPTION**: In the implementing component's stStart lifecycle method, get the navigation key from the extensionAPI, build a binding path, and bind the canvas view to that path so smart controls use the provided context. Example is from component.js.

**LANGUAGE**: JavaScript

**CODE**:
```javascript
stStart: function(oModel, oBindingContext, oExtensionAPI) {
            var oComponentModel = this.getComponentModel();
            var sPath = oExtensionAPI.getNavigationController().getCurrentKeys()[1];
            var sBindingPath = "/C_STTA_SalesOrder_WD_20(" + sPath + ")";
            var oPathSpec = {
                path: sBindingPath
            };
            var oCanvasView = oComponentModel.getProperty("/View");
            oCanvasView.bindElement(oPathSpec);
        },
```

**STEP**: 10 - Navigate to a non-child canvas page or ancestor child (use isAbsolute = true)

**DESCRIPTION**: To navigate to a canvas page that is not a child of the current canvas page (including a child of any hierarchical ancestor), pass isAbsolute: true in navigateInternal options. The manifest routingSpec for the target page remains the same (example below shows routingSpec.noKey = false).

**LANGUAGE**: JSON

**CODE**:
```json
...
"sap.ui.generic.app": {
...
    "pages": {
        "theParentPageName": {
            "entitySet": "theMainEntitySet",
            "component": {
                "name": "sap.suite.ui.generic.template.ObjectPage",
                "settings": {
                    ...
                }
            }
            "pages": {
                "thePageName": {
                    "component": {
                        "name": "sap.suite.ui.generic.template.Canvas",
                        "settings": {
                            ...
                        }
                    },
                    "implementingComponent": {
                        "componentName": "theImplementingComponentQualifiedName",
                                "settings": {
                            ...
                        }
                    },
                    "routingSpec": {
                        "noOData": true,
                        "noKey": false,
                        "routeName": "theRouteName"
                    }
                },
                ...
            }

...
}
```

**LANGUAGE**: JavaScript

**CODE**:
```javascript
...
var oApi = this.extensionAPI;
var oNavigationController = oApi.getNavigationController();
var sUsersChoice = ... //do whatever is necessary to determine the user's choice
oNavigationController.navigateInternal(sUsersChoice, {
	routeName: "theRouteName",
	isAbsolute: true
});
...
```

**STEP**: 11 - Implementation notes and constraints (actionable reminders)

**DESCRIPTION**: - This topic applies only to SAP Fiori elements for OData V2.
- routeName must be unique within the app and should not clash with entity set or navigation property names unless intentionally overriding behavior (see use-case in docs).
- The implementing component can use the Canvas extension API to add standard controls when requested via requiredControls.
- If you need to provide complex information to the canvas page, encode it into a single string before navigation.

**LANGUAGE**: N/A

**CODE**:
```text
Related Information:
Developing Reuse Components: developing-reuse-components-6314fcd.md
Including Reuse Components on an Object Page: including-reuse-components-on-an-object-page-d869d7a.md
UI5 Extension API docs: https://ui5.sap.com/#/api/sap.suite.ui.generic.template.Canvas.extensionAPI.ExtensionAPI
```

fiori-elements-framework
SAPUI5
manifest.json
canvas
routing
extensionAPI
OData V2
navigation
component
controller


**TITLE**: Extending Custom View Switch

**INTRODUCTION**: Implement a controller extension that dynamically switches card tab views based on filter conditions or custom configuration. Use the onBeforeRebindPageExtension hook to compute a mapping of card IDs to tab indices and call this.setTabIndex(oTabIndexList).

**TAGS**: fiori-elements-framework, UI5, OVP, controller-extension, manifest, view-switch, card

**STEP**: 1 — Create controller extension and implement onBeforeRebindPageExtension

**DESCRIPTION**:
- Create a controller extension file (for example, customViewswitch.controller.js).
- Implement onBeforeRebindPageExtension(aCards, oSelectionVariant) to inspect visible cards and the current filter/selection variant, build an object mapping CardId -> TabIndex, and call this.setTabIndex(oTabIndexList).
- Input parameters:
  - aCards: Array of visible card objects (each has an id property).
  - oSelectionVariant: Object containing filter values (has Parameters and SelectOptions arrays).
- TabIndex rules: values start at 1 and must not exceed the number of tabs for the card.
- Example mapping: var oTabIndexList = {"card1": 2, "card2": 1};

**LANGUAGE**: JavaScript

**CODE**:
```javascript
/*
* Breakout function for dynamic view switch
* */
onBeforeRebindPageExtension: function (aCards, oSelectionVariant) {
    var oTabIndexList = {};
    var oFilterList = this._getFilterList(oSelectionVariant); //Sample logic
    var oTabIndexList = {};
    if (aCards && aCards.length > 0) {
        for (var i = 0; i < aCards.length; i++) {
            if (aCards[i].id == "card012") {
                if (oFilterList && oFilterList.hasOwnProperty("SupplierName")) {
                    if (oFilterList.SupplierName == "SAP") {
                        oTabIndexList["card012"] = 1;
                    } else if (oFilterList.SupplierName == "Talpa") {
                        oTabIndexList["card012"] = 2;
                    }
                }
            }
        }
    }//End of sample logic

    this.setTabIndex(oTabIndexList); //Pass updated oTabIndexList object here
}
```

**STEP**: 2 — Implement supporting helper to extract filters from oSelectionVariant

**DESCRIPTION**: Implement a helper method _getFilterList(oSelectionVariant) to return a flat object of filter property names to values by reading both Parameters and SelectOptions (ranges with Option == "EQ").

**LANGUAGE**: JavaScript

**CODE**:
```javascript
//get all filters with values
_getFilterList: function (oSelectionVariant) {
    var oFilterList = {};
    if (oSelectionVariant && oSelectionVariant.Parameters && oSelectionVariant.Parameters.length > 0) {
        for (var i = 0; i < oSelectionVariant.Parameters.length; i++) {
            oFilterList[oSelectionVariant.Parameters[i].PropertyName] = oSelectionVariant.Parameters[i].PropertyValue;
        }
    }
    if (oSelectionVariant && oSelectionVariant.SelectOptions && oSelectionVariant.SelectOptions.length > 0) {
        for (var j = 0; j < oSelectionVariant.SelectOptions.length; j++) {
            var aRanges = oSelectionVariant.SelectOptions[j].Ranges;
            for (var k = 0; k < aRanges.length; k++) {
                if (aRanges[k].Option == "EQ" && aRanges[k].Low !== "") {
                    oFilterList[oSelectionVariant.SelectOptions[j].PropertyName] = aRanges[k].Low;
                }
            }
        }
    }
    return oFilterList;
},
```

**STEP**: 3 — Register controller extension in manifest.json

**DESCRIPTION**: Add a controller extension entry under "extends" -> "extensions" -> "sap.ui.controllerExtensions". Set controllerName to the module path of your controller (e.g., sap.ovp.demo.ext.customController). Ensure the module exists at the corresponding file path.

**LANGUAGE**: JSON

**CODE**:
```json
"extends": {
    "extensions": {
        "sap.ui.controllerExtensions": {
            "sap.ovp.app.Main": {
                "controllerName": "sap.ovp.demo.ext.customController"
            }
        }
    }
}
```

Extending Custom View Switch

fiori-elements-framework UI5 OVP controller-extension manifest view-switch card


**TITLE**: Extending Delivered SAP Fiori Elements Apps Using Adaptation Extensions

**INTRODUCTION**: Use the Adaptation Editor in SAP Business Application Studio (BAS) to create UI adaptation projects that extend delivered SAP Fiori elements applications. This guide summarizes supported page types, available adaptation extension points, overrideable extension functions, and shows a sample override code snippet for List Report addFilters. Use these steps to implement ControllerExtension overrides (templateBased/templateBaseExtension points) as part of an adaptation project.

**TAGS**: fiori-elements-framework, adaptation, adaptation-editor, business-application-studio, controllerextension, OData V2, OData V4, list-report, object-page, overview-page

STEP: 1 — Prerequisites and scope

DESCRIPTION: Create an adaptation project in SAP Business Application Studio using the Adaptation Editor. Supported page types and limitations:
- Supported: List Report, Object Page, Overview Page, Analytical List Page.
- Not supported: Flexible Column Layout.
- The adaptation project references delivered/base (parent) applications.
- For an end-to-end example of creating an adaptation project, see: https://help.sap.com/docs/bas/developing-sap-fiori-app-in-sap-business-application-studio/extending-sap-fiori-application

LANGUAGE: Text

CODE:
```Text
Create an adaptation project in SAP Business Application Studio using the Adaptation Editor and select the delivered app as the parent application.
```

STEP: 2 — Adaptation extension use cases (OData V2)

DESCRIPTION: For OData V2 based Fiori elements apps, adaptation extensions can be used to:
- List Report & Analytical List Page:
  - Add fields to Smart Filter Bar
  - Add columns to tables
  - Add table toolbar buttons and controller logic
  - Override extension functions (see list below)
  - Visual reference: images/List_Report_Adaptation_extensions_d09b292.png
- Object Page:
  - Add toolbar actions, sections, header fields, form fields/field groups
  - Override extension functions (see list below)
  - Visual reference: images/Object_Page_Adaptation_Extensions_07345eb.png
- Overview Page:
  - Add fields to Smart Filter Bar, global actions, controller logic, cards (clone/edit/add)
  - Override extension functions (see list below)

LANGUAGE: Text

CODE:
```Text
Adaptation extensions apply to List Report, Object Page, Overview Page, and Analytical List Page for OData V2 apps.
```

STEP: 3 — List Report: overrideable extension functions and sample override

DESCRIPTION: Override the List Report extension functions as part of a ControllerExtension by implementing the templateBased/templateBaseExtension override points. Common overrideable functions for List Report and Analytical List Page:
- onInitSmartFilterBar
- provideExtensionAppStateData
- restoreExtensionAppStateData
- ensureFieldsForSelect
- addFilters

Example: Overriding addFilters (sample code preserved):

LANGUAGE: JavaScript

CODE:
```JavaScript
override: {
    // override public method of the ListReport controller
    templateBaseExtension: {
        addFilters: function(fnAddFilter, sControlId){
            // custom logic
        }
    }
}
```

STEP: 4 — Object Page: overrideable extension functions and use cases

DESCRIPTION: For Object Page adaptation projects, you can:
- Add toolbar actions, additional sections, header fields, form fields/field groups.
- Override these functions as part of ControllerExtension/templateBasedExtension:
  - provideExtensionStateData
  - restoreExtensionStateData
  - ensureFieldsForSelect
  - addFilters

LANGUAGE: Text

CODE:
```Text
Implement ControllerExtension overrides (templateBasedExtension) to provide/restore extension state data, ensure select fields, and add filters on Object Page.
```

STEP: 5 — Overview Page: overrideable extension functions and use cases

DESCRIPTION: For Overview Page adaptation projects, you can:
- Add fields to Smart Filter Bar, add global actions to filter bar, add extension controller logic.
- Add, clone, and edit cards.
- Override these functions as part of ControllerExtension/templateBasedExtension:
  - provideExtensionAppStateData
  - restoreExtensionAppStateData
  - addFilters
  - provideStartupExtension
  - provideExtensionNavigation
  - provideCustomActionPress
  - provideCustomParameter

LANGUAGE: Text

CODE:
```Text
Use ControllerExtension overrides to extend Overview Page behaviors, card handling, and custom parameters/actions.
```

STEP: 6 — OData V4: controllerextensions API and Safe Mode

DESCRIPTION: For OData V4 Fiori elements apps, use the controllerextensions API to override framework behavior and implement hooks for custom logic. References and tools:
- API Reference: https://ui5.sap.com/#/api/sap.fe.core.controllerextensions
- Live examples and guidance: Standard Floorplans - Extensions - Overview: https://ui5.sap.com/test-resources/sap/fe/core/fpmExplorer/index.html#/controllerExtensions/guidanceControllerExtensions
- Adapt UI in Safe Mode documentation: SAPUI5 Flexibility: Adapting UIs Made Easy (link in references)

LANGUAGE: Text

CODE:
```Text
Use sap.fe.core.controllerextensions to register and implement ControllerExtension overrides for OData V4 Fiori elements apps.
```

STEP: 7 — Notes, limitations, and API reference caveat

DESCRIPTION: Important notes:
- The extension points listed in the UI5 API Reference (for example sap.suite.ui.generic.template.ListReport.controllerFrameworkExtensions) cannot be consumed directly as part of an adaptation project.
- Use the templateBased/templateBaseExtension override points exposed by the adaptation framework instead.
- Check "Details of Extension Functions Used for Extending Delivered Apps" for deeper reference (details-of-extension-functions-used-for-extending-delivered-apps-82630e5.md).

LANGUAGE: Text

CODE:
```Text
Do not use UI5 controllerFrameworkExtensions API endpoints directly in adaptation projects; implement overrides via templateBased/templateBaseExtension points instead.
```

STEP: 8 — Related resources

DESCRIPTION: Further reading and related documentation:
- SAPUI5 Flexibility: Enable Your App for UI Adaptation: ../05_Developing_Apps/sapui5-flexibility-enable-your-app-for-ui-adaptation-f1430c0.md
- SAPUI5 Flexibility: Adapting UIs Made Easy: ../04_Essentials/sapui5-flexibility-adapting-uis-made-easy-a8e55aa.md
- Adapting the UI: adapting-the-ui-59bfd31.md
- Extending SAP Fiori Applications (BAS): https://help.sap.com/docs/bas/developing-sap-fiori-app-in-sap-business-application-studio/extending-sap-fiori-application?locale=en-US

LANGUAGE: Text

CODE:
```Text
Follow the linked references for examples, API details, and step-by-step guidance when implementing adaptation projects and ControllerExtension overrides.
```

fiori-elements-framework
adaptation
adaptation-editor
business-application-studio
controllerextension
OData V2
OData V4
list-report
object-page
overview-page


**TITLE**: Extending Generated SAP Fiori Elements Apps Using App Extensions

**INTRODUCTION**: Practical, code-focused guidance for implementing app extensions in SAP Fiori elements generated applications. Covers when to extend, required cautionary constraints, primary extension mechanisms (manifest changes and SAPUI5 extension points), recommended resources and links for OData V2 and V4 scenarios, and pointers to SAP Fiori tools for creating extensions.

**TAGS**: fiori-elements, app-extensions, sapui5, manifest, extensionAPI, odata-v2, odata-v4, sap-fiori-tools

**STEP**: 1 — Read prerequisites and warnings

**DESCRIPTION**: Before implementing extensions, read the "Read Before Extending a Generated App" guidance and follow the caution: prefer manifest settings and annotations over code extensions. Use app extensions only when absolutely necessary.

**LANGUAGE**: text

**CODE**:
```text
Read Before Extending a Generated App:
- Document: read-before-extending-a-generated-app-d9c146a.md
- Key caution: Use app extensions only when required. Prefer manifest settings or annotations.
- Integration rule: Use only the SAP Fiori elements extensionAPI. Do NOT access or manipulate internal framework controls, properties, models, or binding internals.
```

**STEP**: 2 — Choose extension mechanism based on floorplan

**DESCRIPTION**: Determine which mechanism is appropriate for your floorplan:
- Use manifest.json modifications for configuration-based extensions where available.
- Use SAPUI5 extension points (controller extensions, custom fragments, XML view hooks) when UI control placement or custom logic is required.
- Remember: display/layout and runtime behavior become your responsibility after extension; Fiori elements only supports official extensionAPI functions.

**LANGUAGE**: text

**CODE**:
```text
Typical extension touchpoints:
- File: webapp/manifest.json (manifest-based configuration changes)
- Files: webapp/ext/<yourExtensionController>.js or webapp/controls/<customFragment>.fragment.xml (UI5 controller/fragment extensions)
- Hook into SAP Fiori elements using: extensionAPI methods (see API reference)
Note: After creating an extension, the app owner is responsible for display and runtime behavior.
```

**STEP**: 3 — Use the official ExtensionAPI only

**DESCRIPTION**: All code-based extensions must integrate with SAP Fiori elements via the documented ExtensionAPI. Do not manipulate internal framework objects. Use ExtensionAPI functions for adding filters, actions, navigation, or custom UI elements where supported.

**LANGUAGE**: text

**CODE**:
```text
ExtensionAPI reference:
- OData V4 / UI5 API: https://ui5.sap.com/#/api/sap.fe.core.ExtensionAPI
- Follow only the public methods and lifecycle patterns documented here.
```

**STEP**: 4 — Use SAP Fiori tools to create app extensions (recommended workflow)

**DESCRIPTION**: Use SAP Fiori tools extensions for Visual Studio Code or SAP Business Application Studio to scaffold and maintain app extension artifacts. These tools provide guided configuration for page elements and extension wiring.

**LANGUAGE**: text

**CODE**:
```text
SAP Fiori tools resources:
- SAP Fiori tools: https://help.sap.com/viewer/product/SAP_FIORI_tools/Latest/en-US
- Configure Page Elements: https://help.sap.com/docs/SAP_FIORI_tools/17d50220bcd848aa854c9c182d65b699/047507c86afa4e96bb3d284adb9f4726.html
```

**STEP**: 5 — Follow floorplan-specific extension docs and examples

**DESCRIPTION**: Consult these specific guides per floorplan to apply the correct extension patterns and manifest changes. Use them to find specific extension points and scaffolding examples.

**LANGUAGE**: text

**CODE**:
```text
Floorplan-specific extension documentation:
- Extending List Reports and Object Pages Using App Extensions:
  extending-list-reports-and-object-pages-using-app-extensions-a892eb8.md
- Configuring Analytical List Page App Extensions:
  configuring-analytical-list-page-app-extensions-9504fb4.md
- Configuring Overview Page App Extensions:
  configuring-overview-page-app-extensions-b240f61.md
- General SAPUI5 app extension patterns:
  ../08_Extending_SAPUI5_Applications/extending-apps-a264a9a.md
```

**STEP**: 6 — OData V2 vs V4 considerations

**DESCRIPTION**: When working with OData V2 or V4, prefer the extension guidance for the respective version. For OData V4, consult the ExtensionAPI reference on UI5 for the exact API surface.

**LANGUAGE**: text

**CODE**:
```text
Additional features & references:
- SAP Fiori elements for OData V2: use SAP Fiori tools and floorplan-specific docs (see Step 5)
- SAP Fiori elements for OData V4: ExtensionAPI reference:
  https://ui5.sap.com/#/api/sap.fe.core.ExtensionAPI
```

**STEP**: 7 — Checklist before committing extension code

**DESCRIPTION**: Quick checklist for code-generation agents to validate extension readiness and compliance.

**LANGUAGE**: text

**CODE**:
```text
Pre-commit checklist:
- Confirm requirement cannot be met with manifest settings or annotations.
- Confirm only public ExtensionAPI methods are used.
- Ensure no direct access to framework internals (controls, private models, binding internals).
- Add unit/integration tests for new extension behaviors.
- Document extension location: webapp/manifest.json changes, webapp/ext/<files>, and any fragment XML.
- Verify compatibility with the targeted SAP Fiori elements floorplan and OData version.
```


**TITLE**: Extending List Reports and Object Pages Using App Extensions

**INTRODUCTION**: This document summarizes the required precautions, resources, and actionable steps for adding app extensions to SAP Fiori elements List Reports and Object Pages. Use this as a concise checklist and link map for implementing extensions safely and correctly. Prefer manifest/annotation/configuration solutions; use app extensions only when necessary. Always use the SAP Fiori elements extensionAPI.

**TAGS**: fiori-elements, app-extension, extensionAPI, list-report, object-page, SAP Fiori tools

**STEP**: 1 — Read prerequisite guidance

**DESCRIPTION**: Before creating any app extension, read the prerequisite guidance that explains extension implications and best practices. This ensures you understand what parts of the app you can safely extend and what must remain managed by SAP Fiori elements.

**LANGUAGE**: text

**CODE**:
```text
Read: "Read Before Extending a Generated App"
Path or link: read-before-extending-a-generated-app-d9c146a.md
```

**STEP**: 2 — Follow the security/maintenance caution

**DESCRIPTION**: Only use app extensions when required. After you add an extension, display/layout and system behavior of that extension (control placement, model usage, busy handling) become your responsibility. Do not access or manipulate internal SAP Fiori elements framework objects (controls, models, bindings) directly. Use only the official extensionAPI exposed by SAP Fiori elements.

**LANGUAGE**: text

**CODE**:
```text
Caution:
- Use app extensions only if manifest settings, annotations, or standard APIs can't achieve the behavior.
- Use only the SAP Fiori elements extensionAPI. Do NOT access internal controls, models, properties, or binding internals created by the framework.
```

**STEP**: 3 — Learn how to use the extensionAPI

**DESCRIPTION**: Use the official extensionAPI for all integration points between your extension code and SAP Fiori elements. Review the extensionAPI documentation to find supported methods, lifecycle hooks, and recommended patterns. This avoids fragile implementations and ensures compatibility with framework-managed features (e.g., smart handling, navigation, message handling).

**LANGUAGE**: text

**CODE**:
```text
Reference: "Using the extensionAPI"
Path or link: using-the-extensionapi-bd2994b.md
```

**STEP**: 4 — Create extensions using SAP Fiori tools or manually

**DESCRIPTION**: You can scaffold and manage app extensions either via SAP Fiori tools (recommended) or manually:
- SAP Fiori tools: extensions for Business Application Studio and Visual Studio Code provide GUI and generators.
- Manual: create extension files and register them according to your project structure/manifest.

Use the Configure Page Elements documentation for step-by-step guidance on creating and wiring the extension points.

**LANGUAGE**: text

**CODE**:
```text
SAP Fiori tools: https://help.sap.com/viewer/product/SAP_FIORI_tools/Latest/en-US
Guide: "Configure Page Elements" - https://help.sap.com/docs/SAP_FIORI_tools/17d50220bcd848aa854c9c182d65b699/047507c86afa4e96bb3d284adb9f4726.html
```

**STEP**: 5 — Note about deprecated Web IDE videos

**DESCRIPTION**: Older video walkthroughs using SAP Web IDE were removed from the main documentation because SAP Web IDE is no longer actively supported. If needed, you can still access archived video content from older versions of the documentation.

**LANGUAGE**: text

**CODE**:
```text
Note: Web IDE step-by-step videos removed from current docs; archived versions remain available in older document versions.
```

**STEP**: 6 — Related example: add a custom message strip

**DESCRIPTION**: If your extension needs to show custom text messages above a table on a List Report or Object Page, review the "Adding a Custom Message Strip" example for implementation details.

**LANGUAGE**: text

**CODE**:
```text
Related doc: "Adding a Custom Message Strip to List Report and Analytical List Page"
Link: adding-a-custom-message-strip-to-list-report-analytical-list-page-and-object-page-tables-0fdbefb.md
```

fiori-elements
app-extension
extensionAPI
list-report
object-page
SAP Fiori tools


**TITLE**: App Extension Manifest Examples for SAP Fiori Elements (OData V2 & V4)

**INTRODUCTION**: This document provides concrete manifest examples and actionable guidance to register controller extensions for SAP Fiori elements-based apps. It shows how to target controllers at different specificity levels (global view vs. specific page instance) for both OData V2 and OData V4 floorplans. Use these manifest snippets when you need to override or extend standard controllers on an Object Page or other Fiori Elements views.

**TAGS**: fiori-elements-framework, sapui5, manifest, object-page, odata-v2, odata-v4, extension, routing

**STEP**: 1 — OData V2: Register a global view controller and a page-specific controller

**DESCRIPTION**: Add controller registration entries in the manifest to load either a generic controller for a view or a more specific controller for a single page instance. The "most specific" manifest key wins. Behind the hash (#) is the view ID that makes an entry page-specific.

**LANGUAGE**: JSON

**CODE**:
```json
"sap.suite.ui.generic.template.ObjectPage.view.Details": {
	"controllerName": "SalesOrder.ext.controller.DetailsExtension",
},
"sap.suite.ui.generic.template.ObjectPage.view.Details#SalesOrder::sap.suite.ui.generic.template.ObjectPage.view.Details::SalesOrder_WD" {
	"controllerName": "SalesOrder.ext.controller.SalesOrderExtension",
}
```

**STEP**: 2 — OData V4: Register a generic ObjectPage controller and a page-specific controller

**DESCRIPTION**: For OData V4 Fiori Elements, register controllerName for the template controller and a more specific entry that includes the page ID after the hash. The specific entry will be used for the given page ID; the generic one is the fallback.

**LANGUAGE**: JSON

**CODE**:
```json
"sap.fe.templates.ObjectPage.ObjectPageController": {
    "controllerName": "SalesOrder.ext.OPExtend"
},
"sap.fe.templates.ObjectPage.ObjectPageController#SalesOrder::SalesOrderManageObjectPage": {
    "controllerName": "SalesOrder.ext.SalesOrderOPExtend"
}
```

**STEP**: 3 — OData V2: Multiple page-specific controller registrations with entity set mapping

**DESCRIPTION**: Example showing multiple manifest keys mapping different page instances (by app name, view ID and entity set) to distinct controllers. This pattern is useful when a single application contains multiple object pages (different entity sets) that require different controller extensions. The "most specific" entry (including the hash) overrides the generic view entry.

**LANGUAGE**: JSON

**CODE**:
```json
"sap.suite.ui.generic.template.ObjectPage.view.Details": {
                        "controllerName": "STTASOWD20.ext.controller.DetailsExtension",
                        "sap.ui.generic.app": {
                            "C_STTA_SalesOrder_WD_20": {
                                "EntitySet": "C_STTA_SalesOrder_WD_20"
                            }
                        }
                    },
                    "sap.suite.ui.generic.template.ObjectPage.view.Details#STTASOWD20::sap.suite.ui.generic.template.ObjectPage.view.Details::C_STTA_SalesOrder_WD_20": {
                        "controllerName": "STTASOWD20.ext.controller.SalesOrderExtension",
                        "sap.ui.generic.app": {
                            "C_STTA_SalesOrder_WD_20": {
                                "EntitySet": "C_STTA_SalesOrder_WD_20"
                            }
                        }
                    },
                    "sap.suite.ui.generic.template.ObjectPage.view.Details#STTASOWD20::sap.suite.ui.generic.template.ObjectPage.view.Details::C_STTA_SalesOrderItem_WD_20": {
                        "controllerName": "STTASOWD20.ext.controller.SalesOrderItemExtension",
                        "sap.ui.generic.app": {
                            "C_STTA_SalesOrderItem_WD_20": {
                                "EntitySet": "C_STTA_SalesOrderItem_WD_20"
                            }
                        }
                    }
```

**STEP**: 4 — OData V4: Use routing configuration to derive the page ID for targeting extensions

**DESCRIPTION**: For OData V4, object page targets are typically defined via the routing configuration in the manifest. The target ID (for example "MainEntityObjectPage") combined with the application ID becomes the page ID you can use after the hash in controller registration (MyApplicationID::MainEntityObjectPage). Use this manifest routing example to determine the page identifier for page-specific extension entries.

**LANGUAGE**: JSON

**CODE**:
```json
{
   "sap.app": {
      "id": "MyApplicationID",
      "type": "application"
   },
   "sap.ui5": {
   "routing": {
          "config": {
            "async": true
          },
          "routes": [
            {
              "pattern": "MainEntity({key}):?query:",
              "name": "MainEntityObjectPage",
              "target": "MainEntityObjectPageTarget"
            }
          ],
          "targets": {
            "MainEntityObjectPageTarget": {
              "type": "Component",
              "id": "MainEntityObjectPage",
              "name": "sap.fe.templates.ObjectPage",
              "options": {
                "settings": {
                  "contextPath": "/MainEntity"
                }
              }
            }
          }
        }
   }
}
```

**STEP**: 5 — Additional notes and supported floorplans (OData V2)

**DESCRIPTION**: Adaptation-style app extensions allow safe, upgrade-friendly customizations and are supported for these floorplans: list report, object page, overview page and analytical list page. Extension points can be implemented via manifest changes or SAPUI5 extension points depending on the floorplan. See your project’s adaptation/extension strategy and use the manifest patterns above to register controller overrides.


**TITLE**: Enforce Static Launchpad Tiles for Fiori Elements Bookmarks (OData V2)

**INTRODUCTION**: Extend the standard bookmark function in SAP Fiori elements (OData V2) to force creation of static tiles on the SAP Fiori Launchpad by adding the onSaveAsTileExtension extension point to a list report or analytical list page controller extension. Use this when dynamic tiles are undesirable (e.g., to avoid incorrect runtime data fetches or inconsistent representations).

**TAGS**: fiori-elements-framework, SAP Fiori, bookmark, launchpad, tiles, static-tile, OData V2, extension-point, controller-extension, manifest

**STEP**: 1 — Preconditions and behavior summary

**DESCRIPTION**: Confirm applicability and understand default behavior:
- Applicable only for SAP Fiori elements for OData V2.
- The onSaveAsTileExtension extension point is usable only for tiles added using the bookmark (Share) function.
- Default tile behavior:
  - List reports and analytical list pages: dynamic tiles by default, except if semantic date range fields are used and populated — then a static tile is created.
  - Object pages: static tile by default.
- Use the extension to enforce a static tile (prevent dynamic tile creation) by overriding the serviceUrl field on the oShareInfo object.

**LANGUAGE**: Text

**CODE**:
```text
Notes:
- Ensure you already added a controller extension in manifest.json for your app (prerequisite).
- The extension receives a single parameter oShareInfo; set oShareInfo.serviceUrl = "" to force a static tile.
```

**STEP**: 2 — Implement onSaveAsTileExtension in your controller extension

**DESCRIPTION**: Add the onSaveAsTileExtension method to your controller extension file. Overwrite the serviceUrl field on the provided oShareInfo object. Setting serviceUrl to an empty string forces a static tile. You may instead set it to any explicit service URL string to control dynamic tile behavior.

**LANGUAGE**: JavaScript

**CODE**:
```javascript
sap.ui.define([], function () {
   "use strict";
   return {
      onSaveAsTileExtension: function(oShareInfo) {
         oShareInfo.serviceUrl = ""; // Force static tile
      }
   };
});
```

**STEP**: 3 — Implementation notes and alternatives

**DESCRIPTION**: Implementation details to follow while coding:
- Place the above code in your controller extension module (the module referenced in manifest.json).
- The extension receives oShareInfo; available fields include serviceUrl (the one to override). Setting it to "" enforces a static tile; setting it to a specific URL string forces a dynamic tile that uses that URL.
- Use this extension only for tiles created via the Share/bookmark action. It does not affect other tile creation mechanisms.
- Consider semantic date range behavior: if the filter bar uses semantic date range fields and any such field is populated, a static tile may be created by default; otherwise a dynamic tile is used for list reports and analytical list pages.

**LANGUAGE**: Text

**CODE**:
```text
Reminder:
- This approach is intended for OData V2 Fiori elements apps.
- Ensure the controller extension entry exists in manifest.json before adding the method.
```

fiori-elements-framework
SAP Fiori
bookmark
launchpad
tiles
static-tile
OData V2
extension-point
controller-extension
manifest


**TITLE**: Extending Delivered Apps Manifest Using an Adaptation Project (SAP Fiori elements, OData V2)

**INTRODUCTION**: This guide shows exact manifest/appdescr_variant and annotation changes to extend SAP-delivered Fiori elements apps using an adaptation project. Use the provided JSON/XML snippets to:
- add new subobject pages,
- change page and application configurations (table types, createMode, filters, navigation, etc.),
- add selection presentation variants via annotations,
- include reuse components (libraries/componentUsages and embeddedComponents),
and to register annotation files in the adaptation project's manifest.appdescr_variant.

**TAGS**: fiori-elements-framework, adaptation, manifest.appdescr_variant, manifest.json, OData V2, annotations, reuse-component, neo-app.json, headerWhiteList

**STEP**: Prerequisites

**DESCRIPTION**: Ensure you meet these preconditions before applying the changes:
- SAPUI5 1.108 or higher (ABAP platform 2021 or higher).
- In the application manifest.json, pages and subpages must be specified in object format within sap.ui.generic.app (array format supported as of SAPUI5 1.133).
- Backend: new navigation node must be added and exposed in the OData service metadata before adding a new subobject page.

**LANGUAGE**: Text

**CODE**:
```Text
Files referenced:
- manifest.appdescr_variant (adaptation project) -> Add change definitions to the content[] array.
- manifest.json (application) -> target for the mergers identified by parentPage/entitySet and propertyPath.
- neo-app.json (consuming application) -> add headerWhiteList when reuse components require specific headers.
- changes/annotations/annotations.xml -> local annotation file referenced by appdescr_variant if adding annotations.
```

**STEP**: Add a New Subobject Page (manifest.appdescr_variant)

**DESCRIPTION**: Add this JSON change object to the adaptation project's manifest.appdescr_variant content[] to add a detail (subobject) page for a newly extended node. Ensure the backend navigationProperty and entitySet exist. Set the appropriate layer prefix in childPage.id (e.g., "customer." for customer/vendor layers as described).

**LANGUAGE**: JSON

**CODE**:
```json
{
    "changeType": "appdescr_ui_generic_app_addNewObjectPage",
    "content": {
        "parentPage": {
        "component": "sap.suite.ui.generic.template.ObjectPage",
            "entitySet": "C_STTA_SalesOrder_WD_20"
        },
        "childPage": {
            "id": "customer.ObjectPage|to_extendedNode",
            "definition": {
                "navigationProperty": "to_extendedNode",
                "entitySet": "C_STTA_ExtendedNode"
            }
        }
    }
}
```

**STEP**: Define Node Configuration (createMode, table type) (manifest.appdescr_variant)

**DESCRIPTION**: Use this change to UPSERT section settings for a given parent page (ObjectPage). Adjust propertyPath to point to the facet/section ID (component/settings/sections/<facetId>) or to the component/settings root for page-level settings.

**LANGUAGE**: JSON

**CODE**:
```json
{
    "changeType": "appdescr_ui_generic_app_changePageConfiguration",
    "content": {
        "parentPage": {
            "component": "sap.suite.ui.generic.template.ObjectPage",
            "entitySet": "C_STTA_SalesOrder_WD_20"
        },
        "entityPropertyChange": {
            "propertyPath": "component/settings/sections/extendedFacetId",
            "operation": "UPSERT",
            "propertyValue": {
                "createMode": "inline",
                "tableSettings": {
                    "tableType": "GridTable"
                }
            }
        }
    }
}
```

**STEP**: Modify Application-level Settings (createMode & flexibleColumnLayout) (manifest.appdescr_variant)

**DESCRIPTION**: UPSERT application-level settings (component settings) such as tableSettings.createMode and flexibleColumnLayout defaults. Add this object to the content[] array.

**LANGUAGE**: JSON

**CODE**:
```json
{
    "changeType": "appdescr_ui_generic_app_changePageConfiguration",
    "content": {
        "parentPage": {
            "component": "sap.suite.ui.generic.template"
        },
        "entityPropertyChange": {
            "propertyPath": "settings",
            "operation": "UPSERT",
            "propertyValue": {
                "tableSettings": {
                    "createMode": "creationRows"
                },
                "flexibleColumnLayout": {
                    "defaultTwoColumnLayoutType": "TwoColumnsMidExpanded",
                    "defaultThreeColumnLayoutType": "ThreeColumnsEndExpanded"
                }
            }
        }
    }
}
```

**STEP**: Modify externalNavigationSettings and inboundParameters (manifest.appdescr_variant)

**DESCRIPTION**: Use this UPSERT to add external navigation defaults and inbound parameter settings at the component settings level.

**LANGUAGE**: JSON

**CODE**:
```json
{
    "changeType": "appdescr_ui_generic_app_changePageConfiguration",
    "content": {
        "parentPage": {
            "component": "sap.suite.ui.generic.template"
        },
        "entityPropertyChange": {
            "propertyPath": "settings",
            "operation": "UPSERT",
            "propertyValue": {
                "externalNavigationSettings": {
                    "defaultOutboundSettings": {
                        "refreshStrategyOnAppRestore": {
                            "entitySets": {
                                "STTA_C_MP_Product": "self"
                            }
                        }
                    }
                },
                "inboundParameters": {
                    "Supplier": {
                        "useForCreate": true
                    }
                }
            }
        }
    }
}
```

**STEP**: Add filterSettings (historySettings & dateSettings) for List Report (manifest.appdescr_variant)

**DESCRIPTION**: UPSERT list report component settings to configure filter history and date filter behavior for an entitySet.

**LANGUAGE**: JSON

**CODE**:
```json
{
    "changeType": "appdescr_ui_generic_app_changePageConfiguration",
    "content": {
        "parentPage": {
            "component": "sap.suite.ui.generic.template.ListReport",
            "entitySet": "STTA_C_MP_Product"
        },
        "entityPropertyChange": {
            "propertyPath": "component/settings",
            "operation": "UPSERT",
            "propertyValue": {
                "filterSettings": {
                    "historySettings": {
                        "historyEnabled": "enabled"
                    },
                    "dateSettings": {
                        "useDateRange": false,
                        "selectedValues": "DAYS,WEEK,MONTH,DATERANGE",
                        "fields": {
                            "SemanticDate1": {
                                "selectedValues": "TOMORROW",
                                "exclude": true
                            },
                            "SemanticDate2": {
                                "defaultValue": {
                                    "operation": "LASTYEAR"
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```

**STEP**: Enable table filter in page variant, dataLoadSettings, condensedTableLayout (manifest.appdescr_variant)

**DESCRIPTION**: UPSERT these list report settings to enable table filter in page variants, control initial data load, and set table layout.

**LANGUAGE**: JSON

**CODE**:
```json
{
    "changeType": "appdescr_ui_generic_app_changePageConfiguration",
    "content": {
        "parentPage": {
            "component": "sap.suite.ui.generic.template.ListReport",
            "entitySet": "STTA_C_MP_Product"
        },
        "entityPropertyChange": {
            "propertyPath": "component/settings",
            "operation": "UPSERT",
            "propertyValue": {
                "enableTableFilterInPageVariant":true,
                "dataLoadSettings": {
                    "loadDataOnAppLaunch": "never"
                },
                "condensedTableLayout":true
            }
        }
    }
}
```

**STEP**: Change tableSettings (type, multiSelect, selectAll, multiEdit) (manifest.appdescr_variant)

**DESCRIPTION**: UPSERT table settings on the List Report for an entitySet to configure table type and selection/multi-edit behaviors.

**LANGUAGE**: JSON

**CODE**:
```json
{
    "changeType": "appdescr_ui_generic_app_changePageConfiguration",
    "content": {
        "parentPage": {
            "component": "sap.suite.ui.generic.template.ListReport",
            "entitySet": "STTA_C_MP_Product"
        },
        "entityPropertyChange": {
            "propertyPath": "component/settings/tableSettings",
            "operation": "UPSERT",
            "propertyValue": {
                "type": "GridTable",
                "multiSelect": true,
                "selectAll": false,
                "multiEdit": {
                    "enabled": true
                }
            }
        }
    }
}
```

**STEP**: Add fields to createWithParameterDialog (manifest.appdescr_variant)

**DESCRIPTION**: UPSERT dialog fields mapping for createWithParameterDialog in tableSettings. Adjust path to entitySet that contains the table.

**LANGUAGE**: JSON

**CODE**:
```json
{
    "changeType": "appdescr_ui_generic_app_changePageConfiguration",
    "content": {
        "parentPage": {
            "component": "sap.suite.ui.generic.template.ListReport",
            "entitySet": "STTA_C_SO_SalesOrder_ND"
        },
        "entityPropertyChange": {
            "propertyPath":
            "component/settings/tableSettings/createWithParameterDialog/fields",
            "operation": "UPSERT",
            "propertyValue": {
                "CurrencyCode":{
                    "path":"CurrencyCode"
                }
            }
        }
    }
}
```

**STEP**: Modify Object Page editableHeaderContent and showRelatedApps (manifest.appdescr_variant)

**DESCRIPTION**: UPSERT object page component settings to toggle editableHeaderContent and showRelatedApps flags.

**LANGUAGE**: JSON

**CODE**:
```json
{
    "changeType": "appdescr_ui_generic_app_changePageConfiguration",
    "content": {
        "parentPage" : {
            "component": "sap.suite.ui.generic.template.ObjectPage",
            "entitySet": "STTA_C_MP_Product"
        },
        "entityPropertyChange": {
            "propertyPath": "component/settings",
            "operation": "UPSERT",
            "propertyValue": {
                "editableHeaderContent":false,
                "showRelatedApps":false
            }
        }
    }
}
```

**STEP**: Add createMode for Object Page tableSettings (manifest.appdescr_variant)

**DESCRIPTION**: UPSERT object page tableSettings for creationRows and selection behavior.

**LANGUAGE**: JSON

**CODE**:
```json
{
    "changeType": "appdescr_ui_generic_app_changePageConfiguration",
    "content": {
        "parentPage": {
            "component": "sap.suite.ui.generic.template.ObjectPage",
            "entitySet": "STTA_C_SO_SalesOrder_ND"
        },
        "entityPropertyChange": {
            "propertyPath": "component/settings/tableSettings",
            "operation": "UPSERT",
            "propertyValue": {
                "createMode": "creationRows",
                "multiSelect": true,
                "selectAll": false
            }
        }
    }
}
```

**STEP**: Add Selection Presentation Variant via component settings (manifest.appdescr_variant)

**DESCRIPTION**: UPSERT annotationPath at the List Report component settings to reference a SelectionPresentationVariant (SPV) qualifier defined in an annotation file. After this manifest change, add the annotation file to the adaptation project and register it (next steps).

**LANGUAGE**: JSON

**CODE**:
```json
{
    "changeType": "appdescr_ui_generic_app_changePageConfiguration",
    "content": {
        "parentPage" : {
            "component": "sap.suite.ui.generic.template.ListReport",
            "entitySet": "STTA_C_MP_Product"
        },
        "entityPropertyChange": {
            "propertyPath": "component/settings",
            "operation": "UPSERT",
            "propertyValue": {
                "annotationPath": "com.sap.vocabularies.UI.v1.SelectionPresentationVariant#DefaultSPV"
            }
        }
    }
}
```

**STEP**: Create local annotation file (EDMX XML) in adaptation project

**DESCRIPTION**: Create a local annotation file (e.g., changes/annotations/annotations.xml) in the adaptation project containing the SelectionPresentationVariant, PresentationVariant, LineItem, SelectionFields and SelectionVariant definitions. Use the exact EDMX content below (keep edmx:Reference URIs and Annotations Target set to your namespace/entity type).

**LANGUAGE**: XML

**CODE**:
```xml
<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">
    <edmx:Reference Uri="https://fiorielementsqh3815snapshot-xdf25c17a.dispatcher.neo.ondemand.com/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_COMMON',Version='0001',SAP__Origin='LOCAL')/$value">
        <edmx:Include Namespace="com.sap.vocabularies.Common.v1" Alias="Common"/>
    </edmx:Reference>
    <edmx:Reference Uri="/sap/bc/ui5_ui5/ui2/ushell/resources/sap/ushell/components/factsheet/vocabularies/UI.xml">
        <edmx:Include Alias="UI" Namespace="com.sap.vocabularies.UI.v1"/>
    </edmx:Reference>
    <edmx:Reference Uri="http://docs.oasis-open.org/odata/odata/v4.0/cs01/vocabularies/Org.OData.Capabilities.V1.xml">
        <edmx:Include Alias="Capabilities" Namespace="Org.OData.Capabilities.V1"/>
    </edmx:Reference>
    <edmx:Reference	Uri="/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_COMMUNICATION',Version='0001',SAP__Origin='LOCAL')/$value">
        <edmx:Include Namespace="com.sap.vocabularies.Communication.v1" Alias="Communication"/>
    </edmx:Reference>
    <edmx:Reference Uri="http://docs.oasis-open.org/odata/odata/v4.0/cs01/vocabularies/Org.OData.Measures.V1.xml">
        <edmx:Include Alias="Measures" Namespace="Org.OData.Measures.V1"/>
    </edmx:Reference>
    <edmx:Reference Uri="/sap/opu/odata/sap/STTA_PROD_MAN/$metadata">
        <edmx:Include Alias="STTA_PROD_MAN" Namespace="STTA_PROD_MAN"/>
    </edmx:Reference>
    <edmx:Reference Uri="http://docs.oasis-open.org/odata/odata-data-aggregation-ext/v4.0/cs02/vocabularies/Org.OData.Aggregation.V1.xml">
        <edmx:Include Alias="Aggregation" Namespace="Org.OData.Aggregation.V1"/>
    </edmx:Reference>
    <edmx:Reference Uri="http://docs.oasis-open.org/odata/odata/v4.0/errata03/os/complete/vocabularies/Org.OData.Core.V1.xml">
        <edmx:Include Alias="Core" Namespace="Org.OData.Core.V1"/>
    </edmx:Reference>
    <edmx:DataServices>
        <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm">
            <Annotations Target="STTA_PROD_MAN.STTA_C_MP_ProductType">
                <Annotation Term="com.sap.vocabularies.UI.v1.SelectionPresentationVariant" Qualifier="DefaultSPV">
                    <Record>
                        <PropertyValue Property="ID" String=""/>
                        <PropertyValue Property="Text" String="Default SPV"/>
                        <PropertyValue Property="SelectionVariant" Path="@UI.SelectionVariant#FilterDefaults"/>
                        <PropertyValue Property="PresentationVariant" Path="@UI.PresentationVariant#ManageProducts"/>
                    </Record>
                </Annotation>
                <Annotation Term="com.sap.vocabularies.UI.v1.PresentationVariant" Qualifier="ManageProducts">
                    <Record>
                        <PropertyValue Property="SortOrder">
                            <Collection>
                                <Record Type="com.sap.vocabularies.Common.v1.SortOrderType">
                                    <PropertyValue Property="Property" PropertyPath="Price"/>
                                    <PropertyValue Property="Descending" Bool="false"/>
                                </Record>
                            </Collection>
                        </PropertyValue>
                        <PropertyValue Property="Visualizations">
                            <Collection>
                                <AnnotationPath>@com.sap.vocabularies.UI.v1.LineItem#ManageProducts</AnnotationPath>
                            </Collection>
                        </PropertyValue>
                    </Record>
                </Annotation>
                <Annotation Term="UI.LineItem" Qualifier="ManageProducts">
                    <Collection>
                        <Record Type="UI.DataField">
                            <PropertyValue Property="Value" Path="Price"/>
                            <Annotation Term="UI.Importance" EnumMember="UI.ImportanceType/High"/>
                        </Record>
                        <Record Type="UI.DataFieldForAction">
                            <PropertyValue Property="Label" String="New Activate Button"/>
                            <PropertyValue Property="Action" String="STTA_PROD_MAN.STTA_PROD_MAN_Entities/STTA_C_MP_ProductActivation"/>
                            <PropertyValue Property="InvocationGrouping" EnumMember="UI.OperationGroupingType/ChangeSet"/>
                        </Record>
                        <Record Type="UI.DataField">
                            <PropertyValue Property="Value" Path="ProductPictureURL"/>
                            <Annotation Term="UI.Importance" EnumMember="UI.ImportanceType/High"/>
                        </Record>
                        <Record Type="UI.DataField">
                            <PropertyValue Property="Value" Path="Supplier"/>
                            <Annotation Term="UI.Importance" EnumMember="UI.ImportanceType/High"/>
                        </Record>
                        <Record Type="UI.DataField">
                            <PropertyValue Property="Label" String="Product-ID/-Text"/>
                            <PropertyValue Property="Value" Path="ProductForEdit"/>
                            <Annotation Term="UI.Importance" EnumMember="UI.ImportanceType/High"/>
                        </Record>
                        <Record Type="UI.DataField">
                            <PropertyValue Property="Label" String="Width"/>
                            <PropertyValue Property="Value" Path="Width"/>
                            <Annotation Term="UI.Importance" EnumMember="UI.ImportanceType/High"/>
                        </Record>
                    </Collection>
                </Annotation>
                <Annotation Term="UI.SelectionFields">
                    <Collection>
                        <PropertyPath>Width</PropertyPath>
                    </Collection>
                </Annotation>
                <Annotation Term="UI.SelectionVariant" Qualifier="FilterDefaults">
                    <Record>
                        <PropertyValue Property="Parameters">
                            <Collection>
                            </Collection>
                        </PropertyValue>
                        <PropertyValue Property="SelectOptions">
                            <Collection>
                                <Record Type="UI.SelectOptionType">
                                    <PropertyValue Property="PropertyName" PropertyPath="Width"/>
                                    <PropertyValue Property="Ranges">
                                        <Collection>
                                            <Record>
                                                <PropertyValue Property="Sign" EnumMember="com.sap.vocabularies.UI.v1.SelectionRangeSignType/I"/>
                                                <PropertyValue Property="Option" EnumMember="UI.SelectionRangeOptionType/BT"/>
                                                <PropertyValue Property="Low" String="1.0"/>
                                                <PropertyValue Property="High" String="20.00"/>
                                            </Record>
                                        </Collection>
                                    </PropertyValue>
                                </Record>
                            </Collection>
                        </PropertyValue>
                    </Record>
                </Annotation>
            </Annotations>
        </Schema>
    </edmx:DataServices>
</edmx:Edmx>
```

**STEP**: Register the newly created annotation in manifest.appdescr_variant (manifest.appdescr_variant)

**DESCRIPTION**: Add this appdescr_app_addAnnotationsToOData change to content[] to register the local annotation file under the mainService data source. Adjust dataSourceId and annotations keys to match your project.

**LANGUAGE**: JSON

**CODE**:
```json
{
"changeType": "appdescr_app_addAnnotationsToOData",
    "content": {
        "dataSourceId": "mainService",
        "annotations": ["customer.localAnnotationsNew"],
        "annotationsInsertPosition": "END",
        "dataSource": {
            "customer.localAnnotationsNew": {
                "uri": "changes/annotations/annotations.xml", "type": "ODataAnnotation"
            }
        }
    }
}
```

**STEP**: Include a Reuse Component (clone, neo-app.json headerWhiteList, manifest.appdescr_variant)

**DESCRIPTION**: To include a reuse component:
1. Clone the reuse component into the workspace and ensure the reuse component is available in the target backend.
2. Add required headers in neo-app.json headerWhiteList for the consuming application (if the reuse component requires them).
3. In the adaptation project's manifest.appdescr_variant content[], add appdescr_ui5_addComponentUsages, appdescr_ui5_addLibraries and appdescr_ui_generic_app_changePageConfiguration entries to register componentUsage, library and embed the component on the ObjectPage (embeddedComponents).

Preserve corresponding reuse component configuration (e.g., attachments require additional neo-app.json parameters).

**LANGUAGE**: JSON

**CODE**:
```json
"headerWhiteList": [
    "objecttype",
    "objectkey",
    "slug",
    "MarkForDeletion",
    "documentType",
    "documentNumber",
    "documentVersion",
    "documentPart",
    "semanticobjecttype"
]
```

**STEP**: Add componentUsages, libraries and embedded component to manifest.appdescr_variant (manifest.appdescr_variant)

**DESCRIPTION**: Add these change objects to content[] in manifest.appdescr_variant to register the reuse component usage, its library and embed it into the ObjectPage as an embeddedComponents entry.

**LANGUAGE**: JSON

**CODE**:
```json
{
    "changeType": "appdescr_ui5_addComponentUsages",
    "content": {
        "componentUsages": {
            "attachmentReuseComponent": {
                "name": "sap.se.mi.plm.lib.attachmentservice.attachment.components.stcomponent",
                "settings": {}
            }
        }
    }
},
{
    "changeType": "appdescr_ui5_addLibraries",
    "content": {
        "libraries": {
            "sap.se.mi.plm.lib.attachmentservice": {
                "minVersion": "Active",
                "lazy": true
            }
        }
    }
},
{
    "changeType": "appdescr_ui_generic_app_changePageConfiguration",
    "content": {
        "parentPage": {
            "component": "sap.suite.ui.generic.template.ObjectPage",
            "entitySet": "C_PaymentRunPlanTP"
        },
        "entityPropertyChange": {
            "propertyPath": "embeddedComponents",
            "operation": "UPSERT",
            "propertyValue": {
                "simple::Attachments": {
                    "id": "simple::Attachments",
                    "componentUsage": "attachmentReuseComponent",
                    "title": "Attachment",
                    "settings": {
                        "mode": "C",
                        "objectType": "SCASE",
                        "objectKey": "{PaymentRunPlanName}",
                        "isGuid": true
                    }
                }
            }
        }
    }
},
```

**STEP**: Notes, Limitations & OData V4 pointer

**DESCRIPTION**:
- Table type modifications via adaptation projects can behave differently across applications, OData versions, and configurations — thoroughly test before production.
- Not supported via adaptation projects: adding/modifying filter[] configurations per field and customDateRangeImplementation under filterSettings.
- For OData V4 and additional guidance, see the SAP Fiori tools User Guide "Creating the Project" (link in source documentation).

**LANGUAGE**: Text

**CODE**:
```Text
- Test table type changes across scenarios before productive usage.
- Unsupported in filterSettings via adaptation: filter[] per-field configs and customDateRangeImplementation.
- For OData V4 adaptation steps, consult:
  https://help.sap.com/docs/SAP_FIORI_tools/17d50220bcd848aa854c9c182d65b699/072f566ed1d845b6aa41cb01057700d5.html
```

fiori-elements-framework
adaptation
manifest.appdescr_variant
manifest.json
OData V2
annotations
reuse-component
neo-app.json
headerWhiteList


**TITLE**: Extension Point for List Report Header (Custom Expanded and Collapsed Header Fragments)

**INTRODUCTION**: Configure a List Report to include custom header content above the filter bar by specifying fragment names in manifest.json. Provide UI5 XML fragment files for both expanded and collapsed header states, placed according to the fragment namespace.

**TAGS**: fiori-elements-framework, list-report, extension-point, custom-header, manifest.json, ui5, fragments

**STEP**: 1 — Configure manifest.json to add custom header fragments

**DESCRIPTION**: Add the custom header fragment names under the List Report component target in manifest.json. Use the keys expandedHeaderFragment and collapsedHeaderFragment under content.header.customHeader. These fragment names map to UI5 fragment files by namespace (dot → path).

**LANGUAGE**: JSON

**CODE**:
```json
"targets": {
    "sample": {
        "type": "Component",
        "id": "Default",
        "name": "sap.fe.templates.ListReport",
        "options": {
            "settings": {
                "contextPath": "/RootEntity",
                "variantManagement": "Page",
                "initialLoad": true,
                "liveMode": true,
                "content": {
                    "header": {
                        "customHeader": {
                            "expandedHeaderFragment": "sap.fe.core.fpmExplorer.customListReportHeaderContent.CustomExpandedHeader",
                            "collapsedHeaderFragment": "sap.fe.core.fpmExplorer.customListReportHeaderContent.CustomCollapsedHeader"
                        }
                    }
                }
            }
        }
    }
}
```

**STEP**: 2 — Create the expanded header fragment file

**DESCRIPTION**: Implement the expanded header fragment as an XML fragment at the path derived from the fragment namespace:
webapp/sap/fe/core/fpmExplorer/customListReportHeaderContent/CustomExpandedHeader.fragment.xml. The fragment content is rendered above the filter bar when the header is expanded. Replace the sample controls with your custom UI5 controls.

**LANGUAGE**: XML

**CODE**:
```xml
<!-- File: webapp/sap/fe/core/fpmExplorer/customListReportHeaderContent/CustomExpandedHeader.fragment.xml -->
<core:FragmentDefinition xmlns="sap.m" xmlns:core="sap.ui.core">
  <VBox>
    <!-- Replace with your custom controls for expanded header -->
    <Text text="Custom Expanded Header" />
  </VBox>
</core:FragmentDefinition>
```

**STEP**: 3 — Create the collapsed header fragment file

**DESCRIPTION**: Implement the collapsed header fragment as an XML fragment at:
webapp/sap/fe/core/fpmExplorer/customListReportHeaderContent/CustomCollapsedHeader.fragment.xml. This fragment is used when the header is collapsed. Keep it minimal for compact display.

**LANGUAGE**: XML

**CODE**:
```xml
<!-- File: webapp/sap/fe/core/fpmExplorer/customListReportHeaderContent/CustomCollapsedHeader.fragment.xml -->
<core:FragmentDefinition xmlns="sap.m" xmlns:core="sap.ui.core">
  <!-- Replace with your compact controls for collapsed header -->
  <HBox>
    <Text text="Custom Collapsed Header" />
  </HBox>
</core:FragmentDefinition>
```

**STEP**: 4 — Notes and validation

**DESCRIPTION**:
- The custom header content is inserted above the filter bar. Implement behavior and styling in the fragment controls or associated controllers as needed.
- Verify fragment namespace-to-file mapping: dots in the fragment name map to path separators in webapp/.
- For live examples and additional implementation details, consult the SAP Fiori development portal topic: Standard Floorplans - Extensions - Extensions for List-Based Pages - Custom Header:
https://ui5.sap.com/test-resources/sap/fe/core/fpmExplorer/index.html#/topic/floorplanListReport/customHeaderListReport

**LANGUAGE**: N/A

**CODE**:
```text
Images (for reference):
- images/Custom_Content_in_List_Report_Header_in_Expand_Mode_51fe3b2.png
- images/Custom_Content_in_List_Report_Header_in_Collapsed_Mode_bd1a51e.png
```

fiori-elements-framework list-report extension-point custom-header manifest.json ui5 fragments


**TITLE**: Extension Point — React to Back-End Property Updates (watchProperty)

**INTRODUCTION**: Use the extensionAPI.watchProperty method in a controller extension to run custom logic when a specific OData V4 property is updated from the back end. Typical uses: display or hide messages, trigger UI updates, or perform side effects when property values change. Note: 1:n navigation properties are not supported.

**TAGS**: fiori-elements-framework, ODataV4, extensionAPI, watchProperty, controller-extension, messages

**STEP**: 1 — Scope and constraints

**DESCRIPTION**: Confirm applicability and limitations before implementing. This extension point is only applicable to SAP Fiori elements for OData V4. 1:n navigation properties are not supported by watchProperty.

**LANGUAGE**: Plain Text

**CODE**:
```text
Note: This topic is only applicable to SAP Fiori elements for OData V4.
1:n navigation properties are not supported.
```

**STEP**: 2 — Understand watchProperty callback parameters

**DESCRIPTION**: The watchProperty callback receives these arguments. Use them to determine what changed and whether it's the initial load:
- newValue: the new value of the property
- oldValue: the previous value of the property
- isInitial: true if the property value was retrieved from the back end for the first time
- context: the page context object (useful for retrieving additional context or data)

**LANGUAGE**: Plain Text

**CODE**:
```text
Callback parameters:
- newValue: the new value of the property
- oldValue: the previous value of the property
- isInitial: set to true if the property is retrieved from the back end for the first time
- context: the page context
```

**STEP**: 3 — Implement watchProperty in a controller extension (example)

**DESCRIPTION**: Place the watchProperty call inside the controller extension's onInit override. The sample below shows reacting to a boolean property "isHotCountry": when it becomes true, create and show an information message; otherwise hide messages. Use this.base.getExtensionAPI() to access extensionAPI methods showMessages and hideMessage.

**LANGUAGE**: JavaScript

**CODE**:
```js
sap.ui.define(
    ["sap/ui/core/mvc/ControllerExtension", "sap/ui/core/message/Message", "sap/ui/core/message/MessageType"],
    function (ControllerExtension, Message, MessageType) {
        "use strict";

        return ControllerExtension.extend("watchProperties-basic.ext.OPExtend", {
            override: {
                onInit: function () {
                    this.base.getExtensionAPI().watchProperty("isHotCountry", (newValue, oldValue, isInitial, context) => {
                        if (newValue === true) {
                            const messages = [
                                new Message({
                                    message: "Employee is in a hot country",
                                    type: MessageType.Information
                                })
                            ];
                            this.base.getExtensionAPI().showMessages(messages);
                        } else {
                            this.base.getExtensionAPI().hideMessage();
                        }
                    });
                }
            }
        });
    }
);
```

**STEP**: 4 — Recommended behaviors and tips

**DESCRIPTION**:
- Use isInitial to skip actions on the first back-end load if undesired.
- Keep callback logic lightweight to avoid UI delays.
- Use context to access related entity or page state if needed.
- For message handling, use extensionAPI.showMessages(messages) and extensionAPI.hideMessage() as shown.

**LANGUAGE**: Plain Text

**CODE**:
```text
Tips:
- Use isInitial to avoid executing logic on initial load when appropriate.
- Keep watch callback logic efficient.
- Use 'context' to access related data/state.
- Use showMessages(messages) and hideMessage() for message display control.
```

fiori-elements-framework ODataV4 extensionAPI watchProperty controller-extension messages


**TITLE**: Extension Points for Forms on the Object Page (OData V2 & V4)

**INTRODUCTION**: Practical, code-focused reference for extending forms on the Object Page in SAP Fiori elements. Contains manifest and fragment examples for OData V2 (SmartFormExtension) and OData V4 (custom form elements), property definitions for custom fields, usage of the UI model, and metadata-binding examples. Use only the Fiori elements extensionAPI for behavior and data integration.

**TAGS**: fiori-elements, object-page, forms, extension-points, odata-v2, odata-v4, manifest.json, xmlfragment, ui5, extensionAPI

**STEP**: 1 — Caution / Extension API rule

**DESCRIPTION**: Use app extensions only when manifest settings or annotations cannot produce the required behavior. Integrate app extension code using only the SAP Fiori elements extensionAPI. Do not access or manipulate internal controls, properties, models, or objects created by the framework — you are responsible for extension display and behavior after adding it.

**LANGUAGE**: Text

**CODE**:
```text
Caution:
- Use app extensions only when necessary.
- Use only the official extensionAPI of SAP Fiori elements.
- Do not access or manipulate internal framework controls, properties, or models.
```

**STEP**: 2 — OData V2: Add fields to an existing FieldGroup via SmartFormExtension in manifest

**DESCRIPTION**: Add new fields to an existing FieldGroup on the Object Page by registering a SmartFormExtension in the manifest. Place this manifest entry under the view key for the Object Page (e.g., "sap.suite.ui.generic.template.ObjectPage.view.Details"). SmartFormExtension supports only sap.ui.core.Fragment for className.

- Path context: sap.ui5 -> routing -> targets -> <YourObjectPageTarget> -> options -> settings -> controlConfiguration
- Key format: "SmartFormExtension|<EntityName>|<FieldGroupAnnotation>"

**LANGUAGE**: JSON

**CODE**:
```json
"sap.suite.ui.generic.template.ObjectPage.view.Details": {
    "SmartFormExtension|STTA_C_MP_Product|com.sap.vocabularies.UI.v1.FieldGroup::GeneralInformation": {
        "className": "sap.ui.core.Fragment",
        "fragmentName": "STTA_MP.ext.fragments.SmartFormGroupElement",
        "type": "XML"
    }
}
```

**STEP**: 3 — OData V4: Create an XML fragment for a custom form element (view extension)

**DESCRIPTION**: Implement an xmlfragment that defines the UI for the custom field. Save the fragment as e.g., CustomFormElement.fragment.xml and reference it as the template in manifest controlConfiguration entries.

**LANGUAGE**: XML

**CODE**:
```xml
<!-- CustomFormElement.fragment.xml -->
<core:FragmentDefinition xmlns:core="sap.ui.core" xmlns="sap.m">
    <Text id="customFieldFormSoldToPartyInputField" text="{SoldToParty}" />
</core:FragmentDefinition>
```

**STEP**: 4 — OData V4: Register view extensions in manifest.json via controlConfiguration

**DESCRIPTION**: Register custom fields under the controlConfiguration of the Object Page target in manifest.json. Each custom field needs a unique key, a template that points to the fragment, a label (i18n or metadata binding), and a position object specifying placement and anchor. Example shows two custom fields where the second is positioned after the first.

- Path context: sap.ui5 -> routing -> targets -> <YourObjectPageTarget> -> options -> settings -> controlConfiguration -> @com.sap.vocabularies.UI.v1.FieldGroup -> fields

**LANGUAGE**: JSON

**CODE**:
```json
"sap.ui5": {
    "routing": {
        "targets": {
            "SalesOrderManageObjectPage": {
                "options": {
                    "settings": {
                        "controlConfiguration": {
                            "@com.sap.vocabularies.UI.v1.FieldGroup": {
                                "fields": {
                                    "customFormElementAnchor": {
                                        "template": "ObjectPageStructure.ext.CustomField",
                                         "label": "{i18n>myFieldLabel1}",
                                         "position": {
                                             "placement": "After",
                                             "anchor": "DataField::SalesOrder"
                                         }
                                     },
                                     "customFormElementAnchor2": {
                                         "template": "ObjectPageStructure.ext.CustomField",
                                         "label": "{i18n>myFieldLabel2}",
                                         "position": {
                                             "placement": "After",
                                             "anchor": "customFormElementAnchor"
                                         }
                                     }
                                 }
                             }
                         }
                     }
                 }
             }
        }
    }
 }
```

**STEP**: 5 — Custom Field Properties (required for manifest controlConfiguration entries)

**DESCRIPTION**: Use these properties when declaring custom fields under a FieldGroup in controlConfiguration. Keys must be unique identifiers and can be referenced as anchors for placement.

**LANGUAGE**: Text / Specification

**CODE**:
```text
Properties of a Custom Field in a Form:
- key
  - Supported values: aA-zZ, 0-9, :, _, -
  - Description: Unique identifier used as reference/anchor by other fields.

- label
  - Supported values: any Unicode string
  - Description: Label shown next to the field (can use i18n or metadata binding).

- position
  - Description: Defines position relative to other fields.

- position.placement
  - Supported values: "After" | "Before"
  - Description: Placement relative to the anchor field.

- position.anchor
  - Supported values: "<key_of_column>"
  - Description: The key of another field used as the placement anchor.

- template
  - Description: Fragment name/path following Fragment.load syntax (the fragment implementing the UI).
```

**STEP**: 6 — Use the UI model in fragments to react to edit mode

**DESCRIPTION**: Bind fragment element properties to the ui model to react to mode changes (for example enable/disable behavior depending on editMode).

**LANGUAGE**: JSON / Binding Expression

**CODE**:
```json
"enabled=\"{= ${ui>/editMode} === 'Editable'}\""
```

**STEP**: 7 — Metadata binding for labels (alternative to i18n)

**DESCRIPTION**: Use metadata binding to derive the label from the OData meta model instead of i18n. Useful when the label exists in the service metadata.

**LANGUAGE**: JSON

**CODE**:
```json
"customFormElementAnchor3": {
    "template": "ObjectPageStructure.ext.CustomField",
  "label": "{metaModel>/SalesOrderManage/SoldToParty@com.sap.vocabularies.Common.v1.Label}",
  "position": {
    "placement": "After",
    "anchor": "customFormElementAnchor"
  }
}
```

**STEP**: 8 — Live example and further exploration

**DESCRIPTION**: Use the SAP Fiori development portal building block for form extensions to experiment with sample implementations and see live behavior.

**LANGUAGE**: URL

**CODE**:
```text
Live Example: https://ui5.sap.com/test-resources/sap/fe/core/fpmExplorer/index.html#/buildingBlocks/form/formCustom
```