Blog, Development

Xrm.Navigation.navigateTo – gotchas, tricks and limitations

Here are ways that were used by developers to show Modal Dialogs:

  1. Xrm.Internal.openDialog
  2. Alert.js
  3. Custom Dialogs that used different frameworks like jQuery UI Dialog or similar

But the main and common issue of options available was that those approaches can’t be considered as supported.

And it stayed the same for years until Microsoft introduced Xrm.Navigation.navigateTo method.

So what’s new here?

Here is the code that can be used to open a modal dialog:

So far so good. When this code is called following dialog window is shown:

First thing that I’m not comfortable with is the fact that the header of the dialog just uses the name of the webresource that’s not friendly at all. I found only unsupported way to set it so far. Following code added to the onload script of the dialog sets the header’s label:

Once code is added, dialog starts to look friendlier:

Next part is extraction of parameters passed to the webresource. Firstly I tried getQueryStringParameters of GlobalContext in two combinations – GetGlobalContext().getQueryStringParameters and Xrm.Utility.GetGlobalContext().getQueryStringParameters and both calls did not bring the expected result. So… the last resort is explicit parsing of the url. Following code can be used for parsing:

Now let’s make this dialog look closer to standard dialogs and add “OK”/”Cancel” buttons to it. There are multiple ways of doing this. I decided to use “Office UI Fabric” for this purpose. Here is the code of the dialog page:

Here is how it looks like after modifications:

Unfortunately there is only unsupported way to close dialog at the moment. Following code can be used to close it:

In order to return data from dialog set returnValue of window object in dialog and include parameter to “resolve” handler of promise in calling code.

