Web components are not supported in server-side rendering (SSR) environments. This example assumes that your Angular application is running entirely on the browser (client-side only). If you attempt to use the chart component library within SSR frameworks (such as Angular Universal) without proper dynamic import or client-side rendering guards, you may encounter errors.
Instantiating the Nebuly Charts Client
To get started, you’ll first need to instantiate the Nebuly Charts client.
The following code snippet shows how to do this by importing the library and creating a client instance using your API key:
import NebulyReports from '@nebuly-ai/reports';
const client = new NebulyReports.Client({
publicKey: '<YOUR_NEBULY_PUBLIC_KEY>',
});
Providing the Nebuly Client via Angular Services
Next, it’s best practice in Angular to provide the Nebuly client throughout your app using Angular’s dependency injection system.
This lets any component access the client instance via dependency injection, without having to pass it through inputs manually.
Here’s how you can create a service for the Nebuly client:
// services/nebuly-client.service.ts
import { Injectable } from '@angular/core';
import NebulyReports from '@nebuly-ai/reports';
@Injectable({
providedIn: 'root'
})
export class NebulyClientService {
private client: InstanceType<typeof NebulyReports.Client>;
constructor() {
this.client = new NebulyReports.Client({
baseUrl: "http://localhost:8080/api/external",
publicKey: "<YOUR_NEBULY_PUBLIC_KEY>",
});
}
getClient(): InstanceType<typeof NebulyReports.Client> {
return this.client;
}
}
Registering Nebuly Web Components in Angular
To use Nebuly web components (such as charts) in your Angular application, you need to register them once—usually in your main entry point file.
This enables the custom HTML elements to be recognized by the browser.
The snippet below demonstrates how to do this within an Angular application setup:
// main.ts
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import NebulyReports from '@nebuly-ai/reports/web';
import { AppModule } from './app/app.module';
NebulyReports.registerComponents();
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
Displaying a List of Reports
If you want to display a list of available reports fetched from the Nebuly API, you can define a simple component that leverages the client service and handles loading and error states gracefully.
Here’s an example implementation:
// components/reports-list.component.ts
import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Router } from '@angular/router';
import { NebulyClientService } from '../services/nebuly-client.service';
interface Report {
id: string;
title: string;
}
@Component({
selector: 'app-reports-list',
standalone: true,
imports: [CommonModule],
template: `
<div>
<div *ngIf="error">
Error: {{ error.message }}
</div>
<div *ngIf="isLoading">
Loading...
</div>
<div *ngIf="!isLoading && !error">
<button
*ngFor="let report of reports"
(click)="goToReport(report.id)"
>
{{ report.title }}
</button>
</div>
</div>
`
})
export class ReportsListComponent implements OnInit {
reports: Report[] = [];
isLoading = true;
error: Error | null = null;
constructor(
private nebulyClientService: NebulyClientService,
private router: Router
) {}
ngOnInit() {
this.loadReports();
}
goToReport(reportId: string) {
this.router.navigate(['/report', reportId]);
}
private async loadReports() {
try {
this.isLoading = true;
const client = this.nebulyClientService.getClient();
this.reports = await client.listReports();
} catch (err) {
this.error = err as Error;
} finally {
this.isLoading = false;
}
}
}
Rendering a Report and Its Charts
Once a user selects a report, you’ll want to fetch detailed data for that report and render the associated charts.
The following example demonstrates how you might build a Report
component that retrieves report data, supports loading and error handling, and renders each chart using a separate ChartComponent
:
// components/report.component.ts
import { Component, OnInit, Input } from '@angular/core';
import { CommonModule } from '@angular/common';
import { NebulyClientService } from '../services/nebuly-client.service';
import { ChartComponent } from './chart.component';
interface ChartData {
id: string;
type: string;
data: any;
}
interface ReportData {
title: string;
charts: ChartData[];
}
@Component({
selector: 'app-report',
standalone: true,
imports: [CommonModule, ChartComponent],
template: `
<div *ngIf="error">
Error: {{ error.message }}
</div>
<div *ngIf="isLoading">
Loading...
</div>
<div *ngIf="!isLoading && !error" style="display: flex; flex-direction: column; gap: 1rem;">
<h1>{{ reportData?.title }}</h1>
<div *ngFor="let chart of reportData?.charts">
<app-chart [chart]="chart"></app-chart>
</div>
</div>
`
})
export class ReportComponent implements OnInit {
@Input() reportId!: string;
reportData: ReportData | null = null;
isLoading = true;
error: Error | null = null;
constructor(private nebulyClientService: NebulyClientService) {}
ngOnInit() {
this.loadReport();
}
private async loadReport() {
try {
this.isLoading = true;
const client = this.nebulyClientService.getClient();
this.reportData = await client.getReport({ reportId: this.reportId });
} catch (err) {
this.error = err as Error;
} finally {
this.isLoading = false;
}
}
}
ChartComponent: Rendering Nebuly Chart Types
The ChartComponent
helper function is responsible for rendering the appropriate Nebuly chart web component based on the chart type.
You can set up your chart option objects and extend the switch statement to support all the chart types you need:
// components/chart.component.ts
import { Component, Input } from '@angular/core';
import { CommonModule } from '@angular/common';
import type { ChartData } from '@nebuly-ai/reports';
import type { ChartCustomizationOptions } from '@nebuly-ai/reports/web';
// Define your chart options as needed.
const lineOptions: ChartCustomizationOptions = { /* ... */ };
const metricOptions: ChartCustomizationOptions = { /* ... */ };
const horizontalBarOptions: ChartCustomizationOptions = { /* ... */ };
@Component({
selector: 'app-chart',
standalone: true,
imports: [CommonModule],
template: `
<nebuly-line-chart
*ngIf="chart.type === 'line_chart'"
[data]="chartDataString"
[options]="chartOptionsString">
</nebuly-line-chart>
<nebuly-metric-chart
*ngIf="chart.type === 'metric'"
[data]="chartDataString"
[options]="chartOptionsString">
</nebuly-metric-chart>
<nebuly-horizontal-bar-chart
*ngIf="chart.type === 'horizontal_bar_chart'"
[data]="chartDataString"
[options]="chartOptionsString">
</nebuly-horizontal-bar-chart>
`
})
export class ChartComponent {
@Input() chart!: ChartData;
get chartDataString(): string {
return JSON.stringify(this.chart.data);
}
get chartOptionsString(): string {
switch (this.chart.type) {
case 'line_chart':
return JSON.stringify(lineOptions);
case 'metric':
return JSON.stringify(metricOptions);
case 'horizontal_bar_chart':
return JSON.stringify(horizontalBarOptions);
// Add additional chart type cases here as needed
default:
throw new Error(`Unknown chart type: ${this.chart.type}`);
}
}
}