我有一个工作正常但有轻微问题的应用程序,oData在某些情况下在加载第一个视图时没有准备好。该应用程序使用2个数据模型,它们都在manifest.json中声明,一个是匿名的主要工作,另一个是名为“f4”,用于处理某些格式化程序和下拉列表中使用的某些实体。后一个模型的数据通过根视图的init函数中的一系列读取操作加载。暂且不谈开头提到的问题,其他一切都有效。
感谢这里的一些专家建议,找到了我的问题的原因。路由器在加载数据之前被初始化,因此我决定将读取操作从根视图移动到component.js。
这就是问题所在。应用程序已知模型,但数据似乎是空的。我知道数据正在加载,因为我调试了应用程序,并在成功初始化路由器之前观察了应用程序从所有读取成功函数传递。在另一篇文章中读到,在onInit中执行此操作并不是最好的做法,所以我再次将onInit中的功能移动到onAfterRendering函数,但结果仍然相同,没有数据。
所以问题是:如何在路由器初始化之前访问oData模型,获取所需条目并让应用程序知道它们?
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;
}
});
}
);
根视图控制器(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.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>
答案 0 :(得分:0)
除了早期的回复之外,我还要补充一点,我通常使用metadataLoaded
承诺来确保模型完全实例化。
init : function () {
...
sap.ui.getCore().getModel()..metadataLoaded().then(this._onMetadataLoaded.bind(this));
},
_onMetadataLoaded: function() {
...
}
&#13;
答案 1 :(得分:0)
这个问题已在不能反映最初问题的级别进行了修订,而这个问题错误地使用了 component.js 中的其他命名模型。现在问题的方式,问题只是 component.js 中的 var oModel = this.getModel(); 语句,其中缺少模型名称。
非常感谢@BoghyonHoffmann提供解决方案,但在最后几天如此耐心,并指导我一直以来。这不仅仅是关于工作的事情,还关于这里澄清的许多错误观念,关于数据模型的使用,欢呼!