Blog, Development

Open proper form based on record’s data – UCI way

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? I recalled this post from my friend and former (hopefully short-term) MVP Artem Grunin. Btw – if you haven’t subscribed to his blog and Twitter do it now because he rocks. I decided to take and implement that idea.

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:

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.

49 Comments

  1. 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?

    1. 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

  2. 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.

    1. 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

  3. 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

    1. Krutika,
      I can confirm that I can replicate your behavior. I would recommend to get in touch with Microsoft and ask for help.
      Andrew

      1. 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

  4. 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,

    };
    })();

      1. 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.

    1. 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,
      };
      })();

      1. Matias,
        So what exactly are you trying to implement?
        Remove line with code var Id = result.RecordId – it’s useless.
        Andrew

  5. 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.

    1. Hello,
      When you register command this way platform uses it instead of the standard code used to open the form.
      Andrew

      1. 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?

        1. Hello,
          What do you mean with the button to navigate to other records? Can you please be more specific?
          Andrew

  6. 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.

    1. 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

  7. 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.

  8. 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,
    };
    })();

  9. Hello Andrew, i did post some question replying on another post but i cannot see it. Could you help me?, thanks.

    1. Matias,
      For some reason your questions went to SPAM. I whitelisted it so now I will be able to answer.
      Andrew

      1. 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?

        1. 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

  10. 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.

  11. 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();

  12. Hello.
    Does the function name depends of the entity name? “AB.AccountRibbon”. In my case the entity name is msdyn_projecttask

    1. Mauricio,
      It doesn’t depend. I use that naming just for self-documentation purposes.
      Andrew

  13. 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?

    1. 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

      1. Дякую Andrew for your answer! I already checking if it’s will working for on-prem. 🙂

  14. 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

    1. 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

  15. 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,

  16. 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

    1. Hello Dale,
      Which version of RWB did you use? Was it the XrmToolBox version or Solution one?
      Andrew

      1. 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.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.