Dynamic Cross-App Navigation in Fiori Elements: Navigate to Different Apps from the Same Column

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 press event
  • Call CrossApplicationNavigation.toExternal() with semantic object/action decided from row data