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:

Header of the dialog inherits the “Display name” of Html Webresource you display but if you have the need to set it dynamically you can do it using following unsupported code:

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:

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.

57 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

  12. use ‘window.close()’ to close the webresource dialog
    before that, set the ‘window.returnValue’ with required data to return .

  13. The Last sentence: 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. When I try that with a webresource the returnValue in the promise is null.

    Am I doing something incorrectly? Thank you!

    1. Larry,
      Can you upload the code of your Html/Js webresource somewhere and leave the link here? It’s a bit hard to help you without seeing the code.
      Andrew

      1. Xrm.Navigation.navigateTo(pageInput, navigationOptions).then(function (success) {
        var selectedDateTime = success.selectedSlot;
        //additional code
        }
        //in the webresource
        window.selectedSlot = { date: newDate, start: startTime, end: endTime, isException: isException, };

        1. Try following:

          Xrm.Navigation.navigateTo(pageInput, navigationOptions).then(function (success) {
          var selectedDateTime = success.returnValue;
          //additional code
          }
          //in the webresource
          window.returnValue = { date: newDate, start: startTime, end: endTime, isException: isException, };

        2. Thank you for the quick response! I see the success parameter has a returnvalue in its object, I tried what you suggested but unfortunately returnvalue just stays null

        3. Larry,
          Can you please show the code that you use to set the returnValue and close the dialog window?
          Andrew

        4. I am so sorry it worked! Thank you so much!! This was a life saver!

          In order to get the widow object return value i need to use navigateTo right? Navigation.openwebresource wont return anything?

          //example

          var winobj = Xrm.Navigation.openWebResource(src, 1000, 800);
          winobj.onbeforeunload = function () {
          var selectedDateTime = winobj.returnValue;
          //additional code

          //in webresource
          window.returnValue = { date: newDate, start: startTime, end: endTime, isException: isException, };

        5. Larry,
          Article is about Xrm.Navigation.navigateTo and it’s the intended usage. You can use Xrm.Navigation.openWebResource but it wouldn’t provide you the modal dialog.
          Andrew

  14. Hi Andrew!
    Can we do something like that or at least like with the old and unsupported Xrm.Internal.openDialog(…) for the on-premise 9.0 environment?
    Thank you.

    1. Hello Danylo,
      Absolutely. Check one of my ancient posts on this – https://butenko.pro/2014/06/13/dynamics-crm-2013-step-by-step-creating-dialog-windows/
      Also in 9.0 Microsoft introduced new openDialog method under Xrm.Utility namespace that is generally speaking is a wrapper on top of Xrm.Internal.openDialog. You check example by following url – https://butenko.pro/2017/11/21/microsoft-dynamics-365-v9-0-whats-new-in-clientside-for-devs-besides-xrm-webapi/ also I’m not sure that it’ll work in UCI interface but it definitely works in Classic so you can use it.
      What you can check is well are following posts from marvelous Bob Guidinger:
      https://bguidinger.com/blog/custom-dialog-boxes-part-1
      https://bguidinger.com/blog/custom-dialog-boxes-part-2
      Thanks,
      Andrew

      1. Hi!
        Unfortunately, Xrm.DialogOptions() with Xrm.Internal.openDialog() are not working for the 9.0 on-premise, it gives me an error with the reason that DialogOptions is not a constructor. Also, Xrm.Utility.openDialog() is not working, because it is not a function…
        I have a custom HTML web-resource that I need to open in a modal dialog, and Bob Guidinger has not described how to do it with his great approach.
        It seems like the only way to open custom web-resources in on-premise environments is to use Xrm.Navigation.openWebResource(), but it’s so weak. 🙁

        1. Danylo,
          Where do you try to call those methods from? Is it other custom Html/Js webresource? It worked fine when I used it from form or ribbon script.
          Andrew

      2. Andrew,
        I tried to call them from the Ribbon button script and got errors. 🙁
        Could you tell please what exactly worked fine for you from a ribbon script? Is it on-premise 9.0 env.?

    1. Ville,
      Hypothetically – yes but I haven’t done that yet. Isn’t it would be easier to use Xrm.Utility.lookupObjects to achieve your goal?
      Andrew

      1. Hi Andrew, thanks for your response… i thin so, but my problem is that in my old fetchXML view i was having a link entity, but with the lookupObjects im not sure if it supports or maybe i don’t know how to add that link entity filter to the lookupObject filter…

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.