Skip to Content

[SAPUI5] Problem get data with an ID

Good morning, everyone,

I am new in the world of SAPUI5 and I have a problem, I can't get the orders for a given employee. I have a list here with the employees. When I click on one, I can see the details of its information.

I would also like to display in a table the list of orders he has handled.(Here for the moment and to train I get all the list of orders). Indeed, I don't understand how to use the "EmployeeID" to do a search like "https://services.odata.org/V3/Northwind/Northwind.svc/Employees(1)/Orders", can someone explain to me how it works? It is necessary to go through the controller and not through the "path" in the table present in the Object.view.xml?

Thank you in advance for your help.

Here are the sources:

Worklist.view.xml

<mvc:View
controllerName="northwind.TestTableWithOData.controller.Worklist"
xmlns="sap.m"
xmlns:mvc="sap.ui.core.mvc"
xmlns:semantic="sap.f.semantic"> <semantic:SemanticPage
id="page"
headerPinnable="false"
toggleHeaderOnTitleClick="false"> <semantic:titleHeading>
<Title
text="List of {i18n>worklistTitle}"
level="H2"/>
</semantic:titleHeading> <semantic:content>
<Table
id="table"
width="auto"
items="{
path: '/Employees',
sorter: {
path: 'FirstName',
descending: false
}
}"
noDataText="{worklistView>/tableNoDataText}"
busyIndicatorDelay="{worklistView>/tableBusyDelay}"
growing="true"
growingScrollToLoad="true"
updateFinished=".onUpdateFinished"> <headerToolbar>
<OverflowToolbar>
<Title
id="tableHeader"
text="{worklistView>/worklistTableTitle}"
level="H3"/>
<ToolbarSpacer />
<SearchField
id="searchField"
tooltip="{i18n>worklistSearchTooltip}"
search=".onSearch">
<layoutData>
<OverflowToolbarLayoutData
maxWidth="200px"
priority="NeverOverflow"/>
</layoutData>
</SearchField>
</OverflowToolbar>
</headerToolbar> <columns>
<Column id="nameColumn">
<Text text="{i18n>tableNameColumnTitle}" id="nameColumnTitle"/>
</Column>
<Column id="lastNameColumn">
<Text text="{i18n>tableLastNameColumnTitle}"/>
</Column>
<Column id="addressColumn">
<Text text="{i18n>tableAddressColumnTitle}"/>
</Column>
<Column id="titleColumn">
<Text text="{i18n>tableTitleColumnTitle}"/>
</Column>
</columns> <items>
<ColumnListItem
type="Navigation"
press=".onPress">
<cells>
<ObjectIdentifier
title="{FirstName}"/>
</cells>
<cells>
<ObjectIdentifier
title="{LastName}"/>
</cells>
<cells>
<ObjectIdentifier
title="{Address}"/>
</cells>
<cells>
<ObjectIdentifier
title="{Title}"/>
</cells>
</ColumnListItem>
</items>
</Table>
</semantic:content> <semantic:sendEmailAction>
<semantic:SendEmailAction id="shareEmail" press=".onShareEmailPress"/>
</semantic:sendEmailAction>
</semantic:SemanticPage>< /mvc:View>

Worklist.controller.js

