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 – example from Magnetism Solution. That approach worked, but it was a bit confusing because of form “blink” that was caused with 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 from 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 on the previous step, point to the proper function and add “FirstSelectedItemId” as a parameter for the function.

Functionality will not work as expected without 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 button will not be shown. Here is screenshot of “Enable Rule”:

Once command is added – add the button with the same id – exactly “Mscrm.OpenRecordItem” and use 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 accounts grid and test how it works. If you completed everything the right way you will get everything working fine.

35 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();

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.