如何实现SAPUI5 Fragment中用户输入修改的撤销功能
核心原因
你之前调用的refresh(true)、updateBindings(true)、resetChanges()不生效的根因:
refresh和updateBindings的逻辑是把模型当前存储的值重新渲染到控件上。如果你用的是默认配置的JSON模型,用户输入时双向绑定会直接把新值写入模型覆盖原始值,这时候刷新只会重新渲染用户改后的新值,根本拿不到旧数据。resetChanges()本身只在两种场景下生效:一是用OData V2/V4模型且修改未提交到后端,二是JSON模型手动开启了变更跟踪、框架留存了原始值副本。普通JSON模型默认不存原始值,自然没有内容可重置。
落地实现方案
方案1:单字段独立撤销(通用无依赖,适配所有模型,推荐)
不需要修改模型配置,逻辑完全可控,非常适合单个输入框的撤销场景:
- 在Fragment加载完成、输入框渲染完初始值的时机(比如Fragment挂载后的回调、控制器的
onAfterRendering钩子中),把初始值存在控件实例上即可,不需要额外定义全局变量:
// 替换成你自己获取Input控件的逻辑,注意带上Fragment的ID前缀避免ID冲突 const oAckInput = this.byId("orderAcknowledgmentInput"); oAckInput._originalVal = oAckInput.getValue();
- 撤销按钮的点击事件中直接回写原始值:
onPressUndo: function () { const oInput = this.byId("orderAcknowledgmentInput"); const oTableModel = oInput.getModel("tableData"); const sValuePath = oInput.getBinding("value").getPath(); // 把原始值写回模型,同步清空输入框的校验状态 oTableModel.setProperty(sValuePath, oInput._originalVal); oInput.setValueState("None"); }
方案2:多字段批量撤销(适合整表单/整行表格数据回退)
如果需要同时撤销一组字段的修改,可以给JSON模型开启变更跟踪,直接用UI5原生的重置方法:
- 初始化
tableData模型时打开变更跟踪配置:
// 初始化JSON模型,第二个参数传true开启深拷贝观察 const oTableModel = new JSONModel(yourInitialTableData, true); // 开启双向绑定 oTableModel.setDefaultBindingMode("TwoWay"); // 注册空的属性变更监听,触发框架内部的原始值留存逻辑 oTableModel.attachPropertyChange(() => {}); this.getView().setModel(oTableModel, "tableData");
- 撤销时直接调用重置方法,传入需要重置的字段路径即可:
onPressBatchUndo: function () { const oModel = this.getView().getModel("tableData"); const oInput = this.byId("orderAcknowledgmentInput"); // 拼接字段的完整路径,不传参数的话会重置模型下所有未提交的修改 const sFieldPath = oInput.getBindingContext("tableData").getPath() + "/orderAcknowledgment"; oModel.resetChanges([sFieldPath]); }
如果你用的是OData模型,检查两个点:一是不要误取视图上的本地JSON模型,要拿到正确的OData模型实例;二是传入的重置路径必须是带实体主键的完整路径,比如/OrderSet('1000001')/orderAcknowledgment,路径不匹配的话resetChanges不会生效。
避坑提示
不要在输入框的liveChange事件里提前把输入值同步到本地存储、全局变量这类持久化位置,否则就算重置了模型值,其他位置存储的新值还是会回写覆盖,导致撤销失效。
内容的提问来源于stack exchange,提问作者Adam Harkus
相关产品推荐
相关产品推荐

