powerbi global object not found in typescript - powerbi

I am trying to use this power bi below code where powerbi object not found error is getting in my typescript code:
// Read embed application token from textbox
var txtAccessToken = $('#txtAccessToken').val();
// Read embed URL from textbox
var txtEmbedUrl = $('#txtReportEmbed').val();
// Read report Id from textbox
var txtEmbedReportId = $('#txtEmbedReportId').val();
// Read embed type from radio
var tokenType = $('input:radio[name=tokenType]:checked').val();
// Get models. models contains enums that can be used.
var models = window['powerbi-client'].models;
// We give All permissions to demonstrate switching between View and Edit mode and saving report.
var permissions = models.Permissions.All;
// Embed configuration used to describe the what and how to embed.
// This object is used when calling powerbi.embed.
// This also includes settings and options such as filters.
// You can find more information at https://github.com/Microsoft/PowerBI-JavaScript/wiki/Embed-Configuration-Details.
var config= {
type: 'report',
tokenType: tokenType == '0' ? models.TokenType.Aad : models.TokenType.Embed,
accessToken: txtAccessToken,
embedUrl: txtEmbedUrl,
id: txtEmbedReportId,
permissions: permissions,
settings: {
filterPaneEnabled: true,
navContentPaneEnabled: true
}
};
// Get a reference to the embedded report HTML element
var embedContainer = $('#embedContainer')[0];
// Embed the report and display it within the div container.
var report = powerbi.embed(embedContainer, config);
// Report.off removes a given event handler if it exists.
report.off("loaded");
// Report.on will add an event handler which prints to Log window.
report.on("loaded", function() {
Log.logText("Loaded");
});
report.on("error", function(event) {
Log.log(event.detail);
report.off("error");
});
report.off("saved");
report.on("saved", function(event) {
Log.log(event.detail);
if(event.detail.saveAs) {
Log.logText('In order to interact with the new report, create a new token and load the new report');
}
});
in the above code the powerbi object shows not found in my typescript code: powerbi.embed(embedContainer, config);
I tried to use window['powerbi'] or window.powerbi but doesn't work. What should be the solution then?

I faced a similar issue a few weeks back (probably exactly the same). For me it seems that what works is using window.powerbi.embed() for the embed action, whereas the import import * as powerbi from "powerbi-client"; is used for all other Power BI objects.

I had the same problem, found this question through a google search. I wasn't able to figure out why it wasn't on the window, but as a work around you can initialize it yourself like this:
import * as pbi from "powerbi-client";
const powerbi = new pbi.service.Service(
pbi.factories.hpmFactory,
pbi.factories.wpmpFactory,
pbi.factories.routerFactory
);
const container = document.getElementById("report-container");
powerbi.embed(container, embedConfiguration);

Related

How to Embed 2 or more Power BI reports in a Single web page?

I have a standard user owns sample application which can embed 1 report at a time, however, I need to embed 2 or more reports in a single web page. If there is a sample solution file that can do this Job, that's great.
To embed Power BI element using the JavaScript client, you must configure the settings (which report/dashboard/tile to be embedded, how to authorize the request, what view mode, provide additional filters, etc.) and then call the embed method passing the configuration and a <div> element where the embedded element will be loaded.
This code is from the sample:
// ----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
// ----------------------------------------------------------------------------
$(function () {
var models = window["powerbi-client"].models;
var reportContainer = $("#report-container").get(0);
$.ajax({
type: "GET",
url: "/embedinfo/getembedinfo",
success: function (data) {
embedParams = $.parseJSON(data);
reportLoadConfig = {
type: "report",
tokenType: models.TokenType.Embed,
accessToken: embedParams.EmbedToken.Token,
// You can embed different reports as per your need
embedUrl: embedParams.EmbedReport[0].EmbedUrl,
// Enable this setting to remove gray shoulders from embedded report
// settings: {
// background: models.BackgroundType.Transparent
// }
};
// Use the token expiry to regenerate Embed token for seamless end user experience
// Refer https://aka.ms/RefreshEmbedToken
tokenExpiry = embedParams.EmbedToken.Expiration;
// Embed Power BI report when Access token and Embed URL are available
var report = powerbi.embed(reportContainer, reportLoadConfig);
// Clear any other loaded handler events
report.off("loaded");
// Triggers when a report schema is successfully loaded
report.on("loaded", function () {
console.log("Report load successful");
});
// Clear any other rendered handler events
report.off("rendered");
// Triggers when a report is successfully embedded in UI
report.on("rendered", function () {
console.log("Report render successful");
});
// Clear any other error handler events
report.off("error");
// Handle embed errors
report.on("error", function (event) {
var errorMsg = event.detail;
// Use errorMsg variable to log error in any destination of choice
console.error(errorMsg);
return;
});
},
error: function (err) {
// Show error container
var errorContainer = $(".error-container");
$(".embed-container").hide();
errorContainer.show();
// Format error message
var errMessageHtml = "<strong> Error Details: </strong> <br/>" + err.responseText;
errMessageHtml = errMessageHtml.split("\n").join("<br/>");
// Show error message on UI
errorContainer.append(errMessageHtml);
}
});
});
So to be able to embed multiple elements, you must prepare multiple configurations (see reportLoadConfig in the sample code), prepare multiple placeholders (see reportContainer in the sample code) and call powerbi.embed multiple times.
Check again this article - Understanding the different embedding solutions. For your tests you can use the developer sandbox in the Power BI playground.

