SAP UI5主从应用如何在视图加载前从OData加载2个及以上实体
SAP UI5 Master-Detail主从应用Fragment字段检索报错解决方案
核心问题根因
当前报错是因为XML视图中直接声明的Fragment会随Detail视图初始化一同渲染,此时IconTabBar还未完成Detail Entity的绑定,Fragment内的相对路径绑定会自动向上查找父级(Detail视图层级绑定的Master EntityType)的字段,匹配不到就会抛出异常。
可行解决方案
方案1:保留现有Association关联,控制渲染时序(无需修改后端逻辑)
- 调整路由匹配逻辑,进入路由时立即开启加载状态,同时隐藏IconTabBar
首先给Detail控制器初始化一个视图模型控制显示状态:
onInit: function() { // 初始化视图控制模型 const oViewModel = new sap.ui.model.json.JSONModel({ isDetailLoaded: false }); this.getView().setModel(oViewModel, "viewControl"); this.getRouter().attachRoutePatternMatched(_onRoutePatternMatched, this); }, _onRoutePatternMatched: function(oEvent) { const view = this.getView(); view.setBusy(true); // 先清空IconTabBar的绑定,避免残留上下文报错 view.byId("iconTabBar").unbindElement(); const sPath = "/" + oEvent.getParameter("arguments").contextPath; view.bindElement({ path: sPath, events: { dataReceived: function (oResponse) { view.byId("iconTabBar").bindElement({ path: "Master2Detail", events: { dataReceived: function (oRespon) { // 绑定完成后再显示IconTabBar、关闭加载 view.getModel("viewControl").setProperty("/isDetailLoaded", true); view.setBusy(false); } } }); } } }); }
- 修改XML视图中IconTabBar的可见性绑定
<IconTabBar id="iconTabBar" visible="{viewControl>/isDetailLoaded}" class="sapUiResponsiveContentPadding" tooltip="{i18n>DETAIL_AMOUNT}" expandable="false">
绑定完成前IconTabBar不会渲染,Fragment也不会初始化,自然不会出现字段查找错误。
方案2:动态加载Fragment(更彻底避免提前渲染)
不要在XML中直接声明Fragment,等IconTabBar绑定完成后再动态实例化Fragment插入对应节点:
// IconTabBar的dataReceived事件内 dataReceived: function (oRespon) { const oCurrentTab = view.byId("currentDetailTab"); const oStatusTab = view.byId("statusDetailTab"); // 只加载一次,避免重复实例化 if (!oCurrentTab.getContent().length) { // 加载金额Fragment Fragment.load({ id: view.getId(), name: "app.masterDetail.view.fragments.currentDetail", controller: this }).then(function(oFragment) { oCurrentTab.addContent(oFragment); }); // 加载状态Fragment Fragment.load({ id: view.getId(), name: "app.masterDetail.view.fragments.statusDetail", controller: this }).then(function(oFragment) { oStatusTab.addContent(oFragment); }); } view.setBusy(false); }
方案3:采用单请求优化方案(性能最优,即你提出的思路)
- Master视图跳转时传递需要的头部字段:
function _onUpdateFinished(event) { const selItem = event.getSource().getSelectedItem(); const sPath = selItem.getBindingContextPath().substr(1); // 传递头部需要的Master字段 router.navTo("detail", { contextPath: sPath, masterName: selItem.getProperty("Name"), masterId: selItem.getProperty("ID") }); }
- Detail视图路由匹配时直接绑定Detail实体,头部字段从路由参数取,存到视图模型直接绑定:
_onRoutePatternMatched: function(oEvent) { const view = this.getView(); view.setBusy(true); const oArgs = oEvent.getParameter("arguments"); // 存Master头部字段到视图模型 this.getModel("viewControl").setProperty("/masterInfo", { Name: oArgs.masterName, ID: oArgs.masterId }); // 直接拼接Detail实体的请求路径(根据后端OData的路由规则调整) const sDetailPath = "/DetailEntitySet('" + oArgs.contextPath.split("'")[1] + "')"; view.byId("iconTabBar").bindElement({ path: sDetailPath, events: { dataReceived: function () { view.setBusy(false); } } }); }
- 修改头部字段绑定,直接从视图模型取值:
<f:expandedContent> <Label text="{i18n>DETAIL_NAME}: {viewControl>/masterInfo/Name}"/> </f:expandedContent>
该方案仅发起1次后端请求,完全避免了两次绑定的时序问题,是效果最好的优化方向。
内容的提问来源于stack exchange,提问作者RaulCB
相关产品推荐
相关产品推荐

