A cool feature of the 2011 CRM version was the possibility to have multiple forms for the same entity. That feature is awesome but it has one drawback – it’s not possible to create some kind of dependency between the form to use in the context of data. Among developers, there were a few ways to address this scenario.
The first way I knew of was JavaScript that was executed during the form load. This method checked a record’s data and switched the form using formSelector – an example from Magnetism Solution. That approach worked, but it was a bit confusing because of the form “blink” that was caused by the reload.
The second way I knew is the “Plugin” way – the form to be shown is set in the code behind (the scenes? In the background?). All credit goes to Gonzalo Ruiz, who came up with this wonderful post. Unfortunately, this way doesn’t work for 2015 and any later version.
So how should one address this requirement nowadays?
Video
Scenario
There are 3 forms configured for the “Account” entity in CE – “Default”, “Customer” and “Partner”. When a user opens an account with “Relationship Type” that is equal to “Customer”, he should be navigated to the “Customer” form. When a user opens an account with “Relationship Type” that is equal to “Partner” he should be navigated to the “Partner” form. In all other situations, the “Default” form should be presented.
JavaScript
Let’s start with JavaScript. It’s self-explanatory:
var AB = AB || {}; AB.AccountRibbon = (function(){ function openRecord(recordId) { //Setting formId to "Default" var formId = "8448B78F-8F42-454E-8E2A-F8196B0419AF"; //Getting account's "Relationship Type" field Xrm.WebApi.retrieveRecord("account", recordId, "?$select=customertypecode").then( function(result){ var customerTypeCode = result.customertypecode; switch(customerTypeCode) { case 3: //Customer formId = "B1860C41-4457-4E87-BC49-9C2F8D8B40E3"; break; case 5: //Partner formId = "BF4EC6AC-E250-420E-8118-E1FB676351DA"; break; } //Opening account with formId predefined Xrm.Navigation.openForm({ entityName: "account", entityId: recordId, formId: formId }); }, function(error){ //If anything goes wrong log the error console.log(error); //and open "by default" form Xrm.Navigation.openForm({ entityName: "account", entityId: recordId, formId: formId }); }); } return { OpenRecord: openRecord, }; })();
Ribbon Changes
Create a solution and add the “Account” entity. Open “Ribbon Workbench” and load your solution. Add the following command to the ribbon:
The Id of the command has to be exactly “Mscrm.OpenRecordItem”. As an action, choose JavaScript and point to the WebResource you created in the previous step, point to the proper function, and add “FirstSelectedItemId” as a parameter for the function.
The functionality will not work as expected without a button to be added to the ribbon but I don’t want this button to be visible on the ribbon so I add “Enable Rule” that will always return false and the button will not be shown. Here is a screenshot of “Enable Rule”:
Once the command is added – add the button with the same id – exactly “Mscrm.OpenRecordItem” and use the command you created on the previous step as a command for this button:
Click the “Publish” button to import changes to the instance. Now you can open CE, navigate to the accounts grid, and test how it works. If you completed everything the right way you will get everything working fine.
Great Approach, thanks.
You mention the old javascript blink of web client.
It didn’t look like the UCI solution suffered from that issue in the video?
Does the above present a form switcher that doesn’t suffer from the reload blink now?
David,
The trick is that this approach doesn’t use “FormSwitcher” approach at all so the form doesn’t blink. Script navigates user to the proper form in the first place.
Andrew
Very nice article Andrew.I really like your ideas.
I have one question here .Is the supported to override Mscrm.AddNewRecordFromSubGridStandard command also to open new record in modal form.
Bhuvita,
I haven’t tried that but I believe if you add that command and command to the subgrid of the entity with the same Mscrm.OpenRecordItem id it should override the standard way and you will be able to open the record in the modal form.
Andrew
Great video Andrew, really helpful!
Martin,
Welcome! I’m glad you liked it!
Andrew
Hi Andrew, When I tried with adding the button in either Home or Subgrid, it worked great but as soon as its added for both, it works for one and not for the other. Have you tried adding it for both? My requirement is that I need to open it from the main view as well as from the subgrid. Any help would be greatly appreciated. Cheers, Krutika
Krutika,
I can confirm that I can replicate your behavior. I would recommend to get in touch with Microsoft and ask for help.
Andrew
I believe it’s due to the Ribbon Workbench using the same value for CustomUIAction ID and Button ID. If you manually edit the RibbonDiffXml in the customizations.xml according to the Microsoft article here, you can make it work for both instances. I added a console.log() line to alert when the custom method is called and it fired from both the HomepageGrid and the SubGrid contexts.
https://docs.microsoft.com/en-us/powerapps/developer/model-driven-apps/override-default-open-behavior-grids
Andy,
Thanks for sharing!
Andrew
I am trying to do the same thing with the HomePageGrid ribbon and Subgrid ribbon to display different forms. When I set using RibbonWorkbench (create a button with hidden enable rule and point to the same webresource and same command) and publish only the Subgrid will work. If I remove the subgrid button then the HomePageGrid will work. Can you provide a sample of what your XML looked like in your RibbonDiffXml section? In my case the same webresource would be executed. The Microsoft example in override-default-open-behavior-grids doesn’t provide a sample showing both situations (I have alot of other custom buttons in my RibbonDiffXml as well – so copy/paste as the article suggests is a non-starter).
var RN = RN || {};
RN.ActionRibbon = (function(){
function openRecord(recordId) {
//Setting formId to “Default”
var formId = “0A706BAB-B2B0-EA11-A812-001DD83096F2”; //main form
//Get the record
Xrm.WebApi.retrieveRecord(“brm_action”, recordId).then(
function(result){
var Id = result.RecordId
var pageInput = {
pageType: “entityrecord”,
entityName: “brm_action”,
entityId: recordId
};
var navigationOptions = {
target: 2,
height: { value: 100, unit: “%” },
width: { value: 50, unit: “%” },
position: 1
};
Xrm.Navigation.navigateTo(pageInput, navigationOptions).then(
function success() {
// Run code on success
},
function error() {
// Handle errors
}
);
},
function(error){
//If anything goes wrong log the error
console.log(error);
//and open “by default” form
Xrm.Navigation.openForm({
entityName: “brm_action”,
entityId: recordId,
formId: formId
});
});
}
return {
OpenRecord: openRecord,
};
})();
Hello,
I see the code, how can I help you?
Andrew
Sorry Andrew, I think some of my message was cut off.
I was able to modify your directions above to use the navigateTo function instead of OpenForm so that the new modal forms could be used. The button I added was on the subgrid instead of the home page. It worked great!
However, I did notice that when the modal form window closes, the subgrid doesn’t update until the user manually clicks refresh on the main form ribbon.
Do you know of or recommend a way to wire a refresh command to avoid the user having to manually refresh the page?
scenario
1. Open form
2. On the form, there is a subgrid
3. Click a record in the subgrid to open the modal form (this works great using your modified code)
4. The user makes a change to the record in the modal form, and then closes the form (“e.g. save and close”)
What is happening:
a) The user doesn’t see the changes he made reflected in the subgrid until he hits refresh
What I’m trying to do:
b) After the dialog closes the form, the subgrid and/or the parent form refreshes so that the update can be seen.
Generally speaking Xrm.Navigation.navigateTo returns the promise that is resolved after record is created/updated. So to implement your scenario you can do following:
1. In the command add new crm parameter and pass the grid inside – https://butenko.pro/2012/11/01/ms-crm-2011-how-to-refresh-associated-or-subgrid-from-ribbon-button/
2. Once the promise is resolved – refresh the grid.
Andrew
Andrew that worked like a charm! Thank you so much for your help!
I’m glad it worked!
Hello NewCombR, Im tryng to do the same as you but I cannot make it work, I don’t know where I’m missing something, could you please help somehow? I have i all set up but when I click on subrid record nothing happens I t doesn’t even opens the regular form so I think something might be wrong or missing in the steps I followed throw Andrews post and your code! This is my code copied from yours: I dont understand from where does it get de recordId …
var RN = RN || {};
RN.modalVenta = (function ()
{
function openRecord(recordId)
{
//Setting formId to “Default”
var formId = “78D55690-58A8-42EC-A819-7EE445B855FA”; //main form
//Getting the record
Xrm.WebApi.online.retrieveRecord(“axx_ventadirecta”, recordId).then(
function (result)
{
var Id = result.RecordId
var pageInput = {
pageType: “entityrecord”,
entityName: “axx_ventadirecta”,
entityId: recordId
};
var navigationOptions = {
target: 2,
height: {
value: 100,
unit: ” % ”
},
width: {
value: 50,
unit: ” % ”
},
position: 1
};
Xrm.Navigation.navigateTo(pageInput, navigationOptions).then(
function success()
{
// Run code on success
},
function error()
{
// Handle errors
});
},
function (error)
{
//If anything goes wrong log the error
console.log(error);
//and open “by default” form
Xrm.Navigation.openForm(
{
entityName: “axx_ventadirecta”,
entityId: recordId,
formId: formId
});
});
}
return {
OpenRecord: openRecord,
};
})();
Matias,
So what exactly are you trying to implement?
Remove line with code var Id = result.RecordId – it’s useless.
Andrew
Andrew, beautiful article. I like all your ideas present on you tube.
Sorry, but I am bit confused with the way your logic works? From where script behind button is getting called and how? I have written it on form load but as you said this approach has “blink” issue. Please explain.
Hello,
When you register command this way platform uses it instead of the standard code used to open the form.
Andrew
Thanks for above explanation.
I have implemented in my instance. I am able to navigate to correct form, but once I am on any form, I am not able to see option to navigate to other records directly from forms. Even in your you tube video, I am not able to see the button to navigate to other records. Is this a bug?
Hello,
What do you mean with the button to navigate to other records? Can you please be more specific?
Andrew
Hi Andrew,
I don’t know how to attach images here.
If you navigate to any record from home page view, form will have button on command ribbon before standard buttons which is used to navigate to other records directly from form.
Ok. You meant the quick navigation between records that are available in the grid. I don’t know what it’s not there but it seems that this is the side affect of this enhancement.
Andrew
Yes correct. This is because we are using navigateTo method.
It might be important to note that there are other ways to navigate to a record (such as from a lookup link), and you’ll probably want to include the “old” way of navigating to the correct form onLoad in case one of these other methods is used.
Hello, I’m trying to do the same as you but I its not working, I copied your code and edited for me but i double click o the subgrid record and doesn`t do anything. I checked the code cause when i copied form your i had to edit double commas, and aldo i changed the retrieve like this:
I also followed up Andrews post step by step. I think i got it right but there must be some error somwhere…
var RN = RN || {};
RN.modalVenta = (function ()
{
function openRecord(recordId)
{
//Setting formId to “Default”
var formId = “78D55690-58A8-42EC-A819-7EE445B855FA”; //main form
//Getting the record
Xrm.WebApi.online.retrieveRecord(“axx_ventadirecta”, recordId).then(
function (result)
{
var Id = result.RecordId
var pageInput = {
pageType: “entityrecord”,
entityName: “axx_ventadirecta”,
entityId: recordId
};
var navigationOptions = {
target: 2,
height: {
value: 100,
unit: ” % ”
},
width: {
value: 50,
unit: ” % ”
},
position: 1
};
Xrm.Navigation.navigateTo(pageInput, navigationOptions).then(
function success()
{
// Run code on success
},
function error()
{
// Handle errors
});
},
function (error)
{
//If anything goes wrong log the error
console.log(error);
//and open “by default” form
Xrm.Navigation.openForm(
{
entityName: “axx_ventadirecta”,
entityId: recordId,
formId: formId
});
});
}
return {
OpenRecord: openRecord,
};
})();
Hello Andrew, i did post some question replying on another post but i cannot see it. Could you help me?, thanks.
Matias,
For some reason your questions went to SPAM. I whitelisted it so now I will be able to answer.
Andrew
Hello Andrew, no worries, I’ va managed to solved my problem, thanks! Now its working, but know I have another issue, I put a custom button to the form, for save and close it´s a custom button because I need to run a function before the users leaves the form. But formContext.data.entity.save(“saveandclose”); Its not working, it doesn’t close the modal dialog. do you know how to achieve this? some workaround,? Even thow I need to refresh parent window If the user leaves the dialog form by clicking on the X to close the modal form…or hide de “X” button but I think this can’t be done rigth?
Matias,
It’s a wild shot but you could try it. Try to call window.close after your formContext.data.entity.save. It works for custom html webresource that are called using Xrm.Navigation so I assume it could work for forms as well.
Thanks,
Andrew
Andrew, unfortunately it doesn’t works this works: window.history.go(-1); but it goes back, not what Im looking for…frustrated! I think if I d like to control does event I should go for a custom modal dialog right? I think there is no other alternative to this require.
Hello again Andrew!, I need some help, i need to add to your code the posbility to get a value from a related entity, i generated the code to get the value i need to set the form but i don´t know where to put it, i think i have to replace the part of you code : <<<>>>>
and replace it with this but I m a bit lost:
var formContext = executionContext.getFormContext();
var idCampania = formContext.getAttribute(“axx_campanaorigen”).getValue()[0].id;
var idCampaniaSpl = idCampania.replace(‘{‘, ”).replace(‘}’, ”);
//var currentForm = formContext.ui.formSelector.getCurrentItem();
var req = new XMLHttpRequest();
req.open(“GET”, Xrm.Page.context.getClientUrl() + “/api/data/v9.1/campaigns(“+ idCampaniaSpl +”)?$select=typecode”, true);
req.setRequestHeader(“OData-MaxVersion”, “4.0”);
req.setRequestHeader(“OData-Version”, “4.0”);
req.setRequestHeader(“Accept”, “application/json”);
req.setRequestHeader(“Content-Type”, “application/json; charset=utf-8”);
req.setRequestHeader(“Prefer”, “odata.include-annotations=\”*\””);
req.onreadystatechange = function()
{
if (this.readyState === 4)
{
req.onreadystatechange = null;
if (this.status === 200)
{
var result = JSON.parse(this.response);
var typecode = result[“typecode”];
var typecode_formatted = result[“typecode@OData.Community.Display.V1.FormattedValue”];
} else
{
Xrm.Utility.alertDialog(this.statusText);
}
var tipoCampania = typecode_formatted;
}
};
req.send();
Matias,
So what is the expected result and what doesn’t work?
Andrew
Hello.
Does the function name depends of the entity name? “AB.AccountRibbon”. In my case the entity name is msdyn_projecttask
Mauricio,
It doesn’t depend. I use that naming just for self-documentation purposes.
Andrew
Hi Andrew!
Nice post! I ‘m working in CRM 365 V9 onpremise classic view. I need to run a js fuction with some logic before a contact record is open.
I can use Mscrm.OpenRecordItem for that. It will work in onpremise?
Hello Oscar,
I’m not sure that this approach would work in on-prem but it’s up to you to check. But for the online, I believe that’s the way to go.
Thanks,
Andrew
Дякую Andrew for your answer! I already checking if it’s will working for on-prem. 🙂
Hi Andrew,
The below code have used in online crm 9.1 & used in ribbon workbench too.but still not working
var AB = AB || {};
AB.CaseRibbon = (function(){
function openRecord(recordId) {
//Setting formId to “Default”
var formId = “B57FE4BA-140C-4F92-9653-E5951EED56D9”; //GE
Xrm.WebApi.online.retrieveRecord(“incident”, “recordId”, “?$select=_mdc_interactiontype_value”).then(
function success(result) {
var _mdc_interactiontype_value = result[“_mdc_interactiontype_value”];
var _mdc_interactiontype_value_formatted = result[“_mdc_interactiontype_value@OData.Community.Display.V1.FormattedValue”];
var _mdc_interactiontype_value_lookuplogicalname = result[“_mdc_interactiontype_value@Microsoft.Dynamics.CRM.lookuplogicalname”];
switch(_mdc_interactiontype_value_formatted) {
case “Gift & Entertainment”:
formId = “B57FE4BA-140C-4F92-9653-E5951EED56D9”;
break;
case “Conflict of Interest”:
formId = “4A63C8D1-6C1E-48EC-9DB4-3E6C7155334C”;
break;
case “Investigation”:
formId = “7EB073F1-2777-4FB2-9EC0-40DF876AF433”;
break;
case “Enquiry”:
formId = “6CE61006-C22A-4BF8-B748-F7994F702C4E”;
break;
case “Personal Trade Management”:
formId = “4A65C395-3B4B-4FCA-A1E1-BF37CED7599B”;
break;
case “Restricted Security Management”:
formId = “9850F0B8-B127-42F5-B718-1BC444304E26”;
break;
}
//Opening account with formId predefined
Xrm.Navigation.openForm({
entityName: “incident”,
entityId: recordId,
formId: formId
});
},
function(error) {
//If anything goes wrong log the error
console.log(error);
//and open “by default” form
Xrm.Navigation.openForm({
entityName: “incident”,
entityId: recordId,
formId: formId
});
});
}
return {
OpenRecord: openRecord,
};
})();
Old method i have used in onprem crm 365 9.0 version it is working fine in onprem the below method but not working in online crm 9.1.So i have tried to use yours above method.
//Show form based on Interaction Type, keep this method in all case forms
function showForm(executionContext) {
try {
var formContext = executionContext.getFormContext();
var interactionType = GetLookupName(formContext, “mdc_interactiontype”);
var lblForm;
var relType = interactionType
switch (relType) {
case “Gift & Entertainment”:
lblForm = “Case Overview – G&E”;
break;
case “Conflict of Interest”:
lblForm = “Conflict of Interest”;
break;
case “Investigation”:
lblForm = “Case Overview – Investigation”;
break;
case “Enquiry”:
lblForm = “Case Overview – Enquiry”;
break;
case “Personal Trade Management”:
lblForm = “Case Overview – Personal Trade Management”;
break;
case “Restricted Security Management”:
lblForm = “Restricted Securities”;
break;
default:
lblForm = “Case Overview – G&E”;
}
//check if the current form is form need to be displayed based on the value
var formLabel = formContext.ui.formSelector.getCurrentItem().getLabel();
if (formLabel != lblForm) {
var items = formContext.ui.formSelector.items.get();
for (var i in items) {
var item = items[i];
var itemId = item.getId();
var itemLabel = item.getLabel()
if (itemLabel == lblForm) {
//navigate to the form
item.navigate();
}
}
}
} catch (error) {
var errorOptions = {
details: “Error in CaseOverviewEnquiry js, Method Name:showForm().Download Error log file”,
errorCode: 2,
message: error.message
};
Xrm.Navigation.openErrorDialog(errorOptions);
}
}
Thanks,
Jharana
Jhrana,
Line
Xrm.WebApi.online.retrieveRecord(“incident”, “recordId”, “?$select=_mdc_interactiontype_value”).then(
looks incorrect for me. It should be
Xrm.WebApi.online.retrieveRecord(“incident”, recordId, “?$select=_mdc_interactiontype_value”).then(
Thanks,
Andrew
Hi Andrew,
I have tried the above modified comment of yours but still appropriate form is not loading based on field value.
Can i use the below 2nd code which is using navigate in online 9.2 version as it earlier worked in 9.0 CRM onprem.But unfortunatelly the below code also not working in v 9.2.
Thanks,
Jhrana,
What exact part doesn’t work? I would recommend debugging your code to clarify where it fails. You can check my video on how you can troubleshoot your code – https://www.youtube.com/watch?v=DIAM4q28LXQ&ab_channel=AndrewButenko
Thanks,
Andrew
You are Awesome!
Hello,
I’m glad you liked it.
Andrew
Thanks for this blog.
I’ve got an error when i want to load the solution in Ribbon Workbench.
I’ve createt a new solution, imported the entity account (without any informations) and added the script.
If i want to load the solution the error apears “For performance reasons, this solution cant be loaded.”
When i dont add the script it works fine…..
Any ideas?
Thanks forwards
Hello Dale,
Which version of RWB did you use? Was it the XrmToolBox version or Solution one?
Andrew
Hi Andrew,
It works now.
In the newest version of RibbonWorkbench you are not allowed to add JS anymore. That must be deposited on another solution as a web resource.
Hello Andrew,
create tutorial.
Thank you very much!
One question: How to overwrite this on a SubGrid?
The Main View works perfect.
But if I use this Table as a Sub Grid it looks like there seam to be a different Action triggers a diffrent Open Record.
Many thanks for the tutorial and your Information.
Best Regards
Jaroslaw
Hello Jaroslaw,
I haven’t tried that personally but here is what I have in one of replies here:
>>I believe it’s due to the Ribbon Workbench using the same value for CustomUIAction ID and Button ID. If you manually edit the RibbonDiffXml in the customizations.xml according to the Microsoft article here, you can make it work for both instances. I added a console.log() line to alert when the custom method is called and it fired from both the HomepageGrid and the SubGrid contexts.
Thanks,
Andrew
Nothing happend when click on the link of my form, either form is not open
Hello Muhammad,
If it worked for me and it doesn’t for you it means you did something wrong.
Thanks,
Andrew