How to bind multiple Power BI datasets to a single Power BI Report

I have a user name logging into the Web Application.
I am using HTML, CSS, JavaScript and ASP.NET webform to run the Web Application with Power BI embedded reports.
I am trying to code to pass Server Name and Database name based on the user logged in to Power BI embedded config.
How to pass server name and database name to Power BI Embedded config?
Tried to test the application flow with Import Data Sets using following things, but the Power BI Report is not getting loaded in HTML div element. Its giving "Power BI Loading logo" in the embed div and then showing message as "Power BI content is not available"
Application Flow:
Power BI workspace has One Report and Two Datasets
Following is the Token generation code in .NET
// Generate an embed token and populate embed variables
using (var client = new PowerBIClient(new Uri(Configurations.ApiUrl), Authentication.GetTokenCredentials()))
//using (var client = new PowerBIClient(new Uri(Configurations.ApiUrl), Authentication.m_tokenCredentials))
{
var report = client.Reports.GetReportInGroup(new Guid(Configurations.WorkspaceId), new Guid(ddlReport.SelectedValue));
var rls = new EffectiveIdentity(username: appLoginUserName, new List<string> { userDatasetId.ToString() });
// Effective Identity
var rolesList = new List<string>();
rolesList.Add("Tenant");
rls.Roles = rolesList;
// Create list of datasets
var v2DatasetID = new List<Guid>();
v2DatasetID.Add(userDatasetId);
// Create list of Effective Identities
var v2rls = new List<EffectiveIdentity>();
v2rls.Add(rls);
// Create a request for getting Embed token
// This method works only with new Power BI V2 workspace experience
var tokenRequest = new GenerateTokenRequestV2(
reports: new List<GenerateTokenRequestV2Report>() { new GenerateTokenRequestV2Report(report.Id) },
datasets: v2DatasetID.Select(datasetId => new GenerateTokenRequestV2Dataset(datasetId.ToString())).ToList(),
identities: v2rls,
targetWorkspaces: null
);
// Generate Embed token
var getToken = client.EmbedToken.GenerateToken(tokenRequest);
// Populate embed variables (to be passed client-side)
//embedToken = tokenResponse.Token;
embedToken = getToken.ToString();
embedUrl = report.EmbedUrl;
reportId = report.Id;
}
Following is the Power BI embed configuration with dynamic dataset:
<script>
// Read embed token
var embedToken = "<% =this.embedToken %>";
// Read embed URL
var embedUrl = "<% = this.embedUrl %>";
// Read report Id
var reportId = "<% = this.reportId %>";
// Read dataset Id
var userDatasetId = "<% = this.userDatasetId %>";
// Get models (models contains enums)
var models = window['powerbi-client'].models;
// Embed configuration is used to describe what and how to embed
// This object is used when calling powerbi.embed
// It can also includes settings and options such as filters
var config = {
type: 'report',
tokenType: models.TokenType.Embed,
accessToken: embedToken,
embedUrl: embedUrl,
id: reportId,
datasetId: userDatasetId, // The dataset id that you want the report to use
settings: {
filterPaneEnabled: true,
navContentPaneEnabled: true,
extensions: [
{
command: {
name: "cmdShowValue",
title: "Show Value in MessageBox",
selector: {
$schema: "http://powerbi.com/product/schema#visualSelector",
visualName: "VisualContainer7" // Sales and Avg Price by Month visual
},
extend: {
visualContextMenu: {
title: "Show Value in MessageBox"
}
}
}
}
]
}
};
// Embed the report within the div element
var report = powerbi.embed(embedDiv, config);
</script>
This is not possible. These are report wide settings and you are asking how two different users, which are viewing the same report simultaneously, to connect to a different data sources. You must either deploy as many report are needed and choose which one to embed, or build one report using all the data sources, and then filter the data based on the currently logged in used.
Otherwise, the direct answer to your question is to rebind the report or to change the datasource of the dataset.

What do I place as the report id in the PowerBIEmbed when creating a new report?

