如何用JavaScript在Dynamics 365 CRM(UCI)中取消保存操作?
Dynamics 365 CRM OnSave事件取消问题解决方案
问题分析
- 空函数触发
UciError: Cannot save due to no dirty changes.- 这是CRM默认行为:用户尝试保存无任何字段变更的记录时,系统会抛出该错误。即使事件处理程序的「启用」复选框未勾选仍出现,大概率是浏览器缓存或后台事件注册未同步导致,实际事件仍被触发。
- 调用
preventDefault()后触发UciError: Cannot save due to PreventDefault encountered.- 该错误是预期结果:
preventDefault()会直接阻止表单保存操作,系统会抛出此提示告知保存被中断。但我们需要结合业务逻辑(如WebApi查重结果)来控制是否阻止,而非无条件调用。
- 该错误是预期结果:
解决方案
1. 解决空函数时的无变更保存报错
在函数开头增加表单脏状态判断,无变更时直接返回,不执行后续逻辑:
checkForDuplicate = function (executionContext) { const formContext = executionContext.getFormContext(); // 无字段变更时直接返回,避免系统报错 if (!formContext.data.entity.getIsDirty()) { return; } // 后续逻辑... }
同时检查事件注册的实际状态:进入CRM解决方案,找到对应实体的事件注册记录,确认是否真的禁用了该事件处理程序,避免UI显示与后台不同步。
2. 结合WebApi异步逻辑控制OnSave事件
由于WebApi请求是异步操作,需先阻止默认保存,待请求返回后再决定是否执行保存或提示用户:
- 事件注册时必须勾选「启用异步处理」选项
- 示例代码:
checkForDuplicate = async function (executionContext) { const formContext = executionContext.getFormContext(); const args = executionContext.getEventArgs(); // 无变更时直接返回 if (!formContext.data.entity.getIsDirty()) { return; } // 先阻止默认保存,等待异步查重结果 args.preventDefault(); try { // 获取要查重的字段值(以区域名称为例) const territoryName = formContext.getAttribute("name").getValue(); if (!territoryName) { // 名称为空时允许保存 formContext.data.entity.save(); return; } // 调用WebApi查询是否存在同名活跃区域 const query = `?$select=name&$filter=name eq '${encodeURIComponent(territoryName)}' and statecode eq 0`; const response = await Xrm.WebApi.retrieveMultipleRecords("territory", query); if (response.entities.length > 0) { // 存在重复,提示用户不保存 Xrm.Navigation.openAlertDialog({ text: "该区域名称已存在,无法保存。" }); } else { // 无重复,执行保存 formContext.data.entity.save(); } } catch (error) { console.error("查重失败:", error); Xrm.Navigation.openAlertDialog({ text: "检查重复时出错,请稍后重试。" }); // 可选:出错时允许保存,注释掉则不保存 // formContext.data.entity.save(); } }
关键说明
- 异步函数必须搭配事件注册的「启用异步处理」,否则会导致表单无响应或报错。
- 避免无条件调用
preventDefault(),仅在需要基于异步结果控制保存时才先阻止,后续根据业务逻辑决定是否触发保存。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

