CRM365 表单提供
OnSave
事件来执行业务验证。
如果其中一项验证失败,我们可以使用 executionContext.getEventArgs().preventDefault()
来停止记录创建。
验证当前表单的字段固然很好,但是,在某些情况下,验证还必须要求对实体记录执行查询。
例如,创建房间预订必须检查是否存在任何其他预先存在的预订,如果它们重叠则停止。
问题在于 REST API 调用是异步的,需要时间来执行和返回结果。当信息在响应中变得可用时,OnSave
功能就已经结束,并且记录基本上在没有验证的情况下被保存。
我的问题如下:
executionContext.getEventArgs().preventDefault()
有相反的吗?我们可以停止保存操作,但是有“允许保存”之类的说法吗?
我尝试过 formContext.data.entity.save();
但由于我处于 OnSave
事件中,它创建了一个无限循环。对我来说几乎不可想象这个标志可以设置但不能重置。
是否可以有效地停止 JavaScript 或使其“睡眠”直到 REST API 数据可用?一切都围绕
SetTimeout
函数展开,但这是一个非阻塞函数,当然我的 JavaScript 只是运行它。
我确信我不是唯一遇到这种情况的人,它必须是解决这些基于 REST API 的验证的模式。
我应该补充一点,我正在寻找基于客户端的解决方案;所有这些都可以在插件或自定义工作流程中相对容易地实现。
我找到了此链接并在新的 Dynamics Trial(2020 年发布第 2 波)中验证了它,并且 XRM 组件似乎在那里:
Save and Close
的附加评论:https://dreamingincrm.com/2017/10/12/cancelling-save-event-based-on-the-result-of-async-operation/
编辑,使其不是“仅链接”答案
Clone
创建 Xrm.Page.ui
和 Xrm.Page.data.entity
的副本 - 这样,如果用户按 Save and Close
,这些对象仍然可用saveHandler
方法,使用 RetrieveMultiple
模拟异步验证过程代码:
Xrm.Page.data.entity.addOnSave((()=>{
let isSave = false;
var uiClone = parent.jQuery.extend(true, {}, Xrm.Page.ui);
var entityClone = parent.jQuery.extend(true, {}, Xrm.Page.data.entity);
var closeHandler = ()=>{
console.log('local. close blocked.');
};
var saveHandler = (ev)=>{
console.log('local. save blocked.');
Xrm.WebApi.retrieveMultipleRecords('systemuser','$select=fullname,jobtitle,homephone').then(x=>{
isSave = !x.entities.some(x=>x.homephone == '12345');
if(isSave){
Xrm.Page.data.entity.save = entityClone.save;
Xrm.Page.ui.close = uiClone.close;
if((typeof ev === 'string' && ev === 'saveandclose') ||
(ev.getEventArgs && ev.getEventArgs() && ev.getEventArgs().getSaveMode() === 2)){
console.log('saveandclose');
entityClone.save('saveandclose');
}
else{
console.log('save');
entityClone.save();
}
}
else{
console.log('User with homephone 12345 exists. Save blocked.');
}
});
};
return (e)=>{
var eventArgs = e.getEventArgs();
console.log(`DataXml OnSave: ${Xrm.Page.data.entity.getDataXml()}`);
console.log(`Save Mode: ${eventArgs.getSaveMode()}`);
if(isSave) {
console.log('proceed to save');
Xrm.Page.data.entity.save = entityClone.save;
Xrm.Page.ui.close = uiClone.close;
return;
}
else{
Xrm.Page.data.entity.save = saveHandler;
Xrm.Page.ui.close = closeHandler;
if(eventArgs.getSaveMode() !== 2){
eventArgs.preventDefault();
}
saveHandler(e);
}
}
})());
此代码示例的所有功劳均归原作者所有。
如果问题是手动entity.save()发生在异步函数完成之前,只需将save()放在异步响应中,而不是在函数之后。如果需要执行多个异步功能,也可以使用 async/await