Dynamic Data Update in Angular Chart
30 Aug 202624 minutes to read
The Angular Chart component lets you update the data of a series at runtime without re-rendering the whole chart. This is useful for real-time data streams, user-driven editing, and incremental data loads. The sections below describe the available methods and show how to wire them up in a standalone Angular component.
When to use which method
| Method | Use when |
|---|---|
addPoint |
You want to append a single new data point to an existing series. |
removePoint |
You want to delete a data point by its index. |
setData |
You want to replace the entire data set of a series in one call. |
The methods documented here operate on the live series object. They work with both local data sources and remote data sources that have already been loaded into the chart.
Adding a new data point
Use the addPoint method to dynamically append a new data point to a series. This is useful for real-time data streams, user interactions, or incremental data loading. The method accepts the following parameters:
-
Data point (required): The new data object to append to the series. It must include the fields mapped to the series’
xNameandyName. - Animation duration (optional): Duration in milliseconds for the entry animation. If omitted, the chart’s default animation duration is used.
Sample behavior: the following sample appends a new point ({ x: 'Japan', y: 118.2 }) to a Spline series when the Add Point button is clicked. The sample uses @syncfusion/ej2-angular-buttons to render the button.
import { ChartModule, ChartComponent, SplineSeriesService, CategoryService, LegendService, DataLabelService } from '@syncfusion/ej2-angular-charts';
import { ButtonModule } from '@syncfusion/ej2-angular-buttons';
import { Component, OnInit, ViewChild } from '@angular/core';
@Component({
imports: [
ChartModule, ButtonModule
],
providers: [ SplineSeriesService, CategoryService, LegendService, DataLabelService ],
standalone: true,
selector: 'app-container',
template: `<ejs-chart #chart id="chart-container" [primaryXAxis]='primaryXAxis'[primaryYAxis]='primaryYAxis' [title]='title' [legendSettings]='legendSettings' [chartArea]='chartArea'>
<e-series-collection>
<e-series [dataSource]='chartData' type='Spline' xName='x' yName='y' name='Users' width=2 [marker]='marker'></e-series>
</e-series-collection>
</ejs-chart>
<button ej-button id='add' (click)='click()'>Add Point</button>`
})
export class AppComponent implements OnInit {
@ViewChild('chart')
public chart?: ChartComponent;
public primaryXAxis?: Object;
public primaryYAxis?: Object;
public chartData?: Object[] = [
{ x: "Germany", y: 72 },
{ x: "Russia", y: 103.1 },
{ x: "Brazil", y: 139.1 },
{ x: "India", y: 462.1 },
{ x: "China", y: 721.4 },
{ x: "USA", y: 286.9 },
{ x: "Great Britain", y: 115.1 },
{ x: "Nigeria", y: 97.2 }
];
public title?: string;
public marker?: Object;
public legendSettings?: Object;
public chartArea?: Object;
ngOnInit(): void {
this.primaryXAxis = {
valueType: 'Category',
enableTrim: false,
majorTickLines: { width: 0 },
majorGridLines: { width: 0 }
};
this.primaryYAxis = {
minimum: 0,
maximum: 800,
labelFormat: '{value}M',
edgeLabelPlacement: 'Shift'
};
this.title = 'Internet Users - 2016';
this.marker = {
visible: true,
dataLabel: {
visible: true,
position: 'Top',
font: { fontWeight: '600' }
}
};
this.legendSettings = { visible: false };
this.chartArea = {
border: { width: 1 }
};
}
click() {
if (this.chart?.series?.length) {
if (typeof this.chart.series[0].addPoint === 'function') {
this.chart?.series[0].addPoint({ x: 'Japan', y: 118.2 });
}
}
}
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));Removing an existing data point
Use the removePoint method to dynamically delete a data point from a series by its index. This is useful for filtering data, removing outliers, or responding to user actions. The method accepts the following parameters:
-
Point index (required): The zero-based index of the data point to remove. Passing an index that is outside the valid range (
0topoints.length - 1) is ignored by the chart and logs no error. - Animation duration (optional): Duration in milliseconds for the exit animation. If omitted, the chart’s default animation duration is used.
Sample behavior: the following sample removes the first point (index: 0) from a Spline series when the Remove Point button is clicked. The sample uses @syncfusion/ej2-angular-buttons to render the button.
import { ChartModule, ChartComponent, SplineSeriesService, CategoryService, LegendService, DataLabelService } from '@syncfusion/ej2-angular-charts';
import { ButtonModule } from '@syncfusion/ej2-angular-buttons';
import { Component, OnInit, ViewChild } from '@angular/core';
@Component({
imports: [
ChartModule, ButtonModule
],
providers: [ SplineSeriesService, CategoryService, LegendService, DataLabelService ],
standalone: true,
selector: 'app-container',
template: `<ejs-chart #chart id="chart-container" [primaryXAxis]='primaryXAxis'[primaryYAxis]='primaryYAxis' [title]='title' [legendSettings]='legendSettings' [chartArea]='chartArea'>
<e-series-collection>
<e-series [dataSource]='chartData' type='Spline' xName='x' yName='y' name='Users' width=2 [marker]='marker'></e-series>
</e-series-collection>
</ejs-chart>
<button ej-button id='remove' (click)='click()'>Remove Point</button>`
})
export class AppComponent implements OnInit {
@ViewChild('chart')
public chart?: ChartComponent;
public primaryXAxis?: Object;
public primaryYAxis?: Object;
public chartData?: Object[] = [
{ x: "Germany", y: 72 },
{ x: "Russia", y: 103.1 },
{ x: "Brazil", y: 139.1 },
{ x: "India", y: 462.1 },
{ x: "China", y: 721.4 },
{ x: "USA", y: 286.9 },
{ x: "Great Britain", y: 115.1 },
{ x: "Nigeria", y: 97.2 }
];
public title?: string;
public marker?: Object;
public legendSettings?: Object;
public chartArea?: Object;
ngOnInit(): void {
this.primaryXAxis = {
valueType: 'Category',
enableTrim: false,
majorTickLines: { width: 0 },
majorGridLines: { width: 0 }
};
this.primaryYAxis = {
minimum: 0,
maximum: 800,
labelFormat: '{value}M',
edgeLabelPlacement: 'Shift'
};
this.title = 'Internet Users - 2016';
this.marker = {
visible: true,
dataLabel: {
visible: true,
position: 'Top',
font: { fontWeight: '600' }
}
};
this.legendSettings = { visible: false };
this.chartArea = {
border: { width: 1 }
};
}
click() {
if (this.chart?.series?.length) {
if (typeof this.chart.series[0].removePoint === 'function') {
this.chart?.series[0].removePoint(0);
}
}
}
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));Replacing data points
Use the setData method to replace all data points in a series with a new dataset. This is useful for category switching, time range changes, or complete data refreshes. The method accepts the following parameters:
- New data source (required): The complete new dataset array to display. The new array can have a different length than the original data; the chart will re-render the axis range accordingly.
- Animation duration (optional): Duration in milliseconds for the transition animation. If omitted, the chart’s default animation duration is used.
Sample behavior: the following sample generates a new set of random Y values (10–90) for the existing categories of a Column series and calls setData to swap the data when the Update Data button is clicked. The axisRangeCalculated event handler is used to keep the Y-axis range bounded between 0 and 100. The sample uses @syncfusion/ej2-angular-buttons to render the button.
import { ChartModule, ChartComponent, ColumnSeriesService, CategoryService, IAxisRangeCalculatedEventArgs } from '@syncfusion/ej2-angular-charts';
import { ButtonModule } from '@syncfusion/ej2-angular-buttons';
import { Component, OnInit, ViewChild } from '@angular/core';
@Component({
imports: [
ChartModule, ButtonModule
],
providers: [ ColumnSeriesService, CategoryService ],
standalone: true,
selector: 'app-container',
template: `<ejs-chart #chart id="chart-container" [primaryXAxis]='primaryXAxis'[primaryYAxis]='primaryYAxis' [title]='title' [chartArea]='chartArea' (axisRangeCalculated)="axisRangeCalculated($event)">
<e-series-collection>
<e-series [dataSource]='chartData' type='Column' xName='x' yName='y' columnWidth=0.5 [cornerRadius]='cornerRadius'></e-series>
</e-series-collection>
</ejs-chart>
<button ej-button id='update' (click)='click()'>Update Data</button>`
})
export class AppComponent implements OnInit {
@ViewChild('chart')
public chart?: ChartComponent;
public primaryXAxis?: Object;
public primaryYAxis?: Object;
public chartData?: Object[] = [
{ x: 'Jewellery', y: 75 },
{ x: 'Shoes', y: 45 },
{ x: 'Footwear', y: 73 },
{ x: 'Pet Services', y: 53 },
{ x: 'Business Clothing', y: 85 },
{ x: 'Office Supplies', y: 68 },
{ x: 'Food', y: 45 }
];
public title?: string;
public cornerRadius?: Object;
public chartArea?: Object;
public getRandomInt(min: number, max: number) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
ngOnInit(): void {
this.primaryXAxis = {
valueType: 'Category',
majorGridLines: { width: 0 },
labelStyle: { size: '12px' },
labelIntersectAction: 'Rotate90'
};
this.primaryYAxis = {
title: 'Sales (in percentage)',
labelFormat: '{value}%',
lineStyle: { width: 0 },
majorTickLines: { width: 0 },
interval: 5,
minimum: 0,
maximum: 100
};
this.title = 'Sales by product';
this.cornerRadius = { topLeft: 15, topRight: 15 };
this.chartArea = {
border: { width: 0 }
};
}
click() {
if (this.chart && this.chart.series && this.chart.series.length > 0 && this.chart.series[0].dataSource) {
const newData = (
this.chart.series[0].dataSource as { x: string; y: number }[]
).map((item) => {
const value: number = this.getRandomInt(10, 90);
return { x: item.x, y: value };
});
if (typeof this.chart.series[0].setData === 'function') {
this.chart.series[0].setData(newData, 500);
}
}
}
public axisRangeCalculated (args: IAxisRangeCalculatedEventArgs): void {
if (args.axis.name === 'primaryYAxis') {
args.maximum = args.maximum as number > 100 ? 100 : args.maximum;
if (args.maximum > 80) {
args.interval = 20;
} else if(args.maximum > 40){
args.interval = 10;
}
}
}
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));Click to add or remove a data point
Enable users to add or remove data points by clicking on the chart. Listen to the chartMouseClick event to capture click coordinates and point information. The event’s axisData field exposes the X and Y axis values at the click location (e.g. args.axisData.primaryXAxis, args.axisData.primaryYAxis).
When the user clicks inside the chart area, check whether the click is within ±1 axis unit of any existing point’s x and y values. If a point is matched, identify its index and call removePoint to delete it (a removePoint call is only allowed when more than one point remains in the series). If no point is matched, call addPoint with the rounded X and Y values to add a new data point at the click location. The sample below also enables the tooltip so that the value under the cursor is visible while the user explores the chart.
import { ChartModule, ChartComponent, LineSeriesService, CategoryService, TooltipService, DataLabelService, IAxisRangeCalculatedEventArgs, Series, IMouseEventArgs } from '@syncfusion/ej2-angular-charts';
import { Component, OnInit, ViewChild } from '@angular/core';
@Component({
imports: [
ChartModule
],
providers: [ LineSeriesService, CategoryService, TooltipService, DataLabelService ],
standalone: true,
selector: 'app-container',
template: `<ejs-chart #chart id="chart-container" [primaryXAxis]='primaryXAxis'[primaryYAxis]='primaryYAxis' [title]='title' [chartArea]='chartArea' [tooltip]='tooltip' (chartMouseClick)='chartMouseClick($event)' (axisRangeCalculated)="axisRangeCalculated($event)">
<e-series-collection>
<e-series [dataSource]='chartData' type='Line' xName='x' yName='y' width=3 [marker]='marker'></e-series>
</e-series-collection>
</ejs-chart>
`
})
export class AppComponent implements OnInit {
@ViewChild('chart')
public chart?: ChartComponent;
public primaryXAxis?: Object;
public primaryYAxis?: Object;
public chartData?: Object[] = [
{ x: 20, y: 20 },
{ x: 80, y: 80 }
];
public title?: string;
public marker?: Object;
public chartArea?: Object;
public tooltip?: Object;
ngOnInit(): void {
this.primaryXAxis = {
edgeLabelPlacement: 'Shift',
rangePadding: 'Additional',
majorGridLines: { width: 0 }
};
this.primaryYAxis = {
title: 'Value',
interval: 20,
lineStyle: { width: 0 },
majorTickLines: { width: 0 }
};
this.title = 'User supplied data';
this.marker = {
visible: true,
isFilled: true,
border: {
width: 2,
color: 'White'
},
width: 13,
height: 13
};
this.chartArea = {
border: { width: 0 }
};
this.tooltip = { enable: true };
}
public chartMouseClick(args: IMouseEventArgs): void {
let isRemoved: boolean = false;
if (args.axisData && this.chart?.series) {
for (let i: number = 0; i < (this.chart.series[0] as Series).points.length; i++) {
let markerWidth: number = ((this.chart.series[0] as Series).marker?.width ?? 0) / 2;
let roundedX: number = Math.round(args.axisData['primaryXAxis']) + markerWidth;
let roundedY: number = Math.round(args.axisData['primaryYAxis']) + markerWidth;
let pointX: number = Math.round((this.chart.series[0] as Series).points[i].x as number) + markerWidth;
let pointY: number = Math.round((this.chart.series[0] as Series).points[i].y as number) + markerWidth;
if ((roundedX === pointX || roundedX + 1 === pointX || roundedX - 1 === pointX) &&
(roundedY === pointY || roundedY + 1 === pointY || roundedY - 1 === pointY)) {
if ((this.chart.series[0] as Series).points.length > 1) {
const points = (this.chart.series[0] as Series).points;
const duration: number = i === 0 || i === points[points.length - 1].index ? 500 : 0;
if (this.chart?.series?.length) {
if (typeof this.chart.series[0].removePoint === 'function') {
this.chart.series[0].removePoint(i, duration);
}
}
}
isRemoved = true;
}
}
if (!isRemoved) {
if (this.chart?.series?.length) {
if (typeof this.chart.series[0].addPoint === 'function') {
this.chart.series[0].addPoint({
x: Math.round(args.axisData['primaryXAxis']),
y: Math.round(args.axisData['primaryYAxis'])
});
}
}
}
}
};
public axisRangeCalculated(args: IAxisRangeCalculatedEventArgs): void {
if (args.axis.name === 'primaryXAxis') {
if (args.interval < 10) {
args.maximum = args.maximum + 10;
args.minimum = args.minimum - 10;
args.interval = 10;
}
}
if (args.axis.name === 'primaryYAxis') {
if (args.maximum <= 60) {
args.interval = 10;
}
}
};
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));Troubleshooting
-
addPointis not a function – Make sure the chart series service (e.g.SplineSeriesService,LineSeriesService) is registered in the component’sprovidersarray, and that you are calling the method on aSeriesinstance returned bychart.series[0]. -
The new point is rendered at the wrong position – Verify that the data object’s field names match the series’
xNameandyName, and that the X axisvalueTypematches the type of the newxvalue (for example,'Category'for strings,'Numeric'or'DateTime'for numbers/dates). - Click-to-add does not detect an existing point – The ±1 axis-unit tolerance is intentionally small. Zoom in or increase the marker size to make existing points easier to hit.
-
Removing the last point throws an error – The chart requires at least one data point. Guard the call with a check such as
series.points.length > 1before callingremovePoint.