Search code examples
javascriptdynamics-crmdynamics-crm-2015

"Function Expected" error in JsProvider.ashx after setting a lookup field


I have an HTML page that gets opened when clicking a ribbon button of a custom entity page. The JS code running in this page is does some business logic, and eventually needs to update a lookup field back on the custom entity page.

Currently, for setting the lookup value, I'm doing something like the following*:

window.opener.Xrm.Page.getAttribute("ik_reportid").setValue([{
    id: "d67aa9d8-c528-e711-80f2-005056b74923",
    name: "test record",
    entityType: "ik_report"
}]);

*Note: The above is written hard-coded for simplifying this question. I assure you the problem is not in these values, but somewhere else.

After doing so, the HTML page continues with its existing code, and eventually calls window.opener.Page.data.refresh(true), and then closes itself with window.close().

The problem is that when the opener page is refreshing, I get an error "function expected", and opening the debugger get me to the following line in JsProvider.ashx:

Mscrm.FormInputControl.LookupUIBehavior.$2I=function($p0,$p1){if(!parseInt($p0.type)&&!parseInt($p1.type)||parseInt($p0.category)===LookupItemCategories.UNKNOWN_EMAIL&&parseInt($p1.category)===LookupItemCategories.UNKNOWN_EMAIL)

I watched the values of p0 and p1, and I noticed they don't have a category property. However, when I tried using the same code for setting the value of the same lookup field when I'm on the page itself (i.e., omitting the window.opener', and even calling arefresh`), I get no error.

In addition, I commented-out the refresh call inside the HTML page code. That didn't help, too: when I clicked the save button on the entity page, I again got the "function expected" error, now in Global.ashx (b was expected to be a function, apparently) :

Sys._isInstanceOfType=function(c,b){if(typeof b==="undefined"||b===null)return false; if(b instanceof c) return true;

No idea what's the cause for it. Any help is welcomed.


Solution

  • Posting messages between windows should meet your requirements here. You can find more information here Basically in your parent window do something like this:

    window.onmessage = function (e) {
         //e.data will contain some payload
        Xrm.Page.getAttributes("xxx").setValue(e.data);
    };
    

    Or to be compatible with all browsers:

    if (window.addEventListener) {
      window.addEventListener('message', function (e) {
        //e.data will contain some payload
        Xrm.Page.getAttributes("xxx").setValue(e.data);
      });
    }
    else { // IE8 or earlier
      window.attachEvent('onmessage', function (e) {
         //e.data will contain some payload
         Xrm.Page.getAttributes("xxx").setValue(e.data);
      });
    }
    

    Now in your child window only send the result using postMessage

    window.opener.postMessage("I'm the result", '*');
    

    I usually handle the scenarios that you described this way. The other solution would be to create a callback on parent window

    window.callback = function() {
       //do your stuff here
    }
    

    and from child window calling this callback:

    childWindow.opener.callback();
    

    But personally I prefer the postMessage approach, I had some problems with the callbacks sometimes.