I'm trying to use the PowerBIEmbed React component to create and design a new report. Everything works great when I edit an existing report, but when I'm creating a new one (using an embed token generated with TokenAccessLevel.Create), I'm getting the following error:
Report id is required, but it was not found. You must provide an id either as part of embed configuration or as attribute 'powerbi-report-id'.
The id I'm passing in via the configuration is the empty GUID ("00000000-0000-0000-0000-000000000000"). I have also tried deleting that property from the configuration.
I have the permissions set to models.Permissions.All (which includes models.Permissions.Create), so that isn't the issue.
Client code
const config = {
permissions: models.Permissions.All,
tokenType: models.TokenType.Embed,
type: 'report',
embedURL: generatedURL,
accessToken: generatedToken,
viewMode: models.ViewMode.Edit,
};
return (
<PowerBIEmbed
embedConfig={config}
getEmbeddedComponent={report => this.setState({ report })}
/>
);
Server Code
var authToken = await PowerBIAuthentication.DoAuthentication(_Config);
using var client = new PowerBIClient(new Uri(_Config.ApiUrl), authToken);
var dataSets = await client.Datasets.GetDatasetsInGroupAsync(_Config.WorkspaceId, cancellationToken);
var dataSet = dataSets.Value.First(x => x.Name == "AppProtoModel");
var embedTokenParameters = new GenerateTokenRequest(TokenAccessLevel.Create, dataSet.Id);
var embedToken = await client.Reports.GenerateTokenForCreateInGroupAsync(
_Config.WorkspaceId,
embedTokenParameters,
cancellationToken: cancellationToken);
myDoc.PowerBISettings.EmbedToken = embedToken;
myDoc.PowerBISettings.EmbedUrl = dataSet.CreateReportEmbedURL;
return myDoc;
Currently, PowerBIEmbed component from powerbi-client-react library does not support create mode embedding for Power BI Report and, it can be achieved using Power BI JS SDK.
Refer below code snippets:
const embedConfiguration: IEmbedConfiguration = {
permissions: models.Permissions.All,
tokenType: models.TokenType.Embed,
type: "report",
embedUrl: createReportEmbedURL,
accessToken: createEmbedToken,
viewMode: models.ViewMode.Edit,
datasetId: datasetId,
};
const report = powerbi.createReport(reportContainer, embedConfiguration);
createReportEmbedURL mentioned in above snippet can be generated using Datasets - Get Dataset API.
createEmbedToken mentioned in above snippet can be generated using Embed Token - Report GenerateTokenForCreateInGroup API.
Note: The datasetId passed in the configuration should be the same which is used to generate createReportEmbedURL.
Refer following docs for more information:
Create and save embedded report

Could not pass custom parameters while loading paginated reports in powerbi javascript api

Goal: Load a paginated report into webpage which has few parameters with the help of powerbi api javascript.
Paginated reportUrl:
https://app.powerbi.com/groups/workspaceId/rdlreports/reportId?ctid=something&rp:CustomerID=something&rp:ContractID=something
I can load the report but could not pass the parameters - hence report is loading as blank.
UnLike powerbi report, paginated report doesn't support report.getFilters() like powerBi embedded report.
I referred these docs - but could not find any help...
https://learn.microsoft.com/en-us/power-bi/paginated-reports-parameters
https://learn.microsoft.com/en-us/power-bi/developer/paginated-reports-row-level-security#passing-the-configured-parameter-using-the-embed-token
https://learn.microsoft.com/en-us/power-bi/developer/embed-paginated-reports-customers
This is how I am getting a powerbi report and then embeding that in webpage:
[HttpGet]
[Route("AccessToken")]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult> GetEmbeddedAccessTokenAsync(string reportType)
{
Guid currentReportId = getCurrentReportId(reportType); //private method which gets the report guid
using (var client = await GetPowerBIClientAsync())
{
var report = await client.Reports.GetReportInGroupAsync(_powerBiWorkspaceId, currentReportId);
var generateTokenRequestParameters = new GenerateTokenRequest(accessLevel: TokenAccessLevel.View);
var tokenResponse = await client.Reports.GenerateTokenInGroupAsync(_powerBiWorkspaceId, report.Id, generateTokenRequestParameters);
return new OkObjectResult(JsonSerializer.Serialize(new { EmbedUrl = report.EmbedUrl, AccessToken = tokenResponse.Token, WorkspaceId = _powerBiWorkspaceId, ReportId = report.Id, Expires = tokenResponse.Expiration }));
}
}
let token = await this.http.get(this.url + 'api/PowerBi/AccessToken?reportType=' + this.reportType, { params: {}, responseType: 'text', withCredentials: true }).toPromise();
let tokenObject = JSON.parse(token);
let reportContainer = document.getElementById('kpi-report-container');
this.powerbi.bootstrap(reportContainer, config);
let report: Report = <Report>(this.powerbi.embed(reportContainer, config));
// Report.off removes a given event handler if it exists.
report.off("loaded");
let self = this;
// Report.on will add an event handler which prints to Log window.
report.on("loaded", function () {
self.SelectedReportId(self.reportId);
report.updateSettings({
bookmarksPaneEnabled: false,
filterPaneEnabled: true
});
// Set token expiration listener
self.SetTokenExpirationListener(tokenObject.Expires,
2, /*minutes before expiration*/
tokenObject.ReportId,
tokenObject.WorkspaceId);
});
We can pass the URL parameters into an embedded Paginated Report by concatenating the parameters with the embed URL.
For example:
If we have a parameter named "Salesperson" which has one of its values as "Brownie", then we can filter the Paginated report by concatenating it in the embed URL of the report within report config:
embedUrl + "&rp:Salesperson=Brownie"
The above embedUrl will filter the embedded paginated report as per the given parameter.
You can refer this blog link for more information.

