Dynamics CRM JavaScript表单保存拦截功能实现求助
问题修复:Dynamics 365表单保存时的层级冲突验证
核心问题分析
你的脚本问题出在异步操作与表单保存事件的时序不匹配:Xrm.WebApi的请求是异步的,表单保存事件会在异步请求完成前就执行完毕。直接调用preventDefault会完全阻止保存,但不调用的话又会在验证结果出来前就完成保存。此外,全局状态变量的错误使用导致后续保存操作无法重新触发验证。
修复后的完整代码
// On Save validation var ProjectMainForm = (function () { "use strict"; var SaveMode = { Save: 1, SaveAndClose: 2, SaveAndNew: 59, Autosave: 70 }; var saveMode; function OnSave(executionContext) { var eventArgs = executionContext.getEventArgs(); var formContext = executionContext.getFormContext(); saveMode = eventArgs.getSaveMode(); // 仅对已存在的记录进行验证(表单类型2) if (formContext.ui.getFormType() === 2) { // 先阻止默认保存,等待异步验证结果 eventArgs.preventDefault(); // 过滤不需要验证的保存模式 if (![SaveMode.Save, SaveMode.SaveAndClose, SaveMode.SaveAndNew, SaveMode.Autosave].includes(saveMode)) { return; } fetchChildrenProjects(formContext, eventArgs); } else { console.log("跳过新建记录的验证"); } } function fetchChildrenProjects(formContext) { var projectID = formContext.getAttribute("dmis_dmisid").getValue(); var projectLevel = formContext.getAttribute("dmis_displaylevel").getValue(); var fetchXML = "<fetch top='1'>" + "<entity name='dmis_dmishierarchy'>" + "<attribute name='dmis_dmishierarchyid'/>" + "<filter>" + "<condition attribute='dmis_dmisid' operator='eq' value='" + projectID + "'/>" + "</filter>" + "</entity>" + "</fetch>"; var encodedFetchXML = encodeURIComponent(fetchXML); Xrm.WebApi.retrieveMultipleRecords("dmis_dmishierarchy", "?fetchXml=" + encodedFetchXML).then( function success(result) { if (result.entities.length > 0) { var hierarchyId = result.entities[0].dmis_dmishierarchyid; checkForConflict(formContext, projectLevel, hierarchyId); } else { console.log("未找到当前项目的层级记录"); // 无层级记录,允许保存 triggerSave(formContext); } }, function (error) { Xrm.Navigation.openAlertDialog({ text: "获取层级ID失败: " + error.message }); } ); } function checkForConflict(formContext, projectLevel, hierarchyId) { var fetchXML = "<fetch>" + "<entity name='dmis_dmishierarchy'>" + "<attribute name='dmis_displaylevel'/>" + "<filter>" + "<condition attribute='dmis_parent' operator='eq' value='" + hierarchyId + "'/>" + "</filter>" + "</entity>" + "</fetch>"; var encodedFetchXML = encodeURIComponent(fetchXML); Xrm.WebApi.retrieveMultipleRecords("dmis_dmishierarchy", "?fetchXml=" + encodedFetchXML).then( function success(result) { if (result.entities.some(entity => entity.dmis_displaylevel <= projectLevel)) { Xrm.Navigation.openAlertDialog({ title: "保存冲突", text: "无法保存:当前项目存在同级或更低层级的子项目。" }); } else { // 验证通过,执行手动保存 triggerSave(formContext); } }, function (error) { Xrm.Navigation.openAlertDialog({ text: "检查层级冲突失败: " + error.message }); } ); } // 根据保存模式触发对应的保存操作 function triggerSave(formContext) { switch (saveMode) { case SaveMode.Save: case SaveMode.Autosave: formContext.data.entity.save(); break; case SaveMode.SaveAndClose: formContext.data.entity.save("saveandclose"); break; case SaveMode.SaveAndNew: formContext.data.entity.save("saveandnew"); break; default: formContext.data.entity.save(); } } return { OnSave: OnSave }; })();
关键修改点
- 强制阻止默认保存:在OnSave事件开头就调用
eventArgs.preventDefault(),确保表单不会在异步验证完成前自动保存。 - 移除冗余全局变量:删除
hasCheckedConflict,避免状态残留导致后续保存操作异常。 - 拆分保存逻辑:新增
triggerSave函数统一处理不同保存模式的手动触发,代码更简洁可维护。 - 完善异常场景处理:在获取层级记录为空的场景下直接允许保存,避免验证逻辑遗漏。
内容的提问来源于stack exchange,提问作者Gareth Wilson
相关产品推荐
相关产品推荐

