Dynamics 2013 Accessing Page entities is hard to access with iframe based views
Asked Answered
G

2

6

I am building an angular application which is running as a web resource on Dynamics 2013.

The application runs using a button which is added to the commandContainer using Ribbon workbench which then that button calls a Xrm.Internal.openDialog

All this works fine until I want to start using the Entities exposed by Xrm.Page.Data

Basically my button runs in the context of the main page of dynamics however the Entities are inside an iframe which based on the page I am in has a different Id and name.

So using a simple selector I can not get its contentWindow and start using the Entities.

The #crmContentPanel always has few iframes in it starting from #contentIFrame0 to #contentIFrame(n) and I can never know which iframe is the one with Entities in it.

What is the best practice, associated work flow with developing applications in this environment? How can I easily and reliably access the correct frame which holds the main page entities and work with them.

Perhaps the script is in the wrong location and needs to injected into the main content area so it has direct access to the correct Xrm? How can I achieve that?

Furthermore once I eventually manage to access this data, how can I easily pass this data to my angular application which runs in the dialog as from the documentation I read that the dialog is only allowed 1 query string param and it has to be called data. That would not be enough for my application to start using $routeParams. And I don't think using local or session storage is nice practice. What is the correct approach in this situation.

Sample code of my button script:

function runSendSender() {

    // Content Iframe Entity data:
    var contentFrameXrm = $('#crmContentPanel')
                       .find("iframe#contentIFrame0...n")[0]
                       .contentWindow['Xrm'];

    // even if above selector was consistent across pages
    // I need to send over much more than this one Id :(
    var data = contentFrameXrm.Page.data.entity.getId();

    var src = "/WebResources/concep_/ConcepDynamicsApp/ConcepDynamicsApp.html?data=" + data;
    var DialogOptions = new Xrm.DialogOptions();
    DialogOptions.width = 800;
    DialogOptions.height = 500;
    Xrm.Internal.openDialog(src, DialogOptions, null, null, CallbackFunction);

    function CallbackFunction(returnValue) { }
}

Little more detail

When I type the following in the console I can sometimes (randomly) read the title of the form:

$('#crmContentPanel').find("iframe#contentIFrame0")[0].contentWindow['Xrm'].Page.ui.get_formTitle();

But the same code from the associated web resource function can not access the iframe and errors:

Can not Cannot read property 'contentWindow' of undefined.

Why is the iframe not accessible via the resource script and how can I access the correct context and form title/id.

Gusti answered 5/9, 2014 at 9:52 Comment(2)
You don't have access back to the CRM entities via XRM. When you write JavaScript on a form itself you use Xrm.Page.Data to manipulate the data on the form for that entity. Your Webresource needs to use the id you are passing it to load the necessary data (usually done via OData) and proceed from there.Metamathematics
Hi Nick, thanks but the same issue stands for just getting the Id from Xrm as the script runs in the context of the top page but the Xrm that has the id information of the form is inside another iframe with no fixed id across pages in dynamics. How do I get the id consistently?Gusti
C
3

The record Id can be sent to runSendSender as parameter by the ribbon itself. Just add the appropriate CrmParameter (MSDN) to the function call.

In your case, the parameter value would be FirstPrimaryItemId ("Provides one GUID identifier as a string for the record being viewed.")

After that, you'll have your function changed like this

function runSendSender(recordId) { ... }

Also, stay out from internals: to open a web resource in a dialog, you should use the supported way (link provides info about passing parameters other than data to the resource).

Xrm.Utility.openWebResource(webResourceName,webResourceData,width, height)
Colenecoleopteran answered 11/9, 2014 at 14:10 Comment(0)
T
5

I'm usually including following JavaScript file to the header of the custom WebResource that need to have an access to the CRM specific actions / information:

<script src="ClientGlobalContext.js.aspx" type="text/javascript"></script>

This gives access to some none-entity specific information, such as Xrm.Page.context.getServerUrl() or Xrm.Page.context.getUserId() for example.

But if you added layer with your own iFrame on top of the standard entity page, you definitely can access to information underneath your current context by using following construction:

window.parent.Xrm.Page.data.entity.attributes.get("name").getValue();

Note the window.parent prefix.

Tomfool answered 11/9, 2014 at 11:14 Comment(0)
C
3

The record Id can be sent to runSendSender as parameter by the ribbon itself. Just add the appropriate CrmParameter (MSDN) to the function call.

In your case, the parameter value would be FirstPrimaryItemId ("Provides one GUID identifier as a string for the record being viewed.")

After that, you'll have your function changed like this

function runSendSender(recordId) { ... }

Also, stay out from internals: to open a web resource in a dialog, you should use the supported way (link provides info about passing parameters other than data to the resource).

Xrm.Utility.openWebResource(webResourceName,webResourceData,width, height)
Colenecoleopteran answered 11/9, 2014 at 14:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.