Switch between mobile and desktop view in power bi embedded

I have a power bi report with both desktop and mobile views. I'd like the browser to switch between these views as it resizes. The only way I can currently achieve this is to embed two instances of the report into the browser, one mobile the other desktop, and hide and show them depending on the browser size.
The problem with this is that if I set some filter values when in the desktop view then, narrow the browser so that the mobile view is shown, then the filter values are not same, this obviously being because there are in reality two separate reports.
The other downside of this approach is that I am presumably also incurring the performance cost on my database of generating two reports.
What can I do to only embed a single report that can dynamically switch between mobile and desktop views?
UPDATE Following response below, test code to toggle layout between mobile and custom layout
angular.element($window).on('resize', function () {
if (vm.report === null)
return;
var models = window['powerbi-client'].models;
var newLayout = models.LayoutType.Custom;
if (window.innerWidth < 768) {
newLayout = models.LayoutType.MobilePortrait;
}
if (vm.report.config.settings.layoutType !== newLayout) {
const newSettings = { layoutType: newLayout };
vm.report.updateSettings(newSettings);
}}
UPDATE 2, Added code to show how the report is generated
// report config
var models = window['powerbi-client'].models;
var config = {
type: 'report',
tokenType: models.TokenType.Embed,
accessToken: result.accessToken,
embedUrl: result.embedUrl,
id: result.reportId,
permissions: models.Permissions.View,
viewMode: models.ViewMode.Read,
settings: {
filterPaneEnabled: false,
navContentPaneEnabled: false,
background: models.BackgroundType.Transparent,
layoutType: models.LayoutType.Custom,
customLayout: {
displayOption: models.DisplayOption.FitToPage
}
}
};
// get elements and embed them
var desktopReportContainer = $('.reportContainer')[0];
vm.report = powerbi.embed(desktopReportContainer, config);
Instead of embedding two instances of a report you can do:
Change the layout type by updating settings like here: change-layout-example.
The downside of this approach is that your user's cross filters will not be saved when changing layout.
Before changing the layout type, save a bookmark and then after changing the layout type apply the saved bookmark:
function changeLayout(layoutType) {
report.bookmarksManager.capture()
.then(function (capturedBookmark) {
var bookmarkState = capturedBookmark.state;
var config = {
layoutType: layoutType
};
report.updateSettings(config).then(function () {
report.bookmarksManager.applyState(bookmarkState);
})
})
}
Please note that you will have to add error handling code to the sample above.
Use Custom layout instead of mobile layout like here: Dynamic report layout.
The downside of this approach is that you will have to write code that sets the layout dynamically.
Power BI embed Javascript library has direct support for your case.
First you will need to create a report with mobile layout using Power BI desktop. After you created the report you can embed it using JavaScript SDK. In order to decide in which layout to embed, use the layoutType property of settings in embed configuration.
There are two layout types dedicated to mobile devices:
MobilePortrait - Optimized for portrait view (This is the mobile
layout you created on Power BI desktop)
MobileLandscape - Optimized
for landscape view. This layout looks like the regular report layout.
Load a report in mobile layout Example:
// Get models. models contains enums that can be used.
var models = window['powerbi-client'].models;
var embedConfiguration = {
type: 'report',
id: '5dac7a4a-4452-46b3-99f6-a25915e0fe55',
embedUrl: 'https://app.powerbi.com/reportEmbed',
tokenType: models.TokenType.Embed,
accessToken: 'h4...rf',
settings: {
layoutType: models.LayoutType.MobilePortrait
}
};
Here is the detail guide: https://github.com/Microsoft/PowerBI-JavaScript/wiki/Embed-For-Mobile