Wednesday, May 13, 2009

Page refresh after record was changed on a server

Hi. This is my first post on English so I beg a pardon for my terrible English. My native is C#.

I think that almost all of developers for MS CRM has issues with form refreshing.
For example - child entity update trough plugin invoke update of parent entity and if form of parent entity is opened changes will be shown only after reopening or refreshing of form. To avoid this issue i wrote a little code.

Idea is following:
1. Remember load time of form.
2. By timer read modifyiedon field of opened record form.
3. Compare it. If retrieved modifiedon datetime is greater then load datetime - execute form reload.


First step is retrieving modified datetime from server.

It wasn't a trouble:

var xml = "<?xml version='1.0' encoding='utf-8'?>"+ 
"<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'"+
" xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'"+
" xmlns:xsd='http://www.w3.org/2001/XMLSchema'>"+
GenerateAuthenticationHeader()+
"<soap:Body>"+
"<Retrieve xmlns='http://schemas.microsoft.com/crm/2007/WebServices'>"+
"<entityName>account</entityName>"+
"<id>"+crmForm.ObjectId+"</id>"+
"<columnSet xmlns:q1='http://schemas.microsoft.com/crm/2006/Query' xsi:type='q1:ColumnSet'>"+
"<q1:Attributes>"+
"<q1:Attribute>modifiedon</q1:Attribute>"+
"</q1:Attributes>"+
"</columnSet>"+
"</Retrieve>"+
"</soap:Body>"+
"</soap:Envelope>";
//Prepare the xmlHttpObject and send the request.
var xHReq = new ActiveXObject("Msxml2.XMLHTTP");
xHReq.Open("POST", "/mscrmservices/2007/CrmService.asmx", false);
xHReq.setRequestHeader("SOAPAction","http://schemas.microsoft.com/crm/2007/WebServices/Retrieve");
xHReq.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xHReq.setRequestHeader("Content-Length", xml.length);
xHReq.send(xml);
var resultXml = xHReq.responseXML;

var source = resultXml.selectSingleNode("//q1:modifiedon").nodeTypedValue;



I have the trouble with data formatting of retrieved from CrmService modifiedon datetime, cause it retured in format like 2009-12-30T00:00:00+02:00.

To convert i wrote following code:

var firstpart = source.split('T')[0];
var secondpart = source.split('T')[1].split('+')[0];
var parts = firstpart .split('-');
var parts2 = secondpart.split(':')

var modifiedon = new Date();

modifiedon.setYear(parts[0]);
modifiedon.setMonth(parts[1] - 1);
modifiedon.setDate(parts[2]);

modifiedon.setHours(parts2[0]);
modifiedon.setMinutes(parts2[1]);
modifiedon.setSeconds(parts2[2]);


So for end full retrieved code - it was made for account form. To change for any other - just change entity name in request:

function timerHandler() 
{
var xml = "<?xml version='1.0' encoding='utf-8'?>"+
"<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'"+
" xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'"+
" xmlns:xsd='http://www.w3.org/2001/XMLSchema'>"+
GenerateAuthenticationHeader()+
"<soap:Body>"+
"<Retrieve xmlns='http://schemas.microsoft.com/crm/2007/WebServices'>"+
"<entityName>account</entityName>"+
"<id>"+crmForm.ObjectId+"</id>"+
"<columnSet xmlns:q1='http://schemas.microsoft.com/crm/2006/Query' xsi:type='q1:ColumnSet'>"+
"<q1:Attributes>"+
"<q1:Attribute>modifiedon</q1:Attribute>"+
"</q1:Attributes>"+
"</columnSet>"+
"</Retrieve>"+
"</soap:Body>"+
"</soap:Envelope>";
//Prepare the xmlHttpObject and send the request.
var xHReq = new ActiveXObject("Msxml2.XMLHTTP");
xHReq.Open("POST", "/mscrmservices/2007/CrmService.asmx", false);
xHReq.setRequestHeader("SOAPAction","http://schemas.microsoft.com/crm/2007/WebServices/Retrieve");
xHReq.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xHReq.setRequestHeader("Content-Length", xml.length);
xHReq.send(xml);
var resultXml = xHReq.responseXML;

var source = resultXml.selectSingleNode("//q1:modifiedon").nodeTypedValue;

var firstpart = source.split('T')[0];
var secondpart = source.split('T')[1].split('+')[0];
var parts = firstpart .split('-');
var parts2 = secondpart.split(':')

var modifiedon = new Date();

modifiedon.setYear(parts[0]);
modifiedon.setMonth(parts[1] - 1);
modifiedon.setDate(parts[2]);

modifiedon.setHours(parts2[0]);
modifiedon.setMinutes(parts2[1]);
modifiedon.setSeconds(parts2[2]);

if (modifiedon > openDate)
location.reload();
}

var openDate = new Date();

if (crmForm.FormType == 2)
setInterval(timerHandler, 1000);

4 comments:

  1. Great code Andriy !!!

    ReplyDelete
  2. Thanks =) I hope that this code will help you =)

    ReplyDelete
  3. Andriy, thank you for excellent code. My server is in another time zone, therefore I added

    openDate.setHours(openDate.getUTCHours());

    and
    var thirdpart = source.split('+')[1].split(':')[0]; ...
    modifiedon.setHours(parts2[0] - thirdpart) ;

    I understand that "Midnight issue" might be faced but time difference is low in our case.

    ReplyDelete
  4. Hi Andiry, Hope you are doing well.

    I have one question.
    I want to refresh Parent Form automatically when i enter any record into related entity record.

    ReplyDelete