Show mobile version of powerbi page in powerapps portals - powerbi

We are trying to get a PowerBi report embedded in a Powerapps portal to show the mobile view of the report.
As described here, I’m testing with a report which only have mobile enabled pages.
This is the code I use to request the mobile version, as documented here.
let report = (await powerbi.get($('.portal-pbi-embedded')[0]))
let page = (await report.getPages()).find(i=>i.isActive);
console.log(await page.hasLayout(window['powerbi-client'].models.LayoutType.MobilePortrait))
// true
console.log(await report.updateSettings({layoutType: window['powerbi-client'].models.LayoutType.MobilePortrait}))
// {statusCode: 202, headers: {…}, body: undefined}
It appears that PowerBi can see that there is a mobile layout for the active page, and the updateSettings commands executes without errors, but nothing happens.
I also tried embedding the report again, where I request the mobile layout upfront, this gives the same behaviour (only showing the desktop version).
I recognized that the powerbi client version that powewrapps portals uses is a bit old (version 2.6.5). Even though that we are running the latest version of the portal that are available to us (9.3.2205.12).
Question 1: How do we show the mobile version of the report in the portal?
Question 2: Is there a way to update the powerbi client in the portal?

First Question
you should note the following (from docs):
after the report initial load, changing to report mobile layout is
supported only if mobile layout (portrait/landscape) has been set into
the initial embedding configuration object. Otherwise, you must first
call powerbi.reset(HTMLElement) to remove the iframe. Then, you have
to call powerbi.embed(...) using the same container with the mobile
layout setting defined on the embedded configuration object.
So basically, you are facing two options:
First Option - In your Configuration, use the following concept to control your visuals:
let models = window['powerbi-client'].models;
let embedConfig = {
type: 'report',
id: reportId,
embedUrl: 'https://app.powerbi.com/reportEmbed',
tokenType: models.TokenType.Embed,
accessToken: 'H4...rf',
settings: {
layoutType: models.LayoutType.Custom
customLayout: {
pageSize: {
type: models.PageSizeType.Custom,
width: 1600,
height: 1200
},
displayOption: models.DisplayOption.ActualSize,
pagesLayout: {
"ReportSection1" : {
defaultLayout: {
displayState: {
mode: models.VisualContainerDisplayMode.Hidden
}
},
visualsLayout: {
"VisualContainer1": {
x: 1,
y: 1,
z: 1,
width: 400,
height: 300,
displayState: {
mode: models.VisualContainerDisplayMode.Visible
}
},
"VisualContainer2": {
displayState: {
mode: models.VisualContainerDisplayMode.Visible
}
},
}
}
}
}
}
};
...
// Embed the report and display it within the div container.
let report = powerbi.embed(embedContainer, embedConfig);
The second option - use the reset method:
powerbi.reset(HTMLElement)
powerbi.embed(...)
Second Question
I'm not sure that I understood your question correctly, but if I did - take a look here (https://learn.microsoft.com/en-us/javascript/api/overview/powerbi/update-settings)

Related

power bi embedded "hide toolbar paginated report"

I'm trying to embed Power BI Reports(User Owns Data)
could you please help me how to hide tool bar for paginated report in power bi embedded
?
what is the setting to hide the tool bar
var config = {
type: 'report',
tokenType: models.TokenType.Embed,
accessToken: accessToken,
embedUrl: embedUrl ,
id: embedReportId,
permissions: models.Permissions.All,
settings: {
bars: {
actionBar: {
visible: false
}
},
filterPaneEnabled: false,
navContentPaneEnabled: false
},
};
The paginated report does not support hiding toolbar. It only supports enable/disable and expand/collapse of parameters pane.
For more details on paginated report embed capabilities please refer:
https://learn.microsoft.com/en-us/javascript/api/overview/powerbi/embed-paginated-report

Embedded PowerBi report using mobile layout