sap.ui.define([
"./BaseController",
"sap/ui/model/json/JSONModel",
"../model/formatter",
"sap/ui/model/Filter",
"sap/ui/model/FilterOperator"
], function (BaseController, JSONModel, formatter, Filter, FilterOperator) {
"use strict";

return BaseController.extend("northwind.TestTableWithOData.controller.Worklist", { formatter: formatter, /* =========================================================== */
/* lifecycle methods */
/* =========================================================== */ /**
* Called when the worklist controller is instantiated.
* @public
*/
onInit : function () {
var oViewModel,
iOriginalBusyDelay,
oTable = this.byId("table"); // Put down worklist table's original value for busy indicator delay,
// so it can be restored later on. Busy handling on the table is
// taken care of by the table itself.
iOriginalBusyDelay = oTable.getBusyIndicatorDelay();
// keeps the search state
this._aTableSearchState = []; // Model used to manipulate control states
oViewModel = new JSONModel({
worklistTableTitle : this.getResourceBundle().getText("worklistTableTitle"),
shareOnJamTitle: this.getResourceBundle().getText("worklistTitle"),
shareSendEmailSubject: this.getResourceBundle().getText("shareSendEmailWorklistSubject"),
shareSendEmailMessage: this.getResourceBundle().getText("shareSendEmailWorklistMessage", [location.href]),
tableNoDataText : this.getResourceBundle().getText("tableNoDataText"),
tableBusyDelay : 0
});
this.setModel(oViewModel, "worklistView"); // Make sure, busy indication is showing immediately so there is no
// break after the busy indication for loading the view's meta data is
// ended (see promise 'oWhenMetadataIsLoaded' in AppController)
oTable.attachEventOnce("updateFinished", function(){
// Restore original busy indicator delay for worklist's table
oViewModel.setProperty("/tableBusyDelay", iOriginalBusyDelay);
});
}, /* =========================================================== */
/* event handlers */
/* =========================================================== */ /**
* Triggered by the table's 'updateFinished' event: after new table
* data is available, this handler method updates the table counter.
* This should only happen if the update was successful, which is
* why this handler is attached to 'updateFinished' and not to the
* table's list binding's 'dataReceived' method.
* @param {sap.ui.base.Event} oEvent the update finished event
* @public
*/
onUpdateFinished : function (oEvent) {
// update the worklist's object counter after the table update
var sTitle,
oTable = oEvent.getSource(),
iTotalItems = oEvent.getParameter("total");
// only update the counter if the length is final and
// the table is not empty
if (iTotalItems && oTable.getBinding("items").isLengthFinal()) {
sTitle = this.getResourceBundle().getText("worklistTableTitleCount", [iTotalItems]);
} else {
sTitle = this.getResourceBundle().getText("worklistTableTitle");
}
this.getModel("worklistView").setProperty("/worklistTableTitle", sTitle);
}, /**
* Event handler when a table item gets pressed
* @param {sap.ui.base.Event} oEvent the table selectionChange event
* @public
*/
onPress : function (oEvent) {
// The source is the list item that got pressed
this._showObject(oEvent.getSource());
}, /**
* Event handler for navigating back.
* We navigate back in the browser history
* @public
*/
onNavBack : function() {
// eslint-disable-next-line sap-no-history-manipulation
history.go(-1);
},
onSearch : function (oEvent) {
if (oEvent.getParameters().refreshButtonPressed) {
// Search field's 'refresh' button has been pressed.
// This is visible if you select any master list item.
// In this case no new search is triggered, we only
// refresh the list binding.
this.onRefresh();
} else {
var aTableSearchState = [];
var sQuery = oEvent.getParameter("query"); if (sQuery && sQuery.length > 0) {
aTableSearchState = [new Filter("FirstName", FilterOperator.Contains, sQuery)];
}
this._applySearch(aTableSearchState);
} }, /**
* Event handler for refresh event. Keeps filter, sort
* and group settings and refreshes the list binding.
* @public
*/
onRefresh : function () {
var oTable = this.byId("table");
oTable.getBinding("items").refresh();
}, /* =========================================================== */
/* internal methods */
/* =========================================================== */ /**
* Shows the selected item on the object page
* On phones a additional history entry is created
* @param {sap.m.ObjectListItem} oItem selected Item
* @private
*/
_showObject : function (oItem) {
this.getRouter().navTo("object", {
objectId: oItem.getBindingContext().getProperty("EmployeeID")
});
}, /**
* Internal helper method to apply both filter and search state together on the list binding
* @param {sap.ui.model.Filter[]} aTableSearchState An array of filters for the search
* @private
*/
_applySearch: function(aTableSearchState) {
var oTable = this.byId("table"),
oViewModel = this.getModel("worklistView");
oTable.getBinding("items").filter(aTableSearchState, "Application");
// changes the noDataText of the list in case there are no filter results
if (aTableSearchState.length !== 0) {
oViewModel.setProperty("/tableNoDataText", this.getResourceBundle().getText("worklistNoDataWithSearchText"));
}
} });
});

Object.view.xml

<mvc:View
controllerName="northwind.TestTableWithOData.controller.Object"
xmlns="sap.m"
xmlns:mvc="sap.ui.core.mvc"
xmlns:semantic="sap.f.semantic"
xmlns:form="sap.ui.layout.form"
xmlns:l="sap.ui.layout">

