<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Demo</title>
<script src="bootConfig.js"></script>
<script src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js" id="sap-ui-bootstrap"></script>
</head>
<body class="sapUiBody" id="content">
</body>
</html>
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/m/MessageToast",
], function(Controller, MessageToast) {
"use strict";
const batchGroupId = "myUpdateGroupId";
return Controller.extend("demo.controller.Detail", {
onInit: function() {
const route = this.getOwnerComponent().getRouter().getRoute("masterDetail");
route.attachPatternMatched(this.onPatternMatched, this);
route.attachBeforeMatched(this.reset, this);
},
onPatternMatched: function(event) {
this.bindSelectedItem(event.getParameter("arguments").userName);
},
bindSelectedItem: function(userName) {
this.getView().bindElement({
path: `/People('${userName}')`,
parameters: {
$$updateGroupId: batchGroupId
},
events: {
dataRequested: () => this.byId("page").setBusy(true),
dataReceived: () => this.byId("page").setBusy(false),
},
});
},
onSubmitPress: function() {
if (this.getOwnerComponent().getModel().hasPendingChanges()) {
this.byId("page").setBusy(true);
this.refreshMasterList(batchGroupId);
this.submitBatch(batchGroupId).then(() => {
this.resetEditingStatus();
this.byId("page").setBusy(false);
MessageToast.show("User updated");
});
}
},
refreshMasterList: function(groupId) {
const bus = this.getOwnerComponent().getEventBus();
bus.publish("master", "refresh", groupId);
},
submitBatch: function(id) {
return this.getOwnerComponent().getModel().submitBatch(id);
},
onCancelPress: function() {
this.reset();
},
reset: function(event) {
this.getOwnerComponent().getModel().resetChanges(batchGroupId);
this.resetEditingStatus();
},
resetEditingStatus: function() {
const model = this.getOwnerComponent().getModel("detailViewModel");
model.setProperty("/editing", false);
}
});
});
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/Device"
], function(Controller, Device) {
"use strict";
return Controller.extend("demo.controller.Master", {
onInit: function() {
const bus = this.getOwnerComponent().getEventBus();
bus.subscribe("master", "refresh", this.shouldRefresh, this);
},
onItemPress: function(event) {
const item = event.getParameter("listItem");
this.navToDetailOf(item);
},
navToDetailOf: function(item) {
this.getOwnerComponent().getRouter().navTo("masterDetail", {
userName: item.getBindingContext().getProperty("UserName")
}, !Device.system.phone);
},
shouldRefresh: function(channelId, eventId, groupId) {
const listBinding = this.byId("masterList").getBinding("items");
this.refresh(listBinding, groupId);
},
refresh: function(binding, groupId) {
if (binding.hasPendingChanges()) {
// show message that there are some changes left
} else {
return binding.refresh(groupId);
}
},
});
});
<mvc:View
xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m"
displayBlock="true"
height="100%"
>
<SplitApp id="rootSplitContainer">
<masterPages>
<!-- will be added by Router -->
</masterPages>
<detailPages>
<!-- will be added by Router -->
</detailPages>
</SplitApp>
</mvc:View>
<mvc:View
xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m"
controllerName="demo.controller.Master"
>
<Page
title="Users"
backgroundDesign="List"
>
<List id="masterList"
busyIndicatorDelay="0"
mode="SingleSelectMaster"
growing="true"
items="{/People}"
itemPress=".onItemPress"
>
<StandardListItem
title="{FirstName}"
description="{LastName}"
type="Active"
/>
</List>
</Page>
</mvc:View>
<mvc:View
xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m"
>
<MessagePage
title="Demo"
text="Choose an Item from Master List"
description="Nothing to see here"
/>
</mvc:View>
<mvc:View
xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m"
xmlns:form="sap.ui.layout.form"
controllerName="demo.controller.Detail"
>
<Page id="page"
title="User: {UserName}"
floatingFooter="true"
showFooter="{detailViewModel>/editing}"
>
<headerContent>
<ToggleButton
icon="sap-icon://edit"
pressed="{detailViewModel>/editing}"
visible="{= !${detailViewModel>/editing}}"
/>
</headerContent>
<form:SimpleForm id="form"
layout="ResponsiveGridLayout"
editable="true"
>
<Label text="First Name"/>
<Input
value="{
path: 'FirstName',
type: 'sap.ui.model.odata.type.String',
constraints: {
nullable: false,
maxLength: 30
}
}"
editable="{detailViewModel>/editing}"
/>
<Label text="Last Name"/>
<Input
value="{
path: 'LastName',
type: 'sap.ui.model.odata.type.String',
constraints: {
nullable: false,
maxLength: 30
}
}"
editable="{detailViewModel>/editing}"
/>
</form:SimpleForm>
<footer>
<OverflowToolbar>
<ToolbarSpacer/>
<Button id="submitBtn"
text="Submit"
type="Emphasized"
press=".onSubmitPress"
/>
<Button id="cancelBtn"
text="Cancel"
press=".onCancelPress"
/>
</OverflowToolbar>
</footer>
</Page>
</mvc:View>
{
"_version": "1.10.0",
"start_url": "index.html",
"sap.app": {
"id": "demo",
"type": "application",
"title": "Demo",
"description": "Sample Code",
"applicationVersion": {
"version": "1.0.0"
},
"dataSources": {
"myDataSource": {
"uri": "https://cors-anywhere.herokuapp.com/https://services.odata.org/TripPinRESTierService/(S(0m1hkqy5kzmpz1xxhqwjihdk))/",
"type": "OData",
"settings": {
"odataVersion": "4.0"
}
}
}
},
"sap.ui": {
"technology": "UI5",
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": true
},
"supportedThemes": [
"sap_belize_hcw",
"sap_belize_hcb",
"sap_belize",
"sap_belize_plus"
]
},
"sap.ui5": {
"handleValidation": true,
"dependencies": {
"minUI5Version": "1.54.0",
"libs": {
"sap.ui.core": {},
"sap.m": {},
"sap.ui.layout": {}
}
},
"contentDensities": {
"compact": true,
"cozy": true
},
"resources": {
"js": [
],
"css": [
]
},
"models": {
"": {
"dataSource": "myDataSource",
"settings": {
"autoExpandSelect": true,
"operationMode": "Server",
"synchronizationMode": "None"
},
"preload": true
},
"detailViewModel": {
"type": "sap.ui.model.json.JSONModel"
}
},
"rootView": {
"viewName": "demo.view.Root",
"id": "rootView",
"type": "XML",
"async": true,
"height": "100%",
"displayBlock": true
},
"routing": {
"routes": [{
"name": "master",
"pattern": "",
"target": ["emptyDetail", "master"]
}, {
"name": "masterDetail",
"pattern": "user/{userName}",
"target": ["detail", "master"]
}],
"targets": {
"master": {
"viewId": "masterView",
"viewName": "Master",
"controlAggregation": "masterPages"
},
"detail": {
"viewId": "detailView",
"viewName": "Detail",
"controlAggregation": "detailPages",
"viewLevel": 1,
"transition": "show"
},
"emptyDetail": {
"viewId": "emptyDetailView",
"viewName": "EmptyDetail",
"controlAggregation": "detailPages"
}
},
"config": {
"routerClass": "sap.m.routing.Router",
"async": true,
"viewType": "XML",
"viewPath": "demo.view",
"controlId": "rootSplitContainer"
}
}
}
}
sap.ui.define([
"sap/ui/core/UIComponent",
], function(UIComponent) {
"use strict";
return UIComponent.extend("demo.Component", {
metadata: {
manifest: "json"
},
init: function() {
UIComponent.prototype.init.apply(this, arguments);
this.getModel("detailViewModel").setProperty("/editing", false);
this.getRouter().initialize();
window.onbeforeunload = () => this.getModel().hasPendingChanges() || null;
},
});
});
this["sap-ui-config"] = {
libs: "sap.ui.core, sap.m, sap.ui.layout",
preload: "async",
theme: "sap_belize",
compatVersion: "edge",
resourceRoots: {
"demo": "./"
},
onInit: () => sap.ui.component({
name: "demo",
manifest: true,
}).then(createdComponent => sap.ui.require([
"sap/m/Shell",
"sap/ui/core/ComponentContainer",
], (Shell, ComponentContainer) => new Shell({
app: new ComponentContainer({
component: createdComponent,
height: "100%",
}),
}).placeAt("content"))),
"xx-componentPreload": "off",
"xx-waitForTheme": true,
"xx-async": true,
"xx-xml-processing": "sequential",
};