Category: XML

Add custom fetch XML to subgrid lookup

Add custom fetch XML to subgrid lookup

In this blog, I am going to show how we can change subgrid lookup behavior. Basically, I want to control custom N:N contact subgrid lookup, depend on company lookup that is on the contact form.

e.g. A.Datum company have five contacts and if I select contact lookup (custom N:N subgrid inline lookup ) on one of contact form so it’ll only show four contacts in subgrid lookup excluding this contact.

I have an N:N subgrid and company lookup on the contact form.

2

What’s the tricky part for getting subgrid lookup ?

Inspecting DOM

For add event on subgrid lookup, we need to inspect the DOM for subgrid and look out for lookup object.

Have a look below image, It clearly shows how we can find lookup , object by object.(if object key, not the same like below then find lookup with help of object name.)

FYI I am using Dynamics 365 online.

3

After inspecting the DOM structure of the subgrid and carefully understand the mechanics of the lookup filter,we can set filter criteria like in the JavaScript below:

 var RelatedContact = Xrm.Page.getControl('RelatedContact');
 var RelatedContactLookup = RelatedContact.$0_3.$1m_4.$O_4.$38_3.$3_6;
 RelatedContactLookup.addPreSearch(function ()
 {
 if (Xrm.Page.getAttribute("parentcustomerid").getValue())
 {
 var parentCustomer = Xrm.Page.getAttribute("parentcustomerid").getValue()[0].id;
 var strVar = "";
 strVar += "<filter type=\"and\" >";
 strVar +=" <condition attribute=\"statecode\" operator=\"eq\" value=\"0\" />"
 strVar += " <condition attribute=\"parentcustomerid\" 
               operator=\"eq\" value=\"" + parentCustomer + "\" \/>";
 strVar += " <\/filter>";
 strVar += "";
 RelatedContactLookup.addCustomFilter(strVar, "contact");
 }
 })

 

Get the company id from Xrm.Page library  and passes in fetchXML for search criteria.

Our filter criteria code is done but for triggering the above code, we need to attach click function to the subgrid add button, like in JavaScript below :

var RelatedContact_Button = window.parent.document.getElementById("RelatedContact_addImageButton");
 RelatedContact_Button.addEventListener("click", function ()
 {
 ///put your filter code here  
 }

Here is complete code for JavaScript web resource that we need to add on a contact form.

You can also write this code inside a function and call it onload, here I am using self invoking JS function.

(function ()
{
 setTimeout(function ()
 {
 var RelatedContact_Button = window.parent.document.getElementById("RelatedContact_addImageButton");
 RelatedContact_Button.addEventListener("click", function ()
 {
 var RelatedContact = Xrm.Page.getControl('RelatedContact');
 var RelatedContactLookup = RelatedContact.$0_3.$1m_4.$O_4.$38_3.$3_6;
 RelatedContactLookup.addPreSearch(function ()
 {
 if (Xrm.Page.getAttribute("parentcustomerid").getValue())
 {
 var parentCustomer = Xrm.Page.getAttribute("parentcustomerid").getValue()[0].id;
 var strVar = "";
 strVar += "<filter type=\"and\" >";
 strVar += " <condition attribute=\"parentcustomerid\" operator=\"eq\" value=\"" + parentCustomer + "\" \/>";
 strVar += " <\/filter>";
 strVar += "";
 RelatedContactLookup.addCustomFilter(strVar, "contact");
 }
 })
 })
 }, 2000)
}())

You can also download from here.

animation

 

That’s it , Please try and comment below If you found any problem.

Hope it’ll help someone.

 

Note: This is an unsupported way if you really want to go with a supported way then use custom web resource HTML for showing your grid with filter criteria.

Update FetchXml and Grid layout of Entity View using C# in CRM

Update FetchXml and Grid layout of Entity View using C# in CRM

In this post, I am going to tell you how we can update Entity view programmatically using c#.

Before starting let’s cover entity view and their query types.

What is Entity View ?

Entity views are special SavedQuery that retrieve data by using a specific filter. They also contain information about how the data in the view should be displayed in the application.

An Entity view is different from a UserQuery. A user query, called a Saved view in the application, is owned by an individual user, can be assigned and shared with other users, and can be viewed by other users depending on the query’s access privileges.

Let’s create a new view in account entity i.e. My Custom Accounts

1

4

Here is default Grid Layout and FetchXml of this view

2

5.PNG

Now we write some code for getting fetchXml and layoutXml for this view.

 

QueryExpression qe = new QueryExpression(“savedquery“);
qe.Criteria.AddCondition(“returnedtypecode”, ConditionOperator.Equal, “account“);
qe.Criteria.AddCondition(“name”, ConditionOperator.Equal, “My Custom Accounts“);
qe.ColumnSet = new ColumnSet(true);
var viewData= _service.RetrieveMultiple(qe);

 

For our demo purpose we’re trying to add Account Number in FetchXml.

You can also add filter or some complex query which we want to add but can’t add using Advanced find.

 

//Update fetchxml of view
XmlDocument xml1 = new XmlDocument();
xml1.LoadXml(viewData.Entities[0][“fetchxml”].ToString());
XmlNode entityNode= xml1.SelectSingleNode(“//entity”);
var newAttrnode= xml1.CreateElement(“attribute”);
var nameAttribute = xml1.CreateAttribute(“name”);
nameAttribute.Value = “accountnumber”;
newAttrnode.Attributes.Append(nameAttribute);
entityNode.AppendChild(newAttrnode);
dar.Entities[0][“fetchxml”] = xml1.OuterXml;

 

Using below code ,we’re trying to add accountnumber column in our view grid.

 

//Update Gridxml of view
XmlDocument gridxml = new XmlDocument();
gridxml.LoadXml(viewData.Entities[0][“layoutxml”].ToString());
XmlNode rowNode = gridxml.SelectSingleNode(“//row”);
var newrowAttrnode = gridxml.CreateElement(“cell”);
var accountname = gridxml.CreateAttribute(“name”);
accountname.Value = “accountnumber”;
newrowAttrnode.Attributes.Append(accountname);
var width = gridxml.CreateAttribute(“width”);
width.Value = “150”;
newrowAttrnode.Attributes.Append(width);
rowNode.AppendChild(newrowAttrnode);
dar.Entities[0][“layoutxml”] = gridxml.OuterXml;
_service.Update(dar.Entities[0]);

 

//Publish Account Entity
PublishXmlRequest puxml = new PublishXmlRequest()
{
ParameterXml = “<importexportxml><entities><entity>account</entity></entities></importexportxml>”
};
_service.Execute(puxml);

 

That’s it, our custom view successfully updated with Account Number Column. 🙂

7

6

Thanks for visiting my blog.

Do some creative stuff in CRM  !!!  🙂

 

 

 

 

Add Form Library on CRM Form using C# or javascript

Add Form Library on CRM Form using C# or javascript

Hello Everyone, Today I am going to tell how we can add form library on CRM form using C# or  JavaScript.

We want to add library on account form so for that I created one JavaScript web resources e.g.  am_sample for our demo purpose or you can add existing JS from CRM.

2

After that we add alert functionality inside this so we’ll found ourselves that our code is executed on onload of account form. We put our code inside self invoking function so it will show alert dialog on load of account form.(By using self invoking function we don’t need to define any function in Event Handlers)

here is demo link for self invoking function in JavaScript.

http://embed.plnkr.co/TSEL09/

1

3

In below screen we don’t see any library added on account form let’s write some code for adding file here 🙂

4

 

C# Code :

First we add one function for get form xml in which we passes logical name of Account entity as its parameter.

 

public Entity GetForm(string EntityLogicalname)
{
try
{
QueryExpression query = new QueryExpression(“systemform”)
{
Distinct = false,
ColumnSet = new ColumnSet(new[] { “name”, “formxml”, “objecttypecode” }),
Criteria =
{
Filters =
{
new FilterExpression
{
FilterOperator = LogicalOperator.And,
Conditions =
{
new ConditionExpression(“objecttypecode”, ConditionOperator.Equal, EntityLogicalname),
new ConditionExpression(“type”, ConditionOperator.Equal, 2),
new ConditionExpression(“iscustomizable”, ConditionOperator.Equal, true),
new ConditionExpression(“formactivationstate”, ConditionOperator.Equal, 1)
}
}
}
}
};
return Service.RetrieveMultiple(query).Entities.FirstOrDefault();
}
catch (Exception)
{
throw;
}
}

This function return Entity with formxml attribute.

After that we need to add one more function that change current formxml of Account entity (which return from above function) with new JS that we need to add.

Below is the description of what we’re going to perform in our next funtion :

  • First we select Form node, and formLibraries inside it.
  • If formLibraries not found then we’ll create formLibraries xml node.
  • If formLibraries found then we’ll create Library element inside it with name, libraryUniqueId attributes.
  • After that we append this Library tag into formLibraries and update formxml attribute of Entity.

 

public void AddLibrary(Entity form, string libraryName, bool addFirst)
{
var formXml = form.GetAttributeValue<string>(“formxml”);
var formDoc = new XmlDocument();
formDoc.LoadXml(formXml);
var formNode = formDoc.SelectSingleNode(“form”);
if (formNode == null)
{
throw new Exception(“Expected node \”formNode\” was not found”);
}
var formLibrariesNode = formNode.SelectSingleNode(“formLibraries”);
var eventLibrary = formNode.SelectSingleNode(“events”);
if (formLibrariesNode == null)
{
formLibrariesNode = formDoc.CreateElement(“formLibraries”);
formNode.AppendChild(formLibrariesNode);
}
if(libraryName!=null)
{
var libraryNode = formLibrariesNode.SelectSingleNode(string.Format(“Library[@name='{0}’]”, libraryName));
if (libraryNode != null)
{
Console.WriteLine(“This library is already included in this form”);
}
var nameAttribute = formDoc.CreateAttribute(“name”);
var libraryUniqueIdAttribute = formDoc.CreateAttribute(“libraryUniqueId”);
nameAttribute.Value = libraryName;
libraryUniqueIdAttribute.Value = Guid.NewGuid().ToString(“B”);
libraryNode = formDoc.CreateElement(“Library”);
if (libraryNode.Attributes != null)
{
libraryNode.Attributes.Append(nameAttribute);
libraryNode.Attributes.Append(libraryUniqueIdAttribute);
}
if (formLibrariesNode.ChildNodes.Count > 0 && addFirst)
{
formLibrariesNode.InsertBefore(libraryNode, formLibrariesNode.FirstChild);
}
else
{
formLibrariesNode.AppendChild(libraryNode);
}
}
form[“formxml”] = formDoc.OuterXml;
Service.Update(form);
}

 

After that we’ll publish Account Entity.

public void PublishForm(Entity en)
{
var request = new PublishXmlRequest { ParameterXml = String.Format(“<importexportxml><entities><entity>{0}</entity></entities></importexportxml>”, en.GetAttributeValue<string>(“objecttypecode”)) };
Service.Execute(request);
}

 

Here is calling code

CrmConnection con = CrmConnection.Parse(“Url = https://xxxx.crm5.dynamics.com; Username=xyz@abc.onmicrosoft.com; Password=xyzxyz”);
IOrganizationService Service = new OrganizationService(con);
ScriptManage sc = new ScriptManage(Service);
var EntityName = sc.GetForm(“account”);
sc.AddLibrary(EntityName,”am_sample”, false);
sc.PublishForm(EntityName);

Now you can see JS file is added on account form!! 🙂

For more info about C# code, go through below link.

https://github.com/MscrmTools/XrmToolBox/blob/master/Plugins/MsCrmTools.FormRelated/FormLibrariesManager/AppCode/FormManager.cs

 

 

 

5

8

JS Code :

For using below code we need to add these file references.

  1. ClientGlobalContext.js.aspx
  2. jquery.min.js
  3. Sdk.Soap.min.js
function Getformxml  (EntityLogicalname) {
Sdk.jQ.setJQueryVariable($);
var SystemForm = new Sdk.Query.QueryExpression(“systemform”);
SystemForm.getDistinct();
SystemForm.addColumn(“name”);
SystemForm.addColumn(“formxml”);
SystemForm.addColumn(“objecttypecode”);
Sdk.Query.FilterExpression(Sdk.Query.LogicalOperator.And);
SystemForm.addCondition(“systemform”, “objecttypecode”, Sdk.Query.ConditionOperator.Equal, new Sdk.Query.Strings([EntityLogicalname]))
SystemForm.addCondition(“systemform”, “type”, Sdk.Query.ConditionOperator.Equal, new Sdk.Query.Ints([2]))
SystemForm.addCondition(“systemform”, “iscustomizable”, Sdk.Query.ConditionOperator.Equal, new Sdk.Query.Booleans([true]))
SystemForm.addCondition(“systemform”, “formactivationstate”, Sdk.Query.ConditionOperator.Equal, new Sdk.Query.Ints([1]))
FormxmlQuery = SystemForm;
return Sdk.jQ.retrieveMultiple(SystemForm).then(
function (ec) {
formRequestSuccesscall(ec);
})
new ErrorHandler(“An error occured “).getError(err);
}
function formRequestSuccesscall  (data) {
var $xml, $formtagxml, x = true, xml2 = ”;
if (data.getEntities().getCount() > 0) {
data.getEntities().forEach(function (n, i, arr) {
if (n.view().attributes[‘formxml’])
$xml = $($.parseXML(n.view().attributes[‘formxml’].value));
$formtagxml = $xml.find(“formLibraries”);
$($formtagxml).find(‘Library’).each(function () {
$.each(this.attributes, function (i, attrib) {
if (attrib.name == “name”) {
if (attrib.value == “Content_/scripts/wfHover.js”) {
console.log(‘already add on form!!’);
x = false;
}
}
});
});
if (x) {
if ($formtagxml.length == 0) {
xml2 += ‘<formLibraries><Library name=“am_sample” libraryUniqueId=”‘ + guid() + ‘” /></formLibraries>’;
$formtagxml = $($.parseXML(xml2)).find(“formLibraries”);
$xml.find(“form”).append($($.parseXML(xml2)).find(“formLibraries”));
} else {
$formtagxml.append(‘<Library name=“am_sample” libraryUniqueId=”‘ + guid() + ‘” />’)
}
var oSerializer = new XMLSerializer();
//clone.attributes[‘formxml’].value = oSerializer.serializeToString($xml[0]);
n.setValue(“formxml”, oSerializer.serializeToString($xml[0]));
Sdk.jQ.update(n).then(
function (id) {
// console.log(id);
publishXML(entityLogicalname);
})
}
})
}
}
function publishXML (entityName) {
var context = Xrm.Page.context;
var serverUrl = (context.getServerUrl) ? context.getServerUrl() : context.getClientUrl();
var Publishxml = “”;
Publishxml += “<s:Envelope xmlns:s=\”http:\/\/schemas.xmlsoap.org\/soap\/envelope\/\”>”;
Publishxml += ” <s:Body>”;
Publishxml += ” <Execute xmlns=\”http:\/\/schemas.microsoft.com\/xrm\/2011\/Contracts\/Services\” xmlns:i=\”http:\/\/www.w3.org\/2001\/XMLSchema-instance\”>”;
Publishxml += ” <request i:type=\”b:PublishXmlRequest\” xmlns:a=\”http:\/\/schemas.microsoft.com\/xrm\/2011\/Contracts\” xmlns:b=\”http:\/\/schemas.microsoft.com\/crm\/2011\/Contracts\”>”;
Publishxml += ” <a:Parameters xmlns:c=\”http:\/\/schemas.datacontract.org\/2004\/07\/System.Collections.Generic\”>”;
Publishxml += ” <a:KeyValuePairOfstringanyType>”;
Publishxml += ” <c:key>ParameterXml<\/c:key>”;
Publishxml += ” <c:value i:type=\”d:string\” xmlns:d=\”http:\/\/www.w3.org\/2001\/XMLSchema\”>&lt;importexportxml&gt;&lt;entities&gt;&lt;entity&gt;” + entityName + “&lt;\/entity&gt;&lt;\/entities&gt;&lt;\/importexportxml&gt;<\/c:value>”;
Publishxml += ” <\/a:KeyValuePairOfstringanyType>”;
Publishxml += ” <\/a:Parameters>”;
Publishxml += ” <a:RequestId i:nil=\”true\” \/>”;
Publishxml += ” <a:RequestName>PublishXml<\/a:RequestName>”;
Publishxml += ” <\/request>”;
Publishxml += ” <\/Execute>”;
Publishxml += ” <\/s:Body>”;
Publishxml += “<\/s:Envelope>”;
var req = new XMLHttpRequest();
req.open(“POST”, serverUrl + “/XRMServices/2011/Organization.svc/web”, true);
// Responses will return XML. It isn’t possible to return JSON.
req.setRequestHeader(“Accept”, “application/xml, text/xml, */*”);
req.setRequestHeader(“Content-Type”, “text/xml; charset=utf-8”);
req.setRequestHeader(“SOAPAction”, “http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute&#8221;);
req.onreadystatechange = function () {
if (req.readyState === 4) {
if (req.status === 200) {
}
} else {
alert(“An error occurred ” + req.statusText);
}
}
req.send(Publishxml);
}

here is caling code for JS

Getformxml  (“account”);

 

Hope you will like this blog and Thank you for visiting my blog 🙂