I'm trying to display an embedded PowerBi report from an external website (a html page served by nodejs). I can display the report with desktop layuot but not with mobile layout (the mobile layout is already created and published).
¿How can I embed a report using the mobile layout?
This is my report configuration:
let reportLoadConfig = {//type: report
type: "report",
tokenType: models.TokenType.Embed,
accessToken: embedData.accessToken,
// Use other embed report config based on the requirement. We have used the first one for demo purpose
//embedUrl: embedData.embedUrl[0].embedUrl,
embedUrl:embedData.embedUrl[0].embedUrl,
// Enable this setting to remove gray shoulders from embedded report
settings: {
//background: models.BackgroundType.Transparent,
layoutType: models.LayoutType.MobilePortrait,
filterPaneEnabled: false,
navContentPaneEnabled: false
}
};
// Embed Power BI report when Access token and Embed URL are available
let report = powerbi.embed(reportContainer, reportLoadConfig);
If you are using the Embed Power BI GitHub Examples, please verify:
1- All report pages have to have a mobile layout created.
2- Set the property layoutType to MobilePortrait in report Config var (client side JavaScript code)
3- If your code uses powerbi.bootstrap, verify this part:
//powerbi.bootstrap(reportContainer, { type: "report" }); //This was the default code example
//I changed the code to:
powerbi.bootstrap(
reportContainer,
{
type: 'report',
hostname: "https://app.powerbi.com",
settings: {
layoutType: models.LayoutType.MobileLandscape
}
}
);
4- Inside index.js (client side JavaScript) Verify the code:
let reportLoadConfig = {//type: report
type: "report",
tokenType: models.TokenType.Embed,
accessToken: embedData.accessToken,
// Use other embed report config based on the requirement. We have used the first one for demo purpose
//embedUrl: embedData.embedUrl[0].embedUrl,
embedUrl:embedData.embedUrl[0].embedUrl,
// Enable this setting to remove gray shoulders from embedded report
settings: {
//background: models.BackgroundType.Transparent,
layoutType: models.LayoutType.MobilePortrait,
filterPaneEnabled: false,
navContentPaneEnabled: false
},
};
5- Finally, you can write a custom javascript function (on client side) to verify the screen size and load landscape or portrait layout, something like this:
window.addEventListener('resize', async ()=>{
//write a function to detect the screen size
let isMobile=await isMobileScreen();
let newSettings = {
layoutType: models.LayoutType.MobileLandscape
};
if(isMobile){ //this returns true or false
newSettings = {
layoutType: models.LayoutType.MobilePortrait
};
report.updateSettings(newSettings);//update the report settings
}else{
report.updateSettings(newSettings); //update the report settings
}});
Here's our script. I'm just the middle man, so I don't fully undertand it. What I understood was that Luis' script needed to refresh the page before the new layout took effect. Our changes address that.
let isMobile = window.matchMedia("only screen and (max-width: 760px)").matches;
let newSettings = {
layoutType: models.LayoutType.MobileLandscape
};
if (isMobile) { //this returns true or false
newSettings = {
layoutType: models.LayoutType.MobilePortrait
};
}
// Initialize iframe for embedding report
//powerbi.bootstrap(reportContainer, { type: "report" });
powerbi.bootstrap(
reportContainer,
{
type: 'report',
hostname: "https://app.powerbi.com",
settings: newSettings
}
);
$.ajax({
type: "GET",
url: "/embedinfo/getebiriver",
success: function (data) {
embedData = $.parseJSON(data);
reportLoadConfig = {
type: "report",
tokenType: models.TokenType.Embed,
accessToken: embedData.EmbedToken.Token,
// You can embed different reports as per your need
embedUrl: embedData.EmbedReport[0].EmbedUrl,
// settings config
settings: newSettings
};
Feel free to copy/combine and roll the answer into your own, and then i'll delete this.

Power BI Embedded, Generate Embed Token only with View Access

I have embedded the power bi report using service principal as given here.
I'm generating the embed token as below,
var generateTokenRequestParameters = new GenerateTokenRequest(accessLevel:"View",allowSaveAs:false,identities: new EffectiveIdentity[] { new EffectiveIdentity(username: serviceAccount, roles: new string[] { "Viewer" }, datasets: new string[] { report.DatasetId }) });
EmbedToken embedToken = client.Reports.GenerateTokenInGroup(groupId, reportId, generateTokenRequestParameters);
But when I embed the report using javascript sdk, if I configure the permission as below the user able to edit the reports. How can prevent the user from editing the report in the embed token?
permissions: models.Permissions.ReadWrite,
viewMode: models.ViewMode.Edit,
I have a C# MVC Web Application which embeds PowerBI reports.
Here is our embed config
var config = {
type: 'report',
id: embedReportId,
accessToken: accessToken,
tokenType: models.TokenType.Embed,
embedUrl: embedUrl,
permissions: models.Permissions.View,
settings: {
filterPaneEnabled: false,
navContentPaneEnabled: true,
background: models.BackgroundType.Transparent,
layoutType: models.LayoutType.Custom,
customLayout: {
displayOption: models.DisplayOption.FitToWidth
}
}
};
You mentioned the viewMode property in your question. As you can see we do not even set the viewMode property in our config. We only set the permissions property but as far as I can tell it doesn't do much. This property is rarely used or only controls minor things you can see on the UI.
If you generate the access token like you are for "View" and someone edits the embedding report viewer page to change the permission property from models.Permissions.View to models.Permissions.ReadWrite in the HTML/javascript any subequent calls the PowerBI JavaScript library attempts to make after that report viewer page edit would fail because the accesss token that was generated is for View and not Edit and the API calls to Microsoft/PowerBI would fail.
So you really just need to make sure your back end logic is generating the correct access token for whatever the viewing context is. If you were generating an access token with full permissions and using the PowerBI javascript library to hide things then users could potentially alter your page source and do more than you wanted.
Good luck

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

Html4 browsers does not support history.pushState and history.replaceState methods of History API from HTML5

I am working on an ember application (using ember-1.0.pre.js). And I'm trying to provide cross browser compatibility on IE8.
The issue is with url generate after every transition, it seems incorrect/falsy to user. Let say I hit the url like the_ domain_name/sell/new which initially land me to on sell page of our application. and then i tries to transit a new state called "Purchase" which will land me on purchase page of our application. The new state transition generates a URL the_ domain_name/sell/new#/offers/purchase?&suid=1365149991779013736531657156165 in IE8 addressbar instead of the domain_name/offers/purchase.
Note: the_domain_name = http://www.example.com
The generated url includes two incorrect things,
The initial prefix "/sell/new#".
The parameter "?&_suid=1365149991779013736531657156165" in query string of url.
I tried to figure out the issue and found that HTML4 browsers does not supports pushState and replaceState methods from History API from HTML5. How can i provide the support on IE8 Can anyone help me on this?
I suggest History.js as polyfill for browsers not support History API: https://github.com/browserstate/history.js
It is working in:
HTML5 Browsers:
Firefox 4+
Chrome 8+
Opera 11.5
Safari 5.0+
Safari iOS 4.3+
HTML4 Browsers:
IE 6, 7, 8, 9
Firefox 3
Opera 10, 11.0
Safari 4
Safari iOS 4.2, 4.1, 4.0, 3.2
Add jquery.history.js & Register a history.js location handler into you Ember App.
Here are the parts I modified from original Ember.HistoryLocation ( Full code )
(function() {
var get = Ember.get, set = Ember.set;
var popstateFired = false;
Ember.HistoryJsLocation = Ember.Object.extend({
initState: function() {
this.replaceState(this.formatURL(this.getURL()));
set(this, 'history', window.History);
},
getState: function() {
return get(this, 'history').getState().state;
},
pushState: function(path) {
History.pushState({ path: path }, null, path);
},
replaceState: function(path) {
History.replaceState({ path: path }, null, path);
}
});
Ember.Location.registerImplementation('historyJs', Ember.HistoryJsLocation);
})();
Then use this polyfill in your App:
App.Router.reopen({
location: 'historyJs'
});