Introduction
In real-world business scenarios, applications often need to handle the same type of field with different meanings depending on the data context.
For example:
- In finance, an account assignment might be a Cost Center, WBS Element, or Internal Order.
- In procurement, a reference document could point to a Purchase Order, Contract, or Sales Order.
- In logistics, a location could be a Plant, Storage Location, or Vendor Site.
On the UI, these values are often displayed in a single column of a table. Users expect that:
Clicking on the value should take them to the appropriate app for that type of object.
The challenge?
Fiori Elements supports intent-based navigation via CDS annotations, and you can expose multiple actions for a field (for example, Display and History). However, those intent mappings are defined at design time and apply uniformly to the field. When a column contains different business object types (such as Cost Center, WBS Element or Internal Order), annotations alone can’t route each row to a different semantic object at runtime — for that you need a small front-end extension that inspects the row and invokes the correct intent dynamically.
In this blog, we discuss such a requirement and explain how to solve it using a controller extension that inspects the row’s data and dynamically triggers the right navigation target
Business Requirement
In our procurement application, the Reference Document column of the Items table in the Object Page can display different types of objects:
- Purchase Order
- Contract
- Sales Order
When the user clicks the value, the app should navigate to:
- The PO Display App if the value is a Purchase Order
- The Contract Display App if the value is a Contract
- The Sales Order Display App if the value is a Sales Order
Problem Analysis
By default, Fiori Elements navigation is driven by:
@UI.lineItem.type: #WITH_URL- FLP semantic object/action defined in target mapping
The issue:
- A single column → semantic object/action → always navigates to app, relevant for one data context like Purchase Order, Invoice, etc.
- It cannot dynamically switch based on the type of data in the row.
- Example: clicking Purchase Order still took users to the Sales order App.
Solution Approach
We solved this in two steps:
1. Annotation for link rendering
Mark the column as a link so that Fiori Elements renders it as clickable.
@UI.lineItem: [
{
position: 20,
label: 'Reference Document',
type: #WITH_URL,
url: reference_doc, // dummy placeholder
value: reference_doc
}
]
reference_doc;
2. Controller extension for dynamic navigation
Extend the Object Page controller to override the link press and decide the navigation target at runtime.
sap.ui.define([
"sap/ui/core/mvc/ControllerExtension"
], function (ControllerExtension) {
"use strict";
return ControllerExtension.extend("my.namespace.ext.controller.ObjectPageExt", {
override: {
routing: {
onAfterBinding: function () {
this._makeLinksDynamic();
}
}
},
_makeLinksDynamic: function () {
const oTable = this.base.getView().byId("fe::table::ZC_ProcurementItem::LineItem");
if (!oTable) return;
oTable.attachEventOnce("updateFinished", function () {
oTable.getItems().forEach(function (oItem) {
// Adjust index for the Reference Document column
const oCell = oItem.getCells()[0];
if (oCell && oCell.getAggregation) {
const oDisplay = oCell.getAggregation("display");
if (oDisplay && oDisplay.isA("sap.m.Link")) {
oDisplay.detachPress();
oDisplay.attachPress(this._onLinkPress.bind(this));
}
}
}.bind(this));
}.bind(this));
},
_onLinkPress: function (oEvent) {
const oContext = oEvent.getSource().getBindingContext();
const oData = oContext.getObject();
let sSemanticObject, sAction;
switch (oData.RefDocType) {
case "PO":
sSemanticObject = "PurchaseOrder";
sAction = "display";
break;
case "CTR":
sSemanticObject = "Contract";
sAction = "display";
break;
case "SO":
sSemanticObject = "SalesOrder";
sAction = "display";
break;
default:
return;
}
const oCrossAppNav = sap.ushell && sap.ushell.Container.getService("CrossApplicationNavigation");
if (oCrossAppNav) {
oCrossAppNav.toExternal({
target: { semanticObject: sSemanticObject, action: sAction },
params: { ID: oData.ReferenceDoc } // pass the correct key
});
}
}
});
});Key Takeaways
Fiori Elements annotations can make a field look like a link, but navigation is static.
For dynamic cross-app navigation per row, you need a controller extension.
The key trick is:
- Find the SmartToggle → display aggregation → sap.m.Link
- Override its
pressevent - Call
CrossApplicationNavigation.toExternal()with semantic object/action decided from row data