# Integration with Angular
The HyperFormula API is identical in an Angular app and in plain JavaScript. This guide demonstrates how HyperFormula is integrated with an Angular app (typically as an injectable service), how it is cleaned up, and how you bridge its values into the change-detection cycle.
Install with npm install hyperformula. For other options, see the client-side installation section.
# Basic usage
Wrap the engine in an @Injectable service backed by a BehaviorSubject. Components subscribe to the observable with the async pipe, which handles subscription cleanup automatically.
// spreadsheet.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { HyperFormula, type CellValue } from 'hyperformula';
@Injectable({ providedIn: 'root' })
export class SpreadsheetService {
private readonly hf: HyperFormula;
private readonly _values = new BehaviorSubject<CellValue[][]>([]);
readonly values$ = this._values.asObservable();
constructor() {
this.hf = HyperFormula.buildFromArray(
[
[1, 2, '=A1+B1'],
// your data rows go here
],
{
licenseKey: 'gpl-v3',
// more configuration options go here
}
);
this._values.next(this.hf.getSheetValues(0));
}
calculate() {
this._values.next(this.hf.getSheetValues(0));
}
reset() {
this._values.next([]);
}
}
Consume the service from a component and bind values$ | async in the template. Declare the component in your AppModule alongside CommonModule:
// spreadsheet.component.ts
import { Component } from '@angular/core';
import { Observable } from 'rxjs';
import { SpreadsheetService } from './spreadsheet.service';
import { type CellValue } from 'hyperformula';
@Component({
selector: 'app-spreadsheet',
templateUrl: './spreadsheet.component.html',
})
export class SpreadsheetComponent {
values$: Observable<CellValue[][]>;
constructor(private spreadsheetService: SpreadsheetService) {
this.values$ = this.spreadsheetService.values$;
}
runCalculations() {
this.spreadsheetService.calculate();
}
reset() {
this.spreadsheetService.reset();
}
}
<!-- spreadsheet.component.html -->
<button (click)="runCalculations()">Run calculations</button>
<button (click)="reset()">Reset</button>
<ng-container *ngIf="(values$ | async) as values">
<table *ngIf="values.length">
<tr *ngFor="let row of values">
<td *ngFor="let cell of row">{{ cell }}</td>
</tr>
</table>
</ng-container>
# Notes
# Provider scope
providedIn: 'root' makes the service an application-wide singleton â suitable when a single HyperFormula instance is shared across the app. For per-feature or per-component instances (for example, several independent reports on one screen), provide the service at the component level via providers: [SpreadsheetService]; the service is then created and destroyed alongside the component.
# Cleanup
Root-scoped services live for the application's full lifetime â ngOnDestroy fires only at app shutdown. If you scope the service to a component (providers: [SpreadsheetService]), implement OnDestroy to release the engine:
import { Injectable, OnDestroy } from '@angular/core';
@Injectable()
export class SpreadsheetService implements OnDestroy {
// ...
ngOnDestroy() {
this.hf.destroy();
}
}
# Server-side rendering (Angular Universal)
The service above is already SSR-safe â HyperFormula has no browser-only API dependency. To skip the (otherwise wasted) server-side instantiation in Angular Universal, gate the engine init with isPlatformBrowser (opens new window) from @angular/common.
# Next steps
- Configuration options â full list of
buildFromArray/buildEmptyoptions - Basic operations â CRUD on cells, rows, columns, sheets
- Advanced usage â multi-sheet workbooks, named expressions
- Custom functions â register your own formulas
# Demo
For a more advanced example, check out the Angular demo on Stackblitz.