A GitHub link has been provided to get the sample application, which demonstrates dashboard rendering with a list of dashboards available in your Bold BI server and is followed by steps to create a new embedding application in the Angular
on your own.
NOTE: The best way to get started would be to read the Getting Started section of the documentation to start using first. The
Getting Started
guide gives you enough information that you need to know before working on the sample. To explore the angular embedding sample in the Bold BI v3.2.16, please refer here.
NOTE: Node.js v14.16 to v18.16 are supported
Please get the Angular with ASP.NET Core sample from GitHub.
Please ensure you have enabled embed authentication on the embed settings
page. If it is not currently enabled, please refer to the following image or detailed instructions to enable it.
To download the embedConfig.json
file, please follow this link for reference. Additionally, you can refer to the following image for visual guidance.
Copy the downloaded embedConfig.json
file and paste it into the designated location within the application. Please ensure you have placed it in the application as shown in the following image.
ServerUrl | Dashboard Server BI URL (ex: http://localhost:5000/bi, https://demo.boldbi.com/bi) |
SiteIdentifier | For the Bold BI Enterprise edition, it should be like site/site1. For Bold BI Cloud, it should be an empty string. |
UserEmail | UserEmail of the Admin in your Bold BI, which would be used to get the dashboard list. |
EmbedSecret | Get your EmbedSecret key from the Embed tab by enabling the Enable embed authentication in the Administration page |
Environment | Your Bold BI application environment. (If it is a cloud analytics server, use `BoldBI.Environment.Cloud`; if it is your server, use `BoldBI.Environment.Enterprise`) |
DashboardId | Item ID of the dashboard to be embedded in your application. |
ExpirationTime | Token expiration time. (In the EmbedConfig.json file, the default token expiration time is 10000 seconds) |
Here, the Angular application acts as a client, and the ASP.NET Core application acts as a server since you need to set the following properties in the app.component.ts
file.
Open your Angular with ASP.NET Core project in Visual Studio Code
and install all dependent packages, using the following command npm install
.
Execute the command dotnet restore
to restore the necessary packages. Once the packages have been restored, use the dotnet build
command to build the project.
Run your Angular with ASP.NET Core sample with the command dotnet run
in Visual Studio Code.
The dashboard can be editable in design mode and create a new dashboard with the following changes in the renderDashboard()
method.
dashboardId | Provide the dashboard ID of the dashboard you want to embed in view or edit mode. In order to create a new dashboard, please exclude this specific property. |
mode | In which mode do you want to render the dashboard? It can either be 'BoldBI.Mode.View' or 'BoldBI.Mode.Design' mode. |
authorizationServer | Url of the 'authorizationServerAPI' action in the application. |
renderDashboard(dashboard: Item) {
this.dashboard= BoldBI.create({
serverUrl: this._appComponent.baseUrl,
dashboardId: dashboard.Id,
embedContainerId: "dashboard",
embedType: this.dashboardService.embedConfig.EmbedType,
environment: this.dashboardService.embedConfig.Environment,
width:"100%",
height:"100%",
expirationTime:100000,
authorizationServer: {
url:this._appComponent.apiHost + this._appComponent.authorizationUrl
}
});
this.dashboard.loadDashboard();
}
Based on the configured embedConfig values in the app.component.ts
file, the GetDashboards()
method would be called from the ngOnInit()
in the dashboard-listing.component.ts
.
Above the GetDashboards()
method would call the GetDashboards
action in the BoldBIEmbedController
of the ASP.NET Core server module.
By default, the first dashboard is rendered from the list using the renderDashboard()
method in the dashboards-listing.component.ts
file. This render method implemented with the Bold BI SDK component code.
Before rendering, the authorizationUrl
is called, which redirects to the AuthorizationServer
action in the BoldBIEmbedController
, which generates the EmbedSignature
using the embed secret provided in the embedConfig.json
of the ASP.NET Core application.
These details will be sent to the Bold BI server and validated there. Once details are validated, the dashboard starts to render.
Create a folder in the desired location and open it in the Visual Studio Code.
Open the terminal in the Visual Studio Code. Please refer to the following image.
To create a new project, run this command in the terminal.
dotnet new angular
Please ensure you have enabled embed authentication on the embed settings
page. If it is not currently enabled, please refer to the following image or detailed instructions to enable it.
To download the embedConfig.json
file, please follow this link for reference. Additionally, you can refer to the following image for visual guidance.
Copy the downloaded embedConfig.json
file and paste it into the designated location within the application. Please ensure you have placed it in the application, as shown in the following image.
Create a new folder called Models
. Create a model class as DataClass.cs
to define the following properties. These properties are used to get the dashboard details from the server.
Execute the following commands in the terminal to add the necessary references to the project: dotnet add package Newtonsoft.Json
and dotnet add package System.Runtime.Serialization.Primitives
. Ensure the System.Runtime.Serialization
and Newtonsoft.Json
namespaces are in the DataClass.cs
model file.
[DataContract]
public class EmbedClass
{
[DataMember]
public string embedQuerString { get; set; }
[DataMember]
public string dashboardServerApiUrl { get; set; }
}
public class TokenObject
{
public string Message { get; set; }
public string Status { get; set; }
public string Token { get; set; }
}
public class Token
{
[JsonProperty("access_token")]
public string AccessToken {get;set;}
[JsonProperty("token_type")]
public string TokenType {get;set; }
[JsonProperty("expires_in")]
public string ExpiresIn {get; set;}
[JsonProperty("email")]
public string Email {get;set;}
public string LoginResult {get;set;}
public string LoginStatusInfo {get;set;}
[JsonProperty(".issued")]
public string Issued { get; set; }
[JsonProperty(".expires")]
public string Expires { get; set; }
}
public class EmbedDetails
{
public string Environment { get; set; }
public string SiteIdentifier { get; set; }
public string ServerUrl { get; set; }
public string EmbedSecret { get; set; }
public string UserEmail { get; set; }
public string EmbedType { get; set; }
public string DashboardId { get; set; }
}
Create another model class as GlobalAppSettings.cs
to define the following properties. These properties maintain the embedConfig.json
file object within the GlobalAppSettings
.
public class GlobalAppSettings
{
public static EmbedDetails EmbedDetails { get; set; }
}
Create a new controller as BoldBIEmbedController.cs
. In the Controllers\BoldBIEmbedController.cs
, To get particular dashboard details, define the API GetDetails()
which uses the GetSignatureUrl()
method to generate the algorithm. In this API, embedQuerString
,userEmail
and the value from the GetSignatureUrl()
method are appended as query parameters in the URL to get details of a particular dashboard.
[ApiController]
[Route("api/[controller]")]
public class BoldBIEmbedController : Controller
{
[HttpGet]
[Route("GetData")]
public IActionResult GetData()
{
var jsonData = System.IO.File.ReadAllText("embedConfig.json");
return Ok(jsonData);
}
[HttpGet]
[Route("GetDashboards")]
public string GetDashboards()
{
var token = GetToken();
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(GlobalAppSettings.EmbedDetails.ServerUrl);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Add("Authorization", token.TokenType + " " + token.AccessToken);
var result = client.GetAsync(GlobalAppSettings.EmbedDetails.ServerUrl + "/api/" + GlobalAppSettings.EmbedDetails.SiteIdentifier + "/v2.0/items?ItemType=2").Result;
string resultContent = result.Content.ReadAsStringAsync().Result;
return resultContent;
}
}
public Token GetToken()
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(GlobalAppSettings.EmbedDetails.ServerUrl);
client.DefaultRequestHeaders.Accept.Clear();
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("grant_type", "embed_secret"),
new KeyValuePair<string, string>("Username", GlobalAppSettings.EmbedDetails.UserEmail),
new KeyValuePair<string, string>("embed_secret", GlobalAppSettings.EmbedDetails.EmbedSecret)
});
var result = client.PostAsync(GlobalAppSettings.EmbedDetails.ServerUrl + "/api/" + GlobalAppSettings.EmbedDetails.SiteIdentifier + "/token", content).Result;
string resultContent = result.Content.ReadAsStringAsync().Result;
var response = JsonConvert.DeserializeObject<Token>(resultContent);
return response;
}
}
}
In the Controllers\BoldBIEmbedController.cs
, To get particular dashboard details, define an API AuthorizationServer()
which uses the method GetSignatureUrl()
to generate the algorithm. In this API, the embedQuerString
,userEmail
and the value from the GetSignatureUrl()
method are appended as query parameters in the URL to get details of a particular dashboard. With these details, the renderDashboard()
method is called in the angular application.
[HttpPost]
[Route("AuthorizationServer")]
public string AuthorizationServer([FromBody] object embedQuerString)
{
var embedClass = Newtonsoft.Json.JsonConvert.DeserializeObject<EmbedClass>(embedQuerString.ToString());
var embedQuery = embedClass.embedQuerString;
// User your user-email as embed_user_email
embedQuery += "&embed_user_email=" + GlobalAppSettings.EmbedDetails.UserEmail;
//To set embed_server_timestamp to overcome the EmbedCodeValidation failing while different timezone using at client application.
double timeStamp = (int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
embedQuery += "&embed_server_timestamp=" + timeStamp;
var embedDetailsUrl = "/embed/authorize?" + embedQuery + "&embed_signature=" + GetSignatureUrl(embedQuery);
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(embedClass.dashboardServerApiUrl);
client.DefaultRequestHeaders.Accept.Clear();
var result = client.GetAsync(embedClass.dashboardServerApiUrl + embedDetailsUrl).Result;
string resultContent = result.Content.ReadAsStringAsync().Result;
return resultContent;
}
}
public string GetSignatureUrl(string queryString)
{
if (queryString != null)
{
var encoding = new System.Text.UTF8Encoding();
var keyBytes = encoding.GetBytes(GlobalAppSettings.EmbedDetails.EmbedSecret);
var messageBytes = encoding.GetBytes(queryString);
using (var hmacsha1 = new HMACSHA256(keyBytes))
{
var hashMessage = hmacsha1.ComputeHash(messageBytes);
return Convert.ToBase64String(hashMessage);
}
}
return string.Empty;
}
Open the Program.cs
file and add the following code sample before app.UseHttpsRedirection()
. To read the embedConfig.json
file in order to utilize it in the controller. The existing MapControllerRoute
pattern inside the controller
name and action
name changed as follows. Ensure the using using Newtonsoft.Json
namespaces in the Program.cs
file.
app.UseCors(corsPolicyBuilder => corsPolicyBuilder
.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
string basePath = AppDomain.CurrentDomain.BaseDirectory;
string jsonString = System.IO.File.ReadAllText(Path.Combine(basePath, "embedConfig.json"));
GlobalAppSettings.EmbedDetails = JsonConvert.DeserializeObject<EmbedDetails>(jsonString);
app.MapControllerRoute(
name: "default",
pattern: "{BoldBIEmbed}/{action=GetData}/{id?}");
Create a new file and name it package.json
. It is essential to install the packages listed in the dependencies section below.
{
"name": "angular-sample",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test"
},
"private": true,
"dependencies": {
"@boldbi/boldbi-embedded-sdk": "^6.4.6",
"@angular/animations": "^14.0.0",
"@angular/common": "^14.0.0",
"@angular/compiler": "^14.0.0",
"@angular/core": "^14.0.0",
"@angular/forms": "^14.0.0",
"@angular/platform-browser": "^14.0.0",
"@angular/platform-browser-dynamic": "^14.0.0",
"@angular/router": "^14.0.0",
"rxjs": "~7.5.0",
"tslib": "^2.3.0",
"zone.js": "~0.11.4",
"@angular-devkit/build-angular": "^14.0.0",
"@angular/cli": "^14.0.6",
"@angular/compiler-cli": "^14.0.0"
}
}
Open the folder ClientApp\src\app
and create a dashboard-listing
folder with a dashboard-listing.component.html
and dashboard-listing.component.ts
files in it. In the app.component.ts
file replace the following code, define the mandatory properties, and invoke the ngOnInit()
which is implemented in the dashboard-listing.component.ts
method as follows.
import { Component } from '@angular/core';
import { appService } from './app.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
//ASP.NET Core application would be run on https://localhost:7210;http://localhost:5279, which needs to be set as `apiHost`
public apiHost = "https://localhost:7210/";
//Url of the GetDetails action in ValuesController of the ASP.NET Core application
public authorizationUrl = "api/boldbiembed/authorizationserver";
//Url of the GetDashboards action in ValuesController of the ASP.NET Core application
public getDashboardsUrl = "api/boldbiembed/getdashboards";
public getEmbedConfigUrl = "api/boldbiembed/getdata";
public embedConfig: any;
public dashboards: any;
public baseUrl: any;
public dashboardServerApiUrl!: string;
constructor(private _app: appService) {
}
ngOnInit() {
}
}
NOTE: Open the
launchSettings.json
file,applicationUrl
is copied and pasted inapiHost
.
In the dashboard-listing.component.html
file, create the DOM element to render the dashboard and its list as follows.
<div id="viewer-section">
<div id="dashboard"></div>
</div>
In the Index.html
file, refer to the following cdn files in the <head>
tag.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Embedded BI</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="stylesheet" href="./assets/css/site.css" />
</head>
<body><app-root></app-root></body>
</html>
In the dashboard-listing.component.ts
, you need to implement the ngOnInit()
and renderDashboard()
methods. In the ngOnInit()
method, assign value for the baseUrl
and dashboardServerApiUrl
, which is used by the renderDashboard()
method to render the dashboard. Invoke the getDashboard()
with the token to get the dashboard details and dashboard list from server.
import { Component, OnInit } from '@angular/core';
import { Item } from '../app';
import { appService } from '../app.service';
import { AppComponent } from '../app.component';
import { BoldBI } from '@boldbi/boldbi-embedded-sdk';
import { DashboardService } from '../dashboard.service';
@Component({
selector: 'app-dashboard-listing',
templateUrl: './dashboard-listing.component.html',
providers: [appService]
})
export class DashboardListing implements OnInit {
public dashboardsList!: Item[];
result: any;
dashboard: any;
embedConfig: any;
constructor(private _app: appService, private _appComponent: AppComponent, private dashboardService: DashboardService) {
}
ngOnInit() {
this._app.GetEmbedConfig(this._appComponent.apiHost + this._appComponent.getEmbedConfigUrl).subscribe(data => {
this._appComponent.embedConfig = <any>data;
this.dashboardService.setEmbedConfig(this._appComponent.embedConfig);
if (this.dashboardService.embedConfig.Environment == "enterprise" || this.dashboardService.embedConfig.Environment == "onpremise") {
this._appComponent.baseUrl = this.dashboardService.embedConfig.ServerUrl + "/" + this.dashboardService.embedConfig.SiteIdentifier;
this._appComponent.dashboardServerApiUrl = this.dashboardService.embedConfig.ServerUrl + "/api/" + this.dashboardService.embedConfig.SiteIdentifier;
} else {
this._appComponent.baseUrl = this.dashboardService.embedConfig.ServerUrl;
this._appComponent.dashboardServerApiUrl = this.dashboardService.embedConfig.ServerUrl + "/api";
}})
}
}
In the getDashboard
, the dashboard list is obtained from the server and passed to the dashboardDetails()
method to render a dashboard.
this._app.GetDashboards(this._appComponent.apiHost + this._appComponent.getDashboardsUrl). subscribe(data => {
this._appComponent.dashboards = <any>data;
this.dashboardsList = this._appComponent.dashboards;
this.renderDashboard(this.dashboardsList[0]);
});
Once the server sends the response to the GetDashboards()
of an angular application, this method returns the response to the ngOnInit()
method to call the renderDashboard()
method.
In the renderDashboard()
method, an instance is created to render a dashboard using the loadDashboard()
method as follows.
renderDashboard(dashboard: Item) {
this.dashboard = BoldBI.create({
serverUrl: this._appComponent.baseUrl,
dashboardId: this.dashboardService.embedConfig.DashboardId,
embedContainerId: "dashboard",
embedType: this.dashboardService.embedConfig.EmbedType,
environment: this.dashboardService.embedConfig.Environment,
width: "100%",
height: "100%",
expirationTime: 100000,
authorizationServer: {
url: this._appComponent.apiHost + this._appComponent.authorizationUrl
}
});
console.log(this.dashboard);
this.dashboard.loadDashboard();
}
Open the app.component.html
file and replace the following code.
<body>
<main class="dashboard_container"><router-outlet></router-outlet></main>
</body>
Open the app.module.ts
file and replace the following code. The necessary modules and components are imported.
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { RouterModule } from '@angular/router';
import { appService } from './app.service';
import { AppComponent } from './app.component';
import { NavMenuComponent } from './nav-menu/nav-menu.component';
import { DashboardListing } from './dashboard-listing/dashboard-listing.component';
import { CounterComponent } from './counter/counter.component';
import { FetchDataComponent } from './fetch-data/fetch-data.component';
@NgModule({
imports: [
BrowserModule,
RouterModule.forRoot([
{ path: '', component: DashboardListing },
]
),
HttpClientModule
],
providers: [appService],
declarations: [
AppComponent,
DashboardListing,
NavMenuComponent,
CounterComponent,
FetchDataComponent
],
bootstrap: [AppComponent]
})
export class AppModule { }
Open the folder ClientApp\src\app
and create a new file called app.service.ts
file, include the following code.
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http';
import { HashLocationStrategy } from '@angular/common';
@Injectable()
export class appService {
private authUrl!: string;
private getDashboardsUrl!: string;
private header!: HttpHeaders;
constructor(private http: HttpClient) {
}
public GetDashboards(getDashboardsUrl: string) {
this.header = new HttpHeaders();
this.header = this.header.append('Access-Control-Allow-Origin', '*');
this.header = this.header.append('Authorization', 'bearer ' + "token");
return this.http.get(getDashboardsUrl, {
headers: this.header
}).pipe(res => {
return <any>res;
});
}
public GetEmbedConfig(getDashboardsUrl: string) {
return this.http.get(getDashboardsUrl, {
}).pipe(res => {
return <any>res;
}); }
}
Open the folder ClientApp\src\app
and create a new file called app.ts
and include the following code.
export class Item {
Name!: string;
Description!: string;
Id!: string;
Version!: string;
IsPublic!: boolean;
ItemLocation!: string;
CategoryName!: string;
}
Open the folder ClientApp\src\app
and create a new file called dashboard.service.ts
and including the following code. These properties are used to get and set the value of this property.
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class DashboardService {
public embedConfig: any;
getEmbedConfig(): any {
return this.embedConfig;
}
setEmbedConfig(embedConfig: any): void {
this.embedConfig = embedConfig; }
}
Open the assets
folder and create a subfolder
named css
. Within the css
folder, create a new file called site.css
and place the provided code inside it
body html { width: 100%; height: 100%; }
html, body,app-root { width: 100%; height: 100%; margin: 0; font-family: Roboto; font-size: 13px;}
ul { list-style-type: none; padding-left: 0; }
.tab { padding-top: 2px; padding-bottom: 18px; cursor: pointer }
.active { background-color: burlywood; }
.e-dbrd-blueWaitingIndcator {
-webkit-animation: rotate 2s linear infinite; animation: rotate 2s linear infinite; height: 54px; width: 54px; top: 50%; left: 50%; position: relative; }
.e-waiting { position: fixed; display: block; margin: 0px auto; width: 54px; height: 54px; zoom: 0.5; margin-left: 55px;}
#container { width: 13%; float: left; height: 100%; float: left; background: #f4f4f4; height: 100%; box-shadow: 2px 0 4px 0 rgba(0, 0, 0, .12); overflow: auto; overflow-x: hidden; }
#grid-title { font-size: 17px; border-bottom: 1px solid #333; padding: 15px;}
#panel { width: 100%; float: left; background: #f4f4f4; overflow: auto;}
#dashboard { width: 100%; float: left; height: 100%; display: block; }
.dashboard-item { padding: 10px; border-bottom: 1px solid #ccc; cursor: pointer; }
#viewer-section { width: 100%; height: 100%; float: left; }
#viewer-header { padding: 10px; display: block; float: left; width: 100%; }
#create-dashboard { float: right; margin-right: 20px; background: #0565ff; border: 0; border-radius: 4px; color: #fff;cursor: pointer; display: inline-block;font-size: 12px; font-weight: 600;height: 28px;line-height: 28px; min-width: 90px; outline: none; text-align: center;border: 1px solid #0450cc; }
#edit-dashboard {
float: right; background: #fff; margin-right: 20px; border: 0; border-radius: 4px; color: #333; cursor: pointer; display: inline-block; font-size: 12px; font-weight: 600; height: 28px; line-height: 28px; min-width: 90px; outline: none; text-align: center; border: 1px solid #b3b3b3; }
#dashboardDesigner{ height: 900px; border: 2px solid #333; }
.dashboard_container { height: 775px !important; width: 1685px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; margin-bottom: 0px !important;}
.e-waitpopup-pane { display: none; }
To install all dependent packages, use the following command npm install
.
Run the ASP.NET core and angular applications using the dotnet run
command.