39 Comments

  1. Hi Andrew, note that in chrome the title is in h1#defaultDialogChromeTitle.
    They should really provide a way to set the title on load (even the webresource has another name…)

    1. Thanks, Thomas. That’s why code that used to work earlier doesn’t work anymore.
      Andrew

    2. Regarding Header of the Dialog window .. i was able to specify the display name in the Solution . (Web resource display name in the solution/customization window).

  2. Hi.. Andrew, Thanks for this post. It was really helpful .. Regarding Header of the Dialog window .. i was able to specify the display name in the Solution . (Web resource display name in the solution/customization window).

    Thanks,
    Sumit

    1. This doesn’t seem to work on Chrome?
      The Display name of the Web Resource is not the title for me.

  3. How can I access Xrm.WebApi within the HTML resource?
    So that I can create a Note (annotation Entity) when someone clicks “OK”.

    Thanks!

    1. At the moment keeping in mind deprecation of ClientGlobalContext.js.aspx this fall your best chance is either usage of Xrm.WebApi through parent.Xrm.WebApi or usage of pure XrmHttpRequest from the context of the webresource.

  4. Data parameter is no more supported. Can you Please check as it is crashing when we send parameters as shown above

  5. Passing data is not more supported as per document. Can u Please suggest any way to pass as above code is not working for passing data to web resource

    1. Harkamal,
      I checked what you said and everything works fine for me. If it works for me and doesn’t work for you I believe there could be an issue in your code.
      Andrew

  6. Hi there,
    instant of parent … you can us it like this

    Xrm.Navigation.navigateTo(dialogParameters, navigationOptions).then(
    (result) => this.handleChangeResult(result),
    (error) => this.handleError(error));

    And on the html dialog you can set:
    window.returnValue = { success: true, phonenumber: this.result};

    So this should be completely supported.

    1. Andre, thanks for your comment. In my post I use parent for manipulation with Title and for closing of the dialog and not for sending the result back to the calling code. Is there any alternative to that?
      Andrew

      1. I use this earlier too, but there is a porblem by validating the code with MS tools, because parent is unsupported.
        So I change to set window.returnValue and close the window.
        inside the successhandler, the result is this returnValue you set to window.returnValue

        1. Andre, I got that point.
          What I meant – are there any supported alternatives on how to close the window from the code or how to change the title in the supported way (i.e. without using parent)?
          Andrew

        2. sorry I can’t answer your replay.
          Now I got your problem, I don’t think so because what you call ‘title’, should be somthing like ‘address’. I think this is not well thought out by microsoft right now, maybe there will be a update some time.

  7. Andrew, good morning.

    Could you help me?

    I’m doing with html/js and using your code to open dialog.
    Until now, everything is fine, but i found a problem. After I fill data, we have to do some processes.
    My old dialog uses ‘Start child workflow, Change record status to, create related entity’.

    How do I do this in custom code?
    I’m reading about and looks like ‘Workflows will deprecated’.

    So, i’d like to ask to you what can I do or what you’d do.

    1. Do you think if I use some ‘webapi.update field’ to fires a plugin (to do above operations of old dialog’, will it work in future?
    2. Sdk.rest will be deprecated?
    3. Do you recommend WebAPI? If yes, do you know if old bugs with external webresources still exists? Below:

    Example:
    window[“ENTITY_SET_NAMES”] = window[“ENTITY_SET_NAMES”] || JSON.stringify({
    “contact”: “contacts”,
    “email”: “emails”,
    “account”: “accounts”
    });
    window[“ENTITY_PRIMARY_KEYS”] = window[“ENTITY_PRIMARY_KEYS”] || JSON.stringify({
    “contact”: “contactid”,
    “email”: “emailid”,
    “account”: “accountid”
    });

    4. I had to use these code above in another situation, because i couldn’t retrieve or create record without to do this. Do you think this will be fix in the future?

    Thanks!!

    1. Felipe,
      1. I would recommend to put your logic to action and call it using WebApi.
      2. I believe Sdk.Rest is a wrapper on top of old odata2 endpoint – and it would be deprecated some time so it’s time to switch to WebApi.
      3. I do recommend usage of WebApi. I know what you’re talking about and you have to either use this approach or use parent.Xrm.WebApi… I know that usage of parent is not recommended but at the moment in some situations it’s the most optimal way.
      Andrew

      1. Ok. I understand!

        So, about action, you mean, create an action on process (like workflows) e call using webapi? Could you give me a example or some information to read? Because i’m new in this part.

        Thanks!!

        1. Felipe, sure.
          Here is how you can call the plugin when an action is invoked – https://www.magnetismsolutions.com/blog/dominicjarvis/2017/09/18/how-to-trigger-plugins-on-custom-messages-using-actions-in-dynamics-365
          What you will have to do is to place your logic inside your plugin (writing the code and no fancy UI…)
          To build the code that calls action using WebApi I highly recommend CrmRestBuilder – https://github.com/jlattimer/CRMRESTBuilder/releases/tag/2.6.0.0
          Feel free to ask more question if you have issues.
          Andrew

  8. Many thanks, Andrew. Helped me a lot!!

    I did connection between action interface-plugin code, did logic too, described on link.

    But i still don’t get it how to call Xrm.WebApi.online.execute with parameters, sorry :/

    Because i’m looking everywhere, but i didn’t find how to pass parameters, any types (lookup, entity, string, int).

    And i still one doubt. Do I need to declare input/output parameters in both action interface and plugin code or just in one of it?

  9. Many thanks Andrew,

    We have this xrm.navigatation.navigateto in a lookup, but the Javascript code that should load within this form is not loading.
    Do you know any way to loadto trigger this OnLoad – OnSave Javascript in the dialog form?

    Thank you!

    1. Victor,
      I’m not sure what you mean. Can you please describe your scenario, what you did and what issue you experience.
      Thanks,
      Andrew

      1. Hi Andrew,

        Yes, sorry!
        So we have the entity account, and inside it we have a list of contacts.
        If we click in one record of this list, a modal dialog is opened (we are using the navigateTo.)

        In our contact form we have some Javascript code inside the onLoad event

        function OnLoadContactForm() {
        alert(‘I am the contact’)
        }

        However, when we click in the contact row, the modal dialog is opened, but that alert is not shown.
        Does that make sense?

        Thank you!

        1. Victor,
          Did you attach this OnLoadContactForm handler to OnLoad event of the form load of contact and published changes?
          Andrew

        2. Yes, the onLoad is working perfectly on the contact form, but the event is not working with the dialog form way.

          Thank you,

          Victor

        3. Victor,
          I haven’t tried this scenario. I will take a look and be back to you.
          Andrew

        4. Andrew,

          Many thanks! We think it is a limitation, because it is opened as a section tag inside the HTML, not an iframe, so it seems the Javascript is not loaded, but we didn’t know if you could pass a parameter or something like that.
          BTW I really appreciate how quick you replied to my comments.

          Thanks!!

  10. Hy Andrew,
    i have took your code reference in my example over there actually what i am dong is, i have created that dialog on lead form and on dialog i give drop down to user after the select on option and do click on OK the dialog will be closed and one filed will be update on lead..so for update i have created odata query but i dont know how can i return it
    please can you help?

    Thanks & regards

    1. Yash,
      Not sure what you mean with “return odata query”. Return the value to the calling code and call webapi there.
      Andrew

      1. Means on okButton i am updating one of lead form filed using odata query but it’s not working…

        1. Yash, what exactly are you doing? I don’t have superpowers to read your mind or see your code. Andrew

  11. Hy Andrew
    Here is code:

    var okButton = document.getElementById(“btnOK”);
    new fabric[‘Button’](okButton, () =>
    {
    debugger;
    // window.returnValue = “place here data or object you want to return”;if(select.options[select.selectedIndex].text==”–Select–“)
    {
    alert(“Please select any “);
    var select = document.getElementById(“DropDown”);
    select.onchange = function(){
    selectedOne = select.options[select.selectedIndex].text;
    alert(selectedOne);
    if(selectedOne==”customer” || selectedOne==”partner”)
    {
    var clientUrl = window.parent.Xrm.Page.context.getClientUrl();
    alert(clientUrl);

    var ctyppe ={};
    if(selectedOne==”customer”)
    {
    ctyppe.ewt_custtype=1;//
    }
    else
    {
    ctyppe.ewt_custtype=2;//ECC6
    }
    //Update SAP Source on lead
    var req1 = new XMLHttpRequest();
    req1.open(“GET”, window.parent.Xrm.Page.context.getClientUrl() +
    “/api/data/v9.1/leads?$select=ewt_custtype&$filter=leadid eq ‘”+ leadRef + “‘ “, true);
    req1.setRequestHeader(“Accept”, “application/json”);
    req1.setRequestHeader(“Content-Type”, “application/json; charset=utf-8”);
    req1.setRequestHeader(“OData-MaxVersion”, “4.0”);
    req1.setRequestHeader(“OData-Version”, “4.0”);

    req1.onreadystatechange = function () {

    if (this.readyState == 4 /* complete */) {
    req1.onreadystatechange = null;

    if (this.status == 200 || this.status == 204) {
    //success callback this returns null since no return value available.
    var result = JSON.parse(this.response);
    // Xrm.Utility.closeProgressIndicator();
    } else {
    //error callback
    var error = JSON.parse(this.response).error;
    }
    }
    };
    req1.send(JSON.stringify(ctyppe));
    }
    }
    }

    }

    1. Yash,
      Just return selected values to the calling code and don’t call the webapi in the dialog – call webapi in the calling part (ribbon).
      Andrew

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.