<semantic:SemanticPage
id="page"
headerPinnable="false"
toggleHeaderOnTitleClick="false"
busy="{objectView>/busy}"
busyIndicatorDelay="{objectView>/delay}"> <semantic:titleHeading>
<Title
text="{FirstName}"
level="H2"/>
</semantic:titleHeading> <semantic:headerContent>
<ObjectNumber
/>
</semantic:headerContent>

<semantic:content>
<ObjectHeader
id="objectHeader"
intro="{EmployeeID}"
title="{FirstName}">
</ObjectHeader>
<l:VerticalLayout width="100%">
<Panel

headerText="{FirstName} {LastName} {i18n>EmployeeTabTitle}">
<content>
<form:SimpleForm
minWidth="1024"
maxContainerCols="2"
editable="false"
layout="ResponsiveGridLayout"
labelSpanL="3"
labelSpanM="3"
emptySpanL="4"
emptySpanM="4"
columnsL="1"
columnsM="1">
<form:content>
<Label text="{i18n>labelFirstNameEmployee}"/>
<Text text="{FirstName}"/>
<Label text="{i18n>labelLastNameEmployee}"/>
<Text text="{LastName}"/>
<Label text="{i18n>labelAddressEmployee}"/>
<Text text="{Address}"/>
<Label text="{i18n>labelCityEmployee}"/>
<Text text="{City}"/>
<Label text="{i18n>labelRegionEmployee}"/>
<Text text="{Region}"/>
<Label text="{i18n>labelPostalCodeEmployee}"/>
<Text text="{PostalCode}"/>
<Label text="{i18n>labelCountryEmployee}"/>
<Text text="{Country}"/>
<Label text="{i18n>labelTitleEmployee}"/>
<Text text="{Title}"/>
<Label text="{i18n>labelHireDateEmployee}"/>
<Text text="{HireDate}"/>
</form:content>
</form:SimpleForm>
</content>
</Panel>

<Table
id="tableOrder"
width="auto"
items="{
path: '/Orders',
sorter: {
path: 'OrderDate',
descending: false
},
parameters: {
expand: 'Shipper, Customer'
}
}"
noDataText="{worklistView>/tableNoDataText}"
busyIndicatorDelay="{worklistView>/tableBusyDelay}"
growing="true"
growingScrollToLoad="true"
updateFinished=".onUpdateFinished">

<headerToolbar>
<OverflowToolbar>
<Title
id="tableHeader"
text="{worklistView>/worklistTableTitle}"
level="H3"/>
<ToolbarSpacer />
<SearchField
id="searchField"
tooltip="{i18n>worklistSearchTooltip}"
search=".onSearch">
<layoutData>
<OverflowToolbarLayoutData
maxWidth="200px"
priority="NeverOverflow"/>
</layoutData>
</SearchField>
</OverflowToolbar>
</headerToolbar>

<columns>
<Column id="orderDateColumn">
<Text text="{i18n>tableOrderDateColumnTitle}"/>
</Column>
<Column id="shipperColumn">
<Text text="{i18n>tableShipperColumnTitle}"/>
</Column>
<Column id="customerNameColumn">
<Text text="{i18n>tableCustomerNameColumnTitle}"/>
</Column>
<Column id="customerCompanyNameColumn">
<Text text="{i18n>tableCustomerCompanyNameColumnTitle}"/>
</Column>
</columns>

<items>
<ColumnListItem
type="Navigation"
press=".onPress">
<cells>
<ObjectIdentifier
title="{OrderDate}"/>

<ObjectIdentifier
title="{Shipper/CompanyName}"/>

<ObjectIdentifier
title="{Customer/ContactName}"/>

<ObjectIdentifier
title="{Customer/CompanyName}"/>

</cells>
</ColumnListItem>
</items>
</Table>

</l:VerticalLayout> </semantic:content>

<semantic:sendEmailAction>
<semantic:SendEmailAction id="shareEmail" press=".onShareEmailPress"/>
</semantic:sendEmailAction>
</semantic:SemanticPage>< /mvc:View>

Object.controller.js

