<!DOCTYPE html>
<html style="height: 100%;">
<head>
<meta charset="utf-8" />
<title>Demo</title>
<script id="sap-ui-bootstrap"
src="https://sdk.openui5.org/nightly/resources/sap-ui-core.js"
data-sap-ui-on-init="module:sap/ui/core/ComponentSupport"
data-sap-ui-async="true"
data-sap-ui-compat-version="edge"
data-sap-ui-resource-roots='{
"demo": "./",
"demo.shared": "https://run.plnkr.co/plunks/8aLaog6TMWiYno8Z/"
}'
data-sap-ui-xx-component-preload="off"
data-sap-ui-xx-wait-for-theme="init"
></script>
</head>
<body id="content" class="sapUiBody">
<div style="height: 100%;"
data-sap-ui-component
data-id="rootComponentContainer"
data-name="demo"
data-height="100%"
data-settings='{"id": "rootComponent"}'
></div>
</body>
</html>
sap.ui.define([
"sap/ui/core/UIComponent",
"sap/ui/Device",
"sap/ui/core/EventBus",
], function(UIComponent, Device) {
"use strict";
return UIComponent.extend("demo.Component", {
metadata: {
manifest: "json",
interfaces: [
"sap.ui.core.IAsyncContentCreation",
],
},
init: function() {
UIComponent.prototype.init.apply(this, arguments);
this.getModel("odata").metadataLoaded(true).catch(() => sap.ui.require([
"demo/shared/corsPromptMessage"
]));
this.getRouter().initialize();
this.getEventBus().subscribe("detail", "loaded", this.detailLoaded, this);
},
detailLoaded: function() {
this.getRootControl().byId("rootSplitContainer").hideMaster();
},
});
});
{
"_version": "1.16.0",
"sap.app": {
"id": "demo",
"type": "component",
"i18n": "",
"title": "Demo",
"description": "Sample Code",
"applicationVersion": {
"version": "1.0.0"
},
"dataSources": {
"odataDemo": {
"uri": "https://cors-anywhere.herokuapp.com/https://services.odata.org/V2/Northwind/Northwind.svc/",
"type": "OData",
"settings": {
"odataVersion": "2.0"
}
}
}
},
"sap.ui": {
"technology": "UI5",
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": true
}
},
"sap.ui5": {
"autoPrefixId": true,
"dependencies": {
"minUI5Version": "1.73.1",
"libs": {
"sap.ui.core": {},
"sap.m": {}
}
},
"models": {
"odata": {
"dataSource": "odataDemo",
"settings": {
"tokenHandling": false,
"preliminaryContext": true,
"canonicalRequest": true
},
"preload": true
}
},
"contentDensities": {
"compact": true,
"cozy": true
},
"rootView": {
"viewName": "demo.view.Root",
"id": "rootView",
"type": "XML",
"async": true
},
"routing": {
"routes": {
"master": {
"pattern": "",
"name": "master",
"target": ["detail", "master"]
},
"masterDetail": {
"pattern": "items/{itemId}",
"name": "masterDetail",
"target": ["master", "detail"]
}
},
"targets": {
"master": {
"viewId": "masterView",
"viewName": "Master",
"controlAggregation": "masterPages",
"viewLevel": 1
},
"detail": {
"viewId": "detailView",
"viewName": "Detail",
"controlAggregation": "detailPages",
"transition": "baseSlide",
"viewLevel": 2
}
},
"config": {
"routerClass": "sap.m.routing.Router",
"async": true,
"viewType": "XML",
"viewPath": "demo.view",
"controlId": "rootSplitContainer"
}
}
}
}
<mvc:View controllerName="demo.controller.Detail"
xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m"
xmlns:core="sap.ui.core"
core:require="{ EdmDateTime: 'sap/ui/model/odata/type/DateTime' }"
>
<Page id="page"
class="sapUiNoContentPadding"
busyIndicatorDelay="0"
contentOnlyBusy="true"
title="Product: {odata>ProductName}"
floatingFooter="true"
showNavButton="{:= !${device>/system/desktop}}"
navButtonPress=".navBack($controller.getOwnerComponent().getRouter())"
>
<Table
busyIndicatorDelay="0"
sticky="ColumnHeaders"
growing="true"
growingScrollToLoad="true"
updateFinished=".onBindSuccess"
items="{
path: 'odata>Order_Details',
templateShareable: false
}"
>
<columns>
<Column width="25%">
<Text text="Order ID" />
</Column>
<Column width="25%"
popinDisplay="WithoutHeader"
demandPopin="true"
minScreenWidth="Tablet"
hAlign="Right"
>
<Text text="Order Date" />
</Column>
<Column width="auto">
<Text text="Customer" />
</Column>
</columns>
<ColumnListItem>
<Text text="{odata>Order/OrderID}"/>
<Text text="{
path: 'odata>Order/OrderDate',
type: 'EdmDateTime',
constraints: {
displayFormat: 'Date'
}
}"/>
<Text text="{odata>Order/Customer/CompanyName}"/>
</ColumnListItem>
</Table>
<footer>
<!-- ... -->
</footer>
</Page>
</mvc:View>
<mvc:View controllerName="demo.controller.Master"
xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m">
<Page title="Products from UK"
class="sapUiResponsivePadding--header"
backgroundDesign="List"
>
<List id="masterList"
busyIndicatorDelay="0"
growing="true"
updateFinished=".displayDetailsOfFirstItem($event.getSource())"
items="{
path: 'odata>/Products',
templateShareable: false,
parameters: {
expand: 'Category, Supplier',
select: 'ProductID, ProductName, UnitsInStock, Category/CategoryName, Supplier/Country'
},
sorter: [
{
path: 'Category/CategoryName',
group: true
},
{
path: 'ProductName'
}
],
filters: [
{
path: 'Supplier/Country',
operator: 'EQ',
value1: 'UK'
}
]
}"
>
<ObjectListItem type="Active"
title="{odata>ProductName}"
number="x {odata>UnitsInStock}"
press=".navToDetailOf(${odata>ProductID})"
/>
</List>
</Page>
</mvc:View>
<mvc:View xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m" height="100%">
<SplitApp id="rootSplitContainer">
<masterPages>
<!-- will be placed by the routing -->
</masterPages>
<detailPages>
<!-- will be placed by the routing -->
</detailPages>
</SplitApp>
</mvc:View>
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/core/routing/History",
], function(Controller, History) {
"use strict";
return Controller.extend("demo.controller.Detail", {
onInit: function() {
const router = this.getOwnerComponent().getRouter();
const route = router.getRoute("masterDetail");
route.attachPatternMatched(this.onPatternMatched, this);
},
onPatternMatched: async function(event) {
const model = this.getOwnerComponent().getModel("odata");
const { itemId } = event.getParameter("arguments");
const itemIdDecoded = window.decodeURIComponent(itemId);
await model.metadataLoaded();
this.bindSelectedItem(itemIdDecoded);
},
bindSelectedItem: function(key1) {
const model = this.getOwnerComponent().getModel("odata");
const key = model.createKey("Products", {
ProductID: key1, // creating key(s) dynamically.
// See https://stackoverflow.com/a/47016070/5846045
});
// model.invalidateEntry(key); for https://stackoverflow.com/a/59398119/5846045
this.getView().bindObject({
path: "odata>/" + key,
parameters: {
expand: [
"Order_Details/Order/Customer",
].join(",")
},
});
},
onBindSuccess: function() {
const eventBus = this.getOwnerComponent().getEventBus();
eventBus.publish("detail", "loaded");
},
// Only for mobile case
navBack: router => History.getInstance().getPreviousHash() !== undefined
? window.history.go(-1)
: router.navTo("master", {}, true),
});
});
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/Device",
], function(Controller, Device) {
"use strict";
return Controller.extend("demo.controller.Master", {
navToDetailOf: function(itemId) {
const router = this.getOwnerComponent().getRouter();
const itemIdEncoded = window.encodeURIComponent(itemId);
router.navTo("masterDetail", {
itemId: itemIdEncoded
}, !Device.system.phone);
},
});
});