Embedded reporting is a common requirement for both internal and external (customer- facing) applications. Typically, the application presents a list of reports or dashboards to the user, so the user can pick which one to view. Then the application embeds the content in the presentation layer, so that reports and dashboards appear to be a part of the
application itself (as opposed to redirecting the user to Power BI).
12.1.1 Understanding Embedded Tiles
Power BI includes dashboard APIs that allow you to embed specific dashboard tiles in your apps. The benefit of tile embedding is that the end users can decide what tiles they want to see on a consolidated dashboard, without have to use Power BI Service. So your app can mimic the dashboard features of Power BI Service. It can allow the user to compile its own dashboards from Power BI dashboard tiles, and even from tiles that are located in different Power BI dashboards!
Understanding embedded features
From the end user standpoint, embedded tiles look the same as the ones hosted in Power BI Service.
Figure 12.1 shows the “Sales vs Orders” tile from the Internet Sales dashboard, which you implemented in Chapter 3.
Figure 12.1 This tile is embedded in an iframe element that’s hosted by a web page.
The difference between Power BI Service dashboards and embedding tiles in your app is that, by default, clicking a tile doesn’t do anything. You need to write code for something to happen, such as to navigate the user to the underlying report (from which the
visualization was pinned). On the upside, your custom code has more control over what happens when the end user clicks a tile.
Understanding implementation steps
At a high level, the embedding tile workflow consists of the following steps:
Obtain the tile identifier – You need to gain access programmatically to a dashboard before you get to a tile. So you’d need to find the dashboards available for the user, and then enumerate the dashboard tiles. Once the user chooses a tile, then you work with the tile identifier.
Embed a tile – Embed the tile in your application, such by using an iframe.
(Optional) Handle tile interaction – For example, you might want to open the underlying report when the user clicks a tile.
Of course, security needs to be addressed as well. I’ll explain special considerations
related to integrating custom application security with Power BI when I walk you through the sample code in section 12.3. Now let’s dig deeper into the implementation steps.
12.1.2 Enumerating Dashboards and Tiles
I mentioned in the previous chapter that Power BI includes APIs for enumerating
dashboards and tiles. Your application can call these APIs to present the users with a list of tiles that they might want to see in your application.
Enumerating dashboards
The “List All Dashboards” method returns the dashboards available in the user’s My Workspace. This method has the following signature:
https://api.powerbi.com/beta/myorg/dashboards
Similar to listing datasets, this method supports enumerating dashboards in another workspace by passing the group identifier. For example, if the group identifier of the Finance workspace is e6e4e5ab-2644-4115-96e0-51baa89df249 (remember that you can obtain the groups that the user belongs to by calling the “List All Groups” method), you can get a list of dashboards available in the Finance workspace by using this signature:
https://api.powerbi.com/beta/myorg/groups/e6e4e5ab-2644-4115-96e0-51baa89df249/dashboards Enumerating tiles
Once you retrieve the list of dashboards, you can present the user with a list of tiles from a specific dashboard by calling the “List All Tiles” method. This method takes an id
parameter that corresponds to the dashboard identifier, which you obtain from the “List All Dashboards” method. Here is a sample “List All Tiles” method invocation:
https://api.powerbi.com/beta/myorg/dashboards/id/tiles
The result of this method is a JSON collection of all the tiles hosted in that dashboard. The
following snippet shows the definition of the “Daily Sales” tile:
{
“id”: “255d89b5-75b4-439d-8776-40f5de0463f0”,
“title”: “Daily Sales”,
“subTitle”: “By day”,
“embedUrl”: “https://app.powerbi.com/embed?dashboardId=d0b9e383-7b84-4bbf-8f55- 9094efdca212&tileId=255d89b5-75b4-439d-8776-40f5de0463f0”
}
The embedUrl element is what you need to embed the tile in your app.
12.1.3 Embedding Tiles
Once you have the embed URL, the next step it to embed the tile on a web page. When sending the tile URL, you’d need to also send the OAuth access token to the Power BI Service.
NOTE Currently, the tile embedded API doesn’t support real-time updates when other applications push rows to a dataset. As a workaround, you can use the tile API to refresh the tile data, and then refresh your iframe to load updated data periodically.
Requesting a tile
In the most common scenario, you’d probably report-enable a web application. You can display the tile in an iframe element. To do so, you must write client-side JavaScript to communicate with the Power BI Service. As a first step, you’d need to reference the iframe element and handle its events:
var iframe = document.getElementById(”iFrameEmbedTile’);
var embedTileUrl = document.getElementById(‘tb_EmbedURL’).value;
iframe.src = embedTileUrl;
// iframe.src = embedTileUrl + “&width=” + width + “&height=” + height;
iframe.onload = postActionLoadTile;
When making this call, you can specify the width and height that you want the tile to have.
You must handle the onload event in your code by defining an event handler for the iframe.onload event. In this case, the postActionLoadTile function is the event handler function. If you don’t handle the iframe.onload event, the user will see a spinning progress image, and the tile won’t load.
Handling client-side authentication
Once the iframe triggers the load event, you have to send the access token to Power BI Service. The postActionLoadTile function takes care of this:
function postActionLoadTile() { // get the access token
accessToken = ‘<%=Session[“authResult”]==null? null:
((Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationResult)Session[“authResult”]).AccessToken%>’;
if (”” === accessToken) return;
var h = height;
var w = width;
// construct the push message structure
var m = { action: “loadTile”, accessToken: accessToken, height: h, width: w };
message = JSON.stringify(m);
// push the message.
iframe = document.getElementById(‘iFrameEmbedTile’);
iframe.contentWindow.postMessage(message, “*”);;
}
First, the code obtains the access token from a session variable that stores the
authentication result from the OAuth flow. Normally, the browser would reject cross- domain frame communication. However, the HTML5 specification introduces the window.postMessage() method (see https://developer.mozilla.org/en-
US/docs/Web/API/Window/postMessage) as a secure mechanism to circumvent this restriction. The code creates a JSON push message structure to instruct Power BI Service to load the tile, and then it passes the access token and tile dimensions.
Next, the code posts the message. At this point, the tile should render on the page.
Power BI visualizations use HTML5 and JavaScript to render visualizations on the client (read the next chapter for more detailed information about how this works). The tile will automatically scale to fit within the iframe, based on the height and width you provide.
Filtering tile content
Dashboard tiles support limited filtering capabilities. This could be useful when you want to further filter the content based on some user-specified filter. You can pass a filter on the embed URL using this syntax:
https://app.powerbi.com/embed?dashboardId=<dashboard_id>&tileId=<tile_id>&$filter={FieldName} eq
‘{FieldValue}’
You can filter on any field in the underlying model, even though the field might not be used in the tile. Fields are contained in tables so the FieldName must be specified as TableName/FieldName. The filter is added as “AND” filter to any existing filters that are already applied to the tile, report or Q&A.
Suppose that the user has indicated that they want to see the sales for Canada only. To meet this requirement, you can filter the SalesTerritoryCountry field in the SalesTerritory table. The embed URL that specifies this filtering condition might look like this:
embedTileUrl += “&$filter=SalesTerritory/SalesTerritoryCountry eq ‘Canada’
Currently, the filter syntax supports only a single value and you can’t specify multiple filtering conditions. When you use a filter, the navigationUrl property of the tile will be updated to include the filter. This allows you to pass on the filter to the underlying report if your code opens the report when the user clicks the tile.
Handling user interaction
Remember that Power BI Service allows the user to click a tile and opens the underlying report (from which the tile was pinned). You can add a similar feature to your app with the following code:
if (window.addEventListener) {
window.addEventListener(“message”, receiveMessage, false);
} else {
window.attachEvent(“onmessage”, receiveMessage);
}
function receiveMessage(event) { if (event.data) {
messageData = JSON.parse(event.data);
if (messageData.event === “tileClicked”) { // code to do something with the report URL }
The code defines an event handler that will listen for messages posted to the iframe content. For example, when the tile is loaded, the message is “tileLoaded”, and when the tile is clicked, the message is “tileClicked”. It’s up to you what you want to do with the navigationUrl property, which you obtain from the event parameter. One option is to open a separate window that shows the entire dashboard or the underlying report. Another option (demonstrated by my sample code) is to show the underlying report in the same iframe.