sap.ui.define([
"./BaseController",
"sap/ui/model/json/JSONModel",
"sap/ui/core/routing/History",
"../model/formatter",
"sap/m/MessageToast"
], function (BaseController, JSONModel, History, formatter, MessageToast) {
"use strict"; return BaseController.extend("northwind.TestTableWithOData.controller.Object", { formatter: formatter, /* =========================================================== */
/* lifecycle methods */
/* =========================================================== */ /**
* Called when the worklist controller is instantiated.
* @public
*/
onInit : function () {
// Model used to manipulate control states. The chosen values make sure,
// detail page is busy indication immediately so there is no break in
// between the busy indication for loading the view's meta data
var iOriginalBusyDelay,
oViewModel = new JSONModel({
busy : true,
delay : 0
}); this.getRouter().getRoute("object").attachPatternMatched(this._onObjectMatched, this); // Store original busy indicator delay, so it can be restored later on
iOriginalBusyDelay = this.getView().getBusyIndicatorDelay();
this.setModel(oViewModel, "objectView");
this.getOwnerComponent().getModel().metadataLoaded().then(function () {
// Restore original busy indicator delay for the object view
oViewModel.setProperty("/delay", iOriginalBusyDelay);
}
);
}, /* =========================================================== */
/* event handlers */
/* =========================================================== */
/**
* Event handler for navigating back.
* It there is a history entry we go one step back in the browser history
* If not, it will replace the current entry of the browser history with the worklist route.
* @public
*/
onNavBack : function() {
var sPreviousHash = History.getInstance().getPreviousHash(); if (sPreviousHash !== undefined) {
history.go(-1);
} else {
this.getRouter().navTo("worklist", {}, true);
}
}, /* =========================================================== */
/* internal methods */
/* =========================================================== */ /**
* Binds the view to the object path.
* @function
* @param {sap.ui.base.Event} oEvent pattern match event in route 'object'
* @private
*/
_onObjectMatched : function (oEvent) {
var sObjectId = oEvent.getParameter("arguments").objectId;
this.getModel().metadataLoaded().then( function() {
var sObjectPath = this.getModel().createKey("Employees", {
EmployeeID : sObjectId
});
this._bindView("/" + sObjectPath);
}.bind(this));
}, /**
* Binds the view to the object path.
* @function
* @param {string} sObjectPath path to the object to be bound
* @private
*/
_bindView : function (sObjectPath) {
var oViewModel = this.getModel("objectView"),
oDataModel = this.getModel(); this.getView().bindElement({
path: sObjectPath,
parameters: {
expand: "Orders"
},
events: {
change: this._onBindingChange.bind(this),
dataRequested: function () {
oDataModel.metadataLoaded().then(function () {
// Busy indicator on view should only be set if metadata is loaded,
// otherwise there may be two busy indications next to each other on the
// screen. This happens because route matched handler already calls '_bindView'
// while metadata is loaded.
oViewModel.setProperty("/busy", true);
});
},
dataReceived: function () {
oViewModel.setProperty("/busy", false);
}
}
});
MessageToast.show("View employee informations.");
}, _onBindingChange : function () {
var oView = this.getView(),
oViewModel = this.getModel("objectView"),
oElementBinding = oView.getElementBinding(); // No data for the binding
if (!oElementBinding.getBoundContext()) {
this.getRouter().getTargets().display("objectNotFound");
return;
} var oResourceBundle = this.getResourceBundle(),
oObject = oView.getBindingContext().getObject(),
sObjectId = oObject.EmployeeID,
sObjectName = oObject.FirstName; oViewModel.setProperty("/busy", false); oViewModel.setProperty("/shareSendEmailSubject",
oResourceBundle.getText("shareSendEmailObjectSubject", [sObjectId]));
oViewModel.setProperty("/shareSendEmailMessage",
oResourceBundle.getText("shareSendEmailObjectMessage", [sObjectName, sObjectId, location.href]));
} }); });

Add a comment
10|10000 characters needed characters exceeded

Assigned Tags

Related questions

1 Answer

  • Best Answer
    Posted on Oct 23, 2019 at 05:00 AM

    Hi Arnaud Rmks,

    You need to put the code in the code block, now it is totally unreadable.

    You can see in the object page controller element binding is done to the view with Employee object. So now you placed a table in the object view and you want to trigger the navigation to the orders then you shouldn't use "/Orders" - this is for ORders entityset, this will fetch all the orders.

    So what you need is to trigger the navigation property for the employee from the table. So mention the navigation property name, which is same as entitysetname in our case "Orders" but don't mention "/" that's it.

    So it should be items = "Orders"

    BR,

    Mahesh

    Add a comment
    10|10000 characters needed characters exceeded