Dynamics 365 – Filter lookup with FetchXML (and how to deal with invalid XML format)

By Ritchey Hazeu

In some situations you can’t use the standard filtering options Dynamics 365 has to offer. For example when you use the same entity twice on a form. And you would like to lookup a new field and only filter it on the second entity.

In these cases you can use Javascript to Filter the Lookup yourself. Let’s say we are using the Order entity and want to filter a new field, let’s say Contact and filter it only on the lookup to Order on the Order form, not to the Order itself.

We will create the webresource and place it on OnChange of the Lookup. Don’t forget to check both boxes:

And how does the Javascript looks like?

function filterContactLookup(executionContext){

var formContext = executionContext.getFormContext(); // get the form context

if(formContext.getAttribute("new_orderid") != null) {

var orderField = formContext.getAttribute("new_orderid").getValue();
var orderFieldID = orderField[0].id;
var orderName = orderField[0].name;

formContext.getControl("new_contact").addPreSearch(function (){

    var fetchQuery = "<filter type='and'><condition attribute='new_orderid' operator='like' uiname='" + orderName + "' uitype='salesorder' value='" + orderFieldID + "' /></filter>";

    formContext.getControl("new_contact").addCustomFilter(fetchQuery);
});

        formContext.getControl("new_contact").removePreSearch(function(){

        var fetchQueryRemove = ""

        formContext.getControl("new_contact").addCustomFilter(fetchQueryRemove);

    });

}
}

This piece of code work fine when there are no special characters being used (for example the & character). And it happens quite often that the & character is being used in a name. I’ve tried all kinds of different options to fix this, like:

var fetchQuery = fetchQuery.replace(“&”, “&amp”);

fetchQuery = “?fetchQuery=” + encodeURIComponent(fetchQuery);

All different Xrm.Encoding options as noted on https://docs.microsoft.com/hr-hr/powerapps/developer/model-driven-apps/clientapi/reference/xrm-encoding but without success

and more options which works perfectly in C#….

Gladly for me there was a much easier option, and that was simply to remove the uiname from the fetchxml, and it kept working!

function filterContactLookup(executionContext){

var formContext = executionContext.getFormContext(); // get the form context

if(formContext.getAttribute("new_orderid") != null) {

var orderField = formContext.getAttribute("new_orderid").getValue();
var orderFieldID = orderField[0].id;
var orderName = orderField[0].name;

formContext.getControl("new_contact").addPreSearch(function (){

    var fetchQuery = "<filter type='and'><condition attribute='new_orderid' operator='like' uitype='salesorder' value='" + orderFieldID + "' /></filter>";

    formContext.getControl("new_contact").addCustomFilter(fetchQuery);
});

        formContext.getControl("new_contact").removePreSearch(function(){

        var fetchQueryRemove = ""

        formContext.getControl("new_contact").addCustomFilter(fetchQueryRemove);

    });

}
}

It took me a few hours to notice this…. So hopefully it will save you some time.

And please let me know if there are other options, for example when you don’t got the GUID and only the uiname.

Dynamics 365 – Javascript – formContext – Lock form & fields after subgrid is loaded

By Ritchey Hazeu

Hi! In some scenario’s you would like to know if there are any related records and based on this condition, lock a form or any fields (or do any other action!).

First you would like to count the related records which are present in a subgrid:

var gridContext = formContext.getControl("Gridname");// get the grid context

var count = formContext.getControl("Gridname").getGrid().getTotalRecordCount();

And you would like to run this code after the Subgrid is loaded. So you will use the gridContext and let it run on load (apart from the form).

gridContext.addOnLoad(GridOnloadFunction);

How does this code look when you would like to lock fields?

function lockFieldsOnCount(executionContext) {

var formContext = executionContext.getFormContext(); // get the form context
var gridContext = formContext.getControl("Gridname");// get the grid context
    
var GridOnloadFunction = function () { 
var count = formContext.getControl("Gridname").getGrid().getTotalRecordCount();

if (count > 0){
                
var lockAccount = formContext.getControl("field1").setDisabled(true);

var lockContact = formContext.getControl("field2").setDisabled(true);

}

else {
                
var lockAccount = formContext.getControl("field1").setDisabled(false);

var lockContact = formContext.getControl("field2").setDisabled(false);
}
	
};
    gridContext.addOnLoad(GridOnloadFunction); //run onload of subgrid
}

How does this code look when you would like to lock a form?

function lockFieldsOnCount(executionContext) {

var formContext = executionContext.getFormContext(); // get the form context
var gridContext = formContext.getControl("Gridname");// get the grid context
    
var GridOnloadFunction = function () { 
var count = formContext.getControl("Gridname").getGrid().getTotalRecordCount();

if (count > 0){
                
formContext.data.entity.attributes.forEach(function (attribute, index) {    
var control = Xrm.Page.getControl(attribute.getName());
if (control) {
control.setDisabled(true)
	
}
});
	
else {
formContext.data.entity.attributes.forEach(function (attribute, index) {    
var control = Xrm.Page.getControl(attribute.getName());
if (control) {
control.setDisabled(false)
	
}
});
}
	
};
   gridContext.addOnLoad(GridOnloadFunction); //run onload of subgrid
}

Javascript in the Business Process Flow: header_process_ and postfixes

By Robin Pietens

Some things you run into make you go: ‘Oh yeah, totally forgot about that’. I hope most of you don’t have this happen all that often. I ran into one of them a few days ago and thought I’d share.

I was adding a custom filter to a lookup-view in the business process flow, as you can’t change the view in version 8.2 of Dynamics 365 via normal configuration. I ran into a problem where the filter worked on some fields in the flow, but not all. After spending quite some time on this I came to the below conclusions.

When customizing the business process flow via Javascript, you have to take into account that Dynamics adds ‘header_process_’ as a prefix to your fieldname. In addition, there is something else Dynamics does that is less obvious, and maybe less known as it won’t occur all the time. Dynamics adds a postfix of _X to each field that’s repeated in the same business process flow. X here is the next occurrence, starting with 1. The reason this is hard to spot is that it happens all the way at the end of the schema name of a field. Even if you use a tool like the Power Pane (which I would recommend), you probably won’t see the postfix in the schame name unless you hover over it to appear in full.

In my specific case, I work with a branched business process flow in which two similar stages exist, but you only ever see one of them. The invisible stages of the business process flow are also taken into account when the postfixes are appended. I didn’t know about this, and didn’t look closely enough at the exact schema names!

Another reason the search can take so long is that your code doesn’t actually give any errors. It simply doesn’t execute!

Hope this helps some of you out.

Rewriting Xrm.Page

By Robin Pietens (Dynamics 365 Consultant @ Capgemini)
 
For those that have not yet heard: Microsoft has decided to deprecate the use of Xrm.Page.

Microsoft did indicate their understanding that this feature is used a lot, so they will retain compatibility with it for quite some time. However, new functions should be written in a way that is as future-proof as possible right? For some reason I was unable to easilly find a nice overview of what we should change to deal with this deprecation, and I decided to do something about that.
 

So where we used to write:

function doSomething(){
     var some = Xrm.Page.getAttribute("new_some").getValue(); 
     var action = Xrm.Page.getAttribute("new_action").getValue(); 
     console.log(some + " " + action); 
}

 

We should now do something else, and write:

function doSomething(executionContext){
     var formContext = executionContext.getFormContext(); // get formContext 
     // use formContext instead of Xrm.Page 
     var some = formContext.getAttribute("new_some").getValue(); 
     var action = formContext.getAttribute("new_action").getValue(); 
     console.log(some + " " + action); 
}

 

The other thing to do is to check the box of ‘pass execution context as first parameter’ when setting up the function on the form. If you, like me, make parameters of just about anything, simply pass them with comma’s separated from the executioncontext. Then put everything except the executioncontext in the box as comma separated parameters that will be passed to the function:
 


 

And the function itself will look like this:

function doSomething(executionContext, firstparam, secondparam){
     var formContext = executionContext.getFormContext(); // get formContext
     var some = formContext.getAttribute(firstparam).getValue(); 
     var action = formContext.getAttribute(secondparam).getValue(); 
     console.log(some + " " + action); 
}

 

Any new Scripts that you write should conform to the standard outlined in this blogpost. When making changes to existing libraries, it’s a good idea to take it into account as well. Talk the costs and benefits through with your customer, to keep them as upgrade-proof as possible!

If you want to stay up-to-date with features like this one, keep an eye out for new blogposts and follow us on LinkedIn.

For (hard to find) Microsoft references see: https://docs.microsoft.com/en-us/dynamics365/customer-engagement/developer/clientapi/clientapi-form-context