Fiori Elements片段扩展中无需location.reload()刷新上下文方案
问题场景
在Fiori Elements应用中采用片段扩展(非传统UI5控制器),通过OData v4绑定实现了onSavePress函数用于数据更新/创建。保存后导航至ListReport的其他条目时,仍显示陈旧数据,目前仅location.reload()能解决,但需要更优方案。
简化代码实现
onSavePress: async function (oEvent) { const oButton = oEvent.getSource(); const oVBox = oButton.getParent().getParent(); // Root container const oModel = oButton.getModel(); const oCtx = oVBox.getBindingContext(); const sId = oCtx.getObject().prod_nbr; const sPath = `/Products('${sId}')/general_info`; const oBinding = oModel.bindContext(sPath, null, { $$updateGroupId: "auto" }); await oBinding.initialize(); const oGenCtx = oBinding.getBoundContext(); const generalInfo = await oGenCtx.requestObject(); if (generalInfo) { oGenCtx.setProperty("color", "Red"); oGenCtx.setProperty("notes", "Updated notes"); } else { const oListBinding = oModel.bindList("/GeneralInfo", null, [], [], { $$updateGroupId: "auto" }); oListBinding.create({ ib_code: sId, color: "Red", notes: "Created" }); } await oModel.submitBatch("auto"); // TEMP workaround: location.reload(); // <- Without this, context doesn't refresh properly }
面临挑战
- 未使用标准控制器,无法直接访问Router;
- 通过JS文件动态加载
edit.fragment.xml和readonly.fragment.xml实现编辑/只读模式切换,手动绑定父容器上下文。
核心需求
保存后无需重载页面,即可刷新视图或当前绑定上下文。
具体问题
- 是否可通过编程方式无需
location.reload()刷新上下文或视图? - 此类扩展场景有哪些模式或最佳实践?
额外发现
首次加载Product条目时,Network中的OData V4请求包含Product?$extend=...及general_info所有字段;但保存后返回ListReport点击其他Product时,请求中的Product?$extend=...缺少更新的两个字段,推测数据被缓存,Fiori Elements未重新请求。
解决方案
1. 无需location.reload()的刷新方案
针对OData V4模型的缓存不一致问题,可通过以下几种编程方式实现刷新:
方式一:强制刷新特定绑定上下文
在submitBatch完成后,对当前操作的上下文调用refresh方法并传入true参数(跳过缓存,强制从服务器拉取):
await oModel.submitBatch("auto"); // 刷新当前Product主上下文 oCtx.refresh(true); // 刷新general_info关联上下文 oGenCtx.refresh(true);
方式二:清除实体集缓存并触发绑定更新
如果上下文刷新无效,可直接清除对应实体集的缓存,再刷新父容器绑定:
await oModel.submitBatch("auto"); // 清除Products和GeneralInfo实体集的缓存 oModel.clearCache("/Products"); oModel.clearCache("/GeneralInfo"); // 刷新父容器绑定,同步视图数据 oVBox.getBindingContext().refresh(true);
方式三:利用OData V4的自动刷新配置
在绑定上下文或列表绑定时添加$$refreshAfterChange: true,让模型在提交批量操作后自动刷新相关数据:
// 修改general_info的绑定配置 const oBinding = oModel.bindContext(sPath, null, { $$updateGroupId: "auto", $$refreshAfterChange: true // 提交后自动刷新该上下文 }); // 创建GeneralInfo时的列表绑定也添加该配置 const oListBinding = oModel.bindList("/GeneralInfo", null, [], [], { $$updateGroupId: "auto", $$refreshAfterChange: true });
2. 片段扩展场景的模式与最佳实践
模式一:复用Fiori Elements内置API
即使使用片段扩展,也可通过模型获取根组件,进而调用Fiori Elements的ExtensionAPI实现视图刷新:
const oComponent = oModel.getOwnerComponent(); const oExtensionAPI = oComponent.getExtensionAPI(); // 刷新当前页面所有绑定 oExtensionAPI.refresh(); // 或仅刷新指定实体集 oExtensionAPI.refresh("/Products");
模式二:统一上下文传递
避免通过getParent().getParent()硬编码获取容器,在动态加载片段时直接传入父上下文:
this.loadFragment({ name: "your.namespace.edit.fragment", bindingContext: oParentCtx // 父容器的上下文 }).then(oFragment => { oVBox.addItem(oFragment); });
模式三:更新组与自动刷新配合使用
将OData V4的$$updateGroupId与$$refreshAfterChange配置配合,确保批量提交后模型自动同步服务器数据,减少缓存不一致问题。
模式四:优化控件层级获取方式
给父容器设置唯一id,通过this.byId("containerId")获取容器,替代硬编码的getParent()链式调用,提升代码可维护性。
内容的提问来源于stack exchange,提问作者Aleksandar Grujic

