I have an application which is working fine but has a slight problem, oData in certain cases are not ready when the first view is loaded. The app uses 2 data models, both of them declared in manifest.json, one anonymous for the main work and another one named "f4" for handling of some entities used in certain formatters and dropdowns. Data for the latter model are getting loaded via a series of read operations in the init function of the root view. Leaving aside the issue mentioned in the beginning, everything else works.
Thanks to some expert advice here, found the cause of my problem. Router gets initialized before loading of data, so I decided to move the read ops from the root view to component.js.
Here comes the problem. Model is known to the app but seems to be empty from data. I know that data are getting loaded because I debugged the application and observed the app passing from all the read success functions before successfully initializing the router. Read in another post that doing this in onInit isn't the best possible practice, so I moved again functionality from the onInit to onAfterRendering function as advised but results are still the same, no data.
So the question is: How can I access an oData model, get the required entries and made them known to the app BEFORE router initialization?
Component.js
sap.ui.define([
"sap/ui/core/UIComponent",
"sap/ui/Device",
"kristal/apps/agreements/model/models",
"kristal/apps/agreements/controller/ErrorHandler"
], function (UIComponent, Device, models, ErrorHandler) {
"use strict";
// Promise vars
var oModelTypeDataDeferred = jQuery.Deferred();
var oModelStatusDataDeferred = jQuery.Deferred();
var oModelActionTypeDataDeferred = jQuery.Deferred();
var oModelRoleDataDeferred = jQuery.Deferred();
var oModelRefDataDeferred = jQuery.Deferred();
var oModelExtOrgDataDeferred = jQuery.Deferred();
var oModelInvolvementDataDeferred = jQuery.Deferred();
return UIComponent.extend("kristal.apps.agreements.Component", {
metadata : {
manifest: "json"
},
/**
* The component is initialized by UI5 automatically during the startup of the app and calls the init method once.
* In this function, the FLP and device models are set and the router is initialized.
* @public
* @override
*/
init : function () {
// call the base component's init function
UIComponent.prototype.init.apply(this, arguments);
// initialize the error handler with the component
this._oErrorHandler = new ErrorHandler(this);
// set the device model
this.setModel(models.createDeviceModel(), "device");
// set the FLP model
this.setModel(models.createFLPModel(), "FLP");
// Initialize additional data - UITGKA
var oModel = this.getModel();
var sPath = "/Agreement_TypesSet";
oModel.read(sPath, {
success: function(oData, oResponse) {
oModelTypeDataDeferred.resolve();
},
error: function(oError) {
jQuery.sap.log.error("Error", oError);
}
});
sPath = "/Agreement_StatusesSet";
oModel.read(sPath, {
success: function(oData, oResponse) {
oModelStatusDataDeferred.resolve();
},
error: function(oError) {
jQuery.sap.log.error("Error", oError);
}
});
sPath = "/Action_TypesSet";
oModel.read(sPath, {
success: function(oData, oResponse) {
oModelActionTypeDataDeferred.resolve();
},
error: function(oError) {
jQuery.sap.log.error("Error", oError);
}
});
sPath = "/Role_TypesSet";
oModel.read(sPath, {
success: function(oData, oResponse) {
oModelRoleDataDeferred.resolve();
},
error: function(oError) {
jQuery.sap.log.error("Error", oError);
}
});
sPath = "/Reference_TypesSet";
oModel.read(sPath, {
success: function(oData, oResponse) {
oModelRefDataDeferred.resolve();
},
error: function(oError) {
jQuery.sap.log.error("Error", oError);
}
});
sPath = "/External_OrganizationsSet";
oModel.read(sPath, {
success: function(oData, oResponse) {
oModelRefDataDeferred.resolve();
},
error: function(oError) {
jQuery.sap.log.error("Error", oError);
}
});
sPath = "/Involvement_TypesSet";
oModel.read(sPath, {
success: function(oData, oResponse) {
oModelInvolvementDataDeferred.resolve();
},
error: function(oError) {
jQuery.sap.log.error("Error", oError);
}
});
var readyToGo = function() {
jQuery.sap.log.error("Ready", "f4");
this.getRouter().initialize();
};
jQuery.when(oModelTypeDataDeferred, oModelStatusDataDeferred, oModelActionTypeDataDeferred, oModelRoleDataDeferred, +
oModelRefDataDeferred, oModelExtOrgDataDeferred, oModelInvolvementDataDeferred).done().then( jQuery.proxy(readyToGo, this) );
},
/**
* The component is destroyed by UI5 automatically.
* In this method, the ErrorHandler is destroyed.
* @public
* @override
*/
destroy : function () {
this._oErrorHandler.destroy();
// call the base component's destroy function
UIComponent.prototype.destroy.apply(this, arguments);
},
/**
* This method can be called to determine whether the sapUiSizeCompact or sapUiSizeCozy
* design mode class should be set, which influences the size appearance of some controls.
* @public
* @return {string} css class, either 'sapUiSizeCompact' or 'sapUiSizeCozy' - or an empty string if no css class should be set
*/
getContentDensityClass : function() {
if (this._sContentDensityClass === undefined) {
// check whether FLP has already set the content density class; do nothing in this case
if (jQuery(document.body).hasClass("sapUiSizeCozy") || jQuery(document.body).hasClass("sapUiSizeCompact")) {
this._sContentDensityClass = "";
} else if (!Device.support.touch) { // apply "compact" mode if touch is not supported
this._sContentDensityClass = "sapUiSizeCompact";
} else {
// "cozy" in case of touch support; default for most sap.m controls, but needed for desktop-first controls like sap.ui.table.Table
this._sContentDensityClass = "sapUiSizeCozy";
}
}
return this._sContentDensityClass;
}
});
}
);
Root view controller (app.controller.js)
sap.ui.define([
"kristal/apps/agreements/controller/BaseController",
"sap/ui/model/json/JSONModel"
], function (BaseController, JSONModel) {
"use strict";
return BaseController.extend("kristal.apps.agreements.controller.App", {
onInit : function () {
var oViewModel,
fnSetAppNotBusy,
iOriginalBusyDelay = this.getView().getBusyIndicatorDelay();
oViewModel = new JSONModel({
busy : true,
delay : 0
});
this.setModel(oViewModel, "appView");
fnSetAppNotBusy = function() {
oViewModel.setProperty("/busy", false);
oViewModel.setProperty("/delay", iOriginalBusyDelay);
};
this.getOwnerComponent().getModel().metadataLoaded().
then(fnSetAppNotBusy);
// apply content density mode to root view
this.getView().addStyleClass(this.getOwnerComponent().getContentDensityClass());
},
onBeforeRendering : function() {
}
});
}
);
Worklist Controller (Worklist.controller.js)
sap.ui.define([
"kristal/apps/agreements/controller/BaseController",
"sap/ui/model/json/JSONModel",
"sap/ui/core/routing/History",
"kristal/apps/agreements/model/formatter",
"sap/ui/model/Filter",
"sap/ui/model/FilterOperator"
], function (BaseController, JSONModel, History, formatter, Filter, FilterOperator) {
"use strict";
return BaseController.extend("kristal.apps.agreements.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._oTableSearchState = [];
// Model used to manipulate control states
oViewModel = new JSONModel({
worklistTableTitle : this.getResourceBundle().getText("worklistTableTitle"),
saveAsTileTitle: this.getResourceBundle().getText("worklistViewTitle"),
shareOnJamTitle: this.getResourceBundle().getText("worklistViewTitle"),
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);
});
// Initialize column sorters
this._IDSorter = new sap.ui.model.Sorter("AgrId", false);
this._TypeSorter = new sap.ui.model.Sorter("AgrTypeid", false, function(oContext) {
var target = oContext.getProperty("ct>AgrTypeid");
if (target.length === 0) {
return {
key: "",
text: "No Category"
};
} else {
return {
key: formatter.textAgreementType(target),
text: formatter.textAgreementType(target)
};
}
});
this._PriceSorter = new sap.ui.model.Sorter("Price", false);
this._StatusSorter = new sap.ui.model.Sorter("AgrStatid", false, function(oContext) {
var target = oContext.getProperty("ct>AgrStatid");
if (target.length === 0) {
return {
key: "",
text: "No Category"
};
} else {
return {
key: formatter.textStatus(target),
text: formatter.textStatus(target)
};
}
});
// filter bar stuff
this.oFilterBar = null;
var sViewId = this.getView().getId();
this.oFilterBar = sap.ui.getCore().byId(sViewId + "--filterBar");
this.oFilterBar.registerFetchData(this.fFetchData);
this.oFilterBar.registerApplyData(this.fApplyData);
this.oFilterBar.registerGetFiltersWithValues(this.fGetFiltersWithValues);
this.fVariantStub();
//this.onToggleSearchField();
this.oFilterBar.fireInitialise();
this._sHeader = this.oFilterBar.getHeader();
},
/* =========================================================== */
/* 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.
* It there is a history entry or an previous app-to-app navigation we go one step back in the browser history
* If not, it will navigate to the shell home
* @public
*/
onNavBack : function() {
var sPreviousHash = History.getInstance().getPreviousHash(),
oCrossAppNavigator = sap.ushell.Container.getService("CrossApplicationNavigation");
if (sPreviousHash !== undefined || !oCrossAppNavigator.isInitialNavigation()) {
history.go(-1);
} else {
oCrossAppNavigator.toExternal({
target: {shellHash: "#Shell-home"}
});
}
},
/**
* Event handler when the share in JAM button has been clicked
* @public
*/
onShareInJamPress : function () {
var oViewModel = this.getModel("worklistView"),
oShareDialog = sap.ui.getCore().createComponent({
name: "sap.collaboration.components.fiori.sharing.dialog",
settings: {
object:{
id: location.href,
share: oViewModel.getProperty("/shareOnJamTitle")
}
}
});
oShareDialog.open();
},
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 oFilter;
var oTableSearchState = [];
//var sQuery = oEvent.getParameter("query");
var sSearchKey = this.getView().byId("application-agreements-display-component---worklist--searchField").getValue();
var sStatusKey = this.getView().byId("application-agreements-display-component---worklist--cbStatus").getSelectedKey();
var sTypeKey = this.getView().byId("application-agreements-display-component---worklist--cbType").getSelectedKey();
//if (sQuery && sQuery.length > 0) {
//oTableSearchState = [new Filter("AgrId", FilterOperator.Contains, sQuery)];
//var oFilter = new Filter("AgrId", FilterOperator.Contains, sQuery);
if (sSearchKey !== "") {
oFilter = new Filter("AgrId", FilterOperator.Contains, sSearchKey);
oTableSearchState.push(oFilter);
}
if (sStatusKey !== "") {
oFilter = new Filter("AgrStatid", FilterOperator.EQ, sStatusKey);
oTableSearchState.push(oFilter);
}
if (sTypeKey !== "") {
oFilter = new Filter("AgrTypeid", FilterOperator.EQ, sTypeKey);
oTableSearchState.push(oFilter);
}
//}
this._applySearch(oTableSearchState);
//}
},
/**
* 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();
},
// Custom sorters
onSortID : function(){
this._IDSorter.bDescending = !this._IDSorter.bDescending;
this.byId("table").getBinding("items").sort(this._IDSorter);
},
onSortType : function(){
this._TypeSorter.bDescending = !this._TypeSorter.bDescending;
this.byId("table").getBinding("items").sort(this._TypeSorter);
},
/*onSortComment : function(){
this._CommentSorter.bDescending = !this._CommentSorter.bDescending;
this.byId("table").getBinding("items").sort(this._CommentSorter);
},*/
onSortPrice : function(){
this._PriceSorter.bDescending = !this._PriceSorter.bDescending;
this.byId("table").getBinding("items").sort(this._PriceSorter);
},
onSortStatus : function(){
this._StatusSorter.bDescending = !this._StatusSorter.bDescending;
this.byId("table").getBinding("items").sort(this._StatusSorter);
},
/* =========================================================== */
/* 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("AgrId")
});
},
/**
* Internal helper method to apply both filter and search state together on the list binding
* @param {object} oTableSearchState an array of filters for the search
* @private
*/
_applySearch: function(oTableSearchState) {
var oTable = this.byId("table"),
oViewModel = this.getModel("worklistView");
oTable.getBinding("items").filter(oTableSearchState, "Application");
// changes the noDataText of the list in case there are no filter results
if (oTableSearchState.length !== 0) {
oViewModel.setProperty("/tableNoDataText", this.getResourceBundle().getText("worklistNoDataWithSearchText"));
}
},
// Filter bar stuff
onToggleSearchField: function(oEvent) {
var oSearchField = this.oFilterBar.getBasicSearch();
if (!oSearchField) {
var oBasicSearch = new sap.m.SearchField({
showSearchButton: false
});
} else {
oSearchField = null;
}
this.oFilterBar.setBasicSearch(oBasicSearch);
oBasicSearch.attachBrowserEvent("keyup", jQuery.proxy(function(e) {
if (e.which === 13) {
this.onSearch();
}
}, this));
},
onToggleShowFilters: function(oEvent) {
var bFlag = this.oFilterBar.getShowFilterConfiguration();
this.oFilterBar.setShowFilterConfiguration(!bFlag);
},
onToggleHeader: function(oEvent) {
var sHeader = "";
if (this.oFilterBar.getHeader() !== this._sHeader) {
sHeader = this._oHeader;
}
this.oFilterBar.setHeader(sHeader);
},
onChange: function(oEvent) {
this.oFilterBar.fireFilterChange(oEvent);
},
onClear: function(oEvent) {
var oItems = this.oFilterBar.getAllFilterItems(true);
for (var i = 0; i < oItems.length; i++) {
var oControl = this.oFilterBar.determineControlByFilterItem(oItems[i]);
if (oControl) {
var sType = oControl.getMetadata().getName();
if (sType === "sap.m.ComboBox") {
oControl.setSelectedKey("");
} else {
oControl.setValue("");
}
}
}
},
_showToast: function(sMessage) {
jQuery.sap.require("sap.m.MessageToast");
sap.m.MessageToast.show(sMessage);
},
onCancel: function(oEvent) {
this._showToast("cancel triggered");
},
onReset: function(oEvent) {
this._showToast("reset triggered");
},
/*onSearch: function(oEvent) {
this._showToast("search triggered");
},*/
onFiltersDialogClosed: function(oEvent) {
this._showToast("filtersDialogClosed triggered");
},
fFetchData: function() {
var sGroupName;
var oJsonParam;
var oJsonData = [];
var oItems = this.getAllFilterItems(true);
for (var i = 0; i < oItems.length; i++) {
oJsonParam = {};
sGroupName = null;
if (oItems[i].getGroupName) {
sGroupName = oItems[i].getGroupName();
oJsonParam.group_name = sGroupName;
}
oJsonParam.name = oItems[i].getName();
var oControl = this.determineControlByFilterItem(oItems[i]);
if (oControl) {
oJsonParam.value = oControl.getValue();
oJsonData.push(oJsonParam);
}
}
return oJsonData;
},
fApplyData: function(oJsonData) {
var sGroupName;
for (var i = 0; i < oJsonData.length; i++) {
sGroupName = null;
if (oJsonData[i].group_name) {
sGroupName = oJsonData[i].group_name;
}
var oControl = this.determineControlByName(oJsonData[i].name, sGroupName);
if (oControl) {
oControl.setValue(oJsonData[i].value);
}
}
},
fGetFiltersWithValues: function() {
var i;
var oControl;
var aFilters = this.getFilterGroupItems();
var aFiltersWithValue = [];
for (i = 0; i < aFilters.length; i++) {
oControl = this.determineControlByFilterItem(aFilters[i]);
if (oControl && oControl.getValue && oControl.getValue()) {
aFiltersWithValue.push(aFilters[i]);
}
}
return aFiltersWithValue;
},
fVariantStub: function() {
var oVM = this.oFilterBar._oVariantManagement;
oVM.initialise = function() {
this.fireEvent("initialise");
this._setStandardVariant();
this._setSelectedVariant();
};
var nKey = 0;
var mMap = {};
var sCurrentVariantKey = null;
oVM._oVariantSet = {
getVariant: function(sKey) {
return mMap[sKey];
},
addVariant: function(sName) {
var sKey = "" + nKey++;
var oVariant = {
key: sKey,
name: sName,
getItemValue: function(s) {
return this[s];
},
setItemValue: function(s, oObj) {
this[s] = oObj;
},
getVariantKey: function() {
return this.key;
}
};
mMap[sKey] = oVariant;
return oVariant;
},
setCurrentVariantKey: function(sKey) {
sCurrentVariantKey = sKey;
},
getCurrentVariantKey: function() {
return sCurrentVariantKey;
},
delVariant: function(sKey) {
if (mMap[sKey]) {
delete mMap[sKey];
}
}
};
}
});
}
);
Worklist.view.xml
<mvc:View
controllerName="kristal.apps.agreements.controller.Worklist"
xmlns="sap.m"
xmlns:mvc="sap.ui.core.mvc"
xmlns:semantic="sap.m.semantic"
xmlns:fb="sap.ui.comp.filterbar"
xmlns:core="sap.ui.core"
xmlns:footerbar="sap.ushell.ui.footerbar">
<semantic:FullscreenPage
id="page"
navButtonPress="onNavBack"
showNavButton="true"
title="{i18n>worklistViewTitle}">
<semantic:content>
<fb:FilterBar id="filterBar" header="{i18n>worklistListFilters}" enableBasicSearch="true"
reset="onReset" search="onSearch" clear="onClear" cancel="onCancel"
filtersDialogClosed = "onFiltersDialogClosed"
showRestoreButton="true" showClearButton="true" showCancelButton="true">
<fb:filterItems>
<!--fb:FilterItem name="A" label="Delivery Date">
<fb:control>
<DatePicker change="onChange"/>
</fb:control>
</fb:FilterItem-->
<fb:FilterItem name="sSearch" label="Search Agreement">
<fb:control>
<Input
id="searchField"
tooltip="{i18n>worklistSearchTooltip}"
width="auto"/>
</fb:control>
</fb:FilterItem>
<fb:FilterItem name="A" label="{i18n>tableTypeColumnTitle}" labelTooltip="Agreement Types">
<fb:control>
<ComboBox id="cbType" items="{
path: 'f4>/Agreement_TypesSet',
sorter: { path: 'AgrTypeid' }
}">
<items>
<core:Item key="{f4>AgrTypeid}" text="{f4>AgrTypetxt}"/>
</items>
</ComboBox>
</fb:control>
</fb:FilterItem>
<fb:FilterItem name="B" label="{i18n>tableStatusColumnTitle}" labelTooltip="Statuses">
<fb:control>
<ComboBox id="cbStatus" items="{
path: 'f4>/Agreement_StatusesSet',
sorter: { path: 'AgrStatid' }
}">
<items>
<core:Item key="{f4>AgrStatid}" text="{f4>AgrStattxt}"/>
</items>
</ComboBox>
</fb:control>
</fb:FilterItem>
</fb:filterItems>
</fb:FilterBar>
<Table
id="table"
width="auto"
class="sapUiResponsiveMargin"
items="{
path: '/AgreementsSet',
sorter: { path: 'AgrId' }
}"
noDataText="{worklistView>/tableNoDataText}"
busyIndicatorDelay="{worklistView>/tableBusyDelay}"
growing="true"
growingScrollToLoad="true"
updateFinished="onUpdateFinished">
<headerToolbar>
<Toolbar>
<Title id="tableHeader" text="{worklistView>/worklistTableTitle}"/>
<ToolbarSpacer />
<!--SearchField
id="searchField"
tooltip="{i18n>worklistSearchTooltip}"
search="onSearch"
width="auto">
</SearchField-->
</Toolbar>
</headerToolbar>
<columns>
<Column id="nameColumn">
<header>
<Toolbar>
<Text text="{i18n>tableNameColumnTitle}" id="nameColumnTitle"/>
<Button
icon="sap-icon://sort"
press="onSortID" />
</Toolbar>
</header>
</Column>
<Column id="typeColumn">
<header>
<Toolbar>
<Text text="{i18n>tableTypeColumnTitle}" id="nameTypeTitle"/>
<Button
icon="sap-icon://sort"
press="onSortType" />
</Toolbar>
</header>
</Column>
<Column id="commentColumn">
<header>
<Toolbar>
<Text text="{i18n>tableCommentColumnTitle}" id="nameCommentTitle"/>
<!--Button
icon="sap-icon://sort"
press="onSortComment" /-->
</Toolbar>
</header>
</Column>
<Column id="unitNumberColumn" hAlign="Right">
<header align="Right">
<Toolbar>
<Text text="{i18n>tableUnitNumberColumnTitle}" id="unitNumberColumnTitle"/>
<Button
icon="sap-icon://sort"
press="onSortPrice" />
</Toolbar>
</header>
</Column>
<Column id="statusColumn" hAlign="Right">
<header align="Right">
<Toolbar>
<Text text="{i18n>tableStatusColumnTitle}" id="nameStatusTitle"/>
<Button
icon="sap-icon://sort"
press="onSortStatus" />
</Toolbar>
</header>
</Column>
</columns>
<items>
<ColumnListItem
type="Navigation"
press="onPress">
<cells>
<ObjectIdentifier
title="{AgrId}"
text="{Shorttitle}">
</ObjectIdentifier>
<Text text="{
path: 'AgrTypeid',
formatter: '.formatter.textAgreementType'
}"/>
<Text text="{AgrComment}"/>
<ObjectNumber
number="{
path: 'Price',
formatter: '.formatter.numberUnit'
}"
unit="{Curr}"/>
<ObjectStatus
text="{
path: 'AgrStatid',
formatter: '.formatter.textStatus'
}"
state="{
path: 'AgrStatid',
formatter: '.formatter.stateStatus'
}"
/>
</cells>
</ColumnListItem>
</items>
</Table>
</semantic:content>
<semantic:sendEmailAction>
<semantic:SendEmailAction id="shareEmail" press="onShareEmailPress"/>
</semantic:sendEmailAction>
<semantic:shareInJamAction>
<semantic:ShareInJamAction id="shareInJam" visible="{FLP>/isShareInJamActive}" press="onShareInJamPress"/>
</semantic:shareInJamAction>
<semantic:saveAsTileAction>
<footerbar:AddBookmarkButton id ="shareTile" title="{worklistView>/saveAsTileTitle}" />
</semantic:saveAsTileAction>
</semantic:FullscreenPage>
sap.ui.model.odata.ODataModel
with the equivalentv2.ODataModel
. The former model has been deprecated for a long time. – Boghyon Hoffmannthis.getModel
) as well as from Controller (viathis.getOwnerComponent().getModel
). – Boghyon Hoffmann