Think of the following problem: You need to check some data on the server using javascript on the OnSave event of MS CRM. You would instantiate a ActiveX XMLHttp object. Next you would initialize all parameters including the onreadystatechangefunction and then send the request. The data would be returned in your onreadystatechangefunction where you could analyze it. Based on this analysis you would decide whether you would allow saving the CRM form or not. But wait a minute. You are now in your handler function and already left the scope of the OnSave handler. So there is no possibility for influencing the save behavior anymore. The problem is the asynchronous behavior of the ajax call.
I tried several possible solutions, e.g. playing around with window.setTimeout to build some wait function. But nothing accomplished the behavior I wanted:
1. Send the request
2. Get the data
3. Analyze it
4. Decide whether to allow saving or not.
I spend several hours thinking of a solution, but could not find any. But sometimes you have to break your own stupid way of thinking as a programmer and asking what you would call a non-programming person. I described my problem, he thought for a moment and instantly came up with the solution:
1. In the OnSave event send the request and then stop saving the form by setting event.returnValue = false.
2. In your onreadystatechangefunction receive the data, analyze it and then save the form using Save() or SaveAndClose() in your code or don't save it based on this analysis.
3. The only thing you have to consider is that saving the form in this way will again fire the event. To avoid an infinte loop you have to set some kind of flag and analyze it before firing the request.
I don't know if you will find this posting worth the reading, because you would have solved the problem this way from the beginning. But maybe there is someone out there that got stuck in his or her thinking the same way and does not have a colleague like my colleague Mario. :-)
Here is some basic sketch of the code you would insert in the OnSave event:
// write the original event mode into a global variable
eventMode=event.Mode;
// first check the flag
if(typeof notsave!='undefined')
{
event.returnValue=true;
return true;
}
window.HttpReq=new ActiveXObject('Microsoft.XMLHTTP');
if (window.HttpReq.overrideMimeType){window.HttpReq.overrideMimeType('text/xml')};
window.HttpReq.onreadystatechange=function(){saveMyEntity();}
window.HttpReq.open('POST', '/myurlthatdoessomething.aspx', true);
window.HttpReq.send();
// the following two code lines are the important part
event.returnValue = false;
return false;
function saveMyEntity()
{
if (window.HttpReq.readyState==4)
{
if (window.HttpReq.status==200)
{
// here is the analysis of the server responce
res=window.HttpReq.responseXML.selectSingleNode('//check').text;
if(res=='ok')
{
// this is the flag. it is a global variable. as an alternative bind it to the window object
notsave=1;
if(eventMode==1)
{
crmForm.Save();
}
else
{
crmForm.SaveAndClose();
}
}
else
{
alert('Some freaky error message that confuses the user and leaves him completely puzzeled');
}
}
}
}
Hf :-)