external/ag-shared/prompts/skills/example/ag-charts/framework-patterns.md
This guide provides detailed technical documentation about how AG Charts examples are transformed from vanilla TypeScript into React, Angular, and Vue variants.
The example generation system (plugins/ag-charts-generate-example-files) automatically transforms vanilla TypeScript examples into framework-specific implementations. This transformation is pattern-based and relies on parsing the vanilla code structure to extract reusable components.
Supported Frameworks:
vanilla - Plain JavaScript (ES6)typescript - TypeScript with SystemJSreactFunctional - React with functional components (JSX)reactFunctionalTs - React with functional components (TSX)angular - Angular with standalone componentsvue3 - Vue 3 with Composition APIThe parser (chart-vanilla-src-parser.ts) uses TypeScript's AST to extract:
AgChartOptions configurationThe parser specifically looks for this pattern:
const options: AgChartOptions = {
container: document.getElementById('myChart'),
// ...
};
Requirements:
document.getElementById()getElementById() maps to the HTML elementWhy This Matters: Frameworks handle DOM differently:
@ViewChild or template variablesTransformation Steps:
Options -> State: Options object becomes useState
// Vanilla
const options: AgChartOptions = {
/* ... */
};
// React
const [options, setOptions] = useState<AgChartOptions>({
/* ... */
});
Chart Instance -> Ref: Chart variable becomes useRef
// Vanilla
const chart = AgCharts.create(options);
// React
const chartRef = useRef<AgChartsInstance>(null);
// In component: <AgCharts ref={chartRef} options={options} />
Update Functions: Wrapped to use state setters
// Vanilla
function updateChart() {
options.data = newData;
chart.update(options);
}
// React
function updateChart() {
const nextOptions = clone(options);
nextOptions.data = newData;
setOptions(nextOptions);
}
HTML Events: Converted to React event handlers
<!-- Vanilla -->
<button onclick="toggleSeries()">Toggle</button>
<!-- React -->
<button onClick="{toggleSeries}">Toggle</button>
Chart Components Used:
AgCharts - Standard chartsAgFinancialCharts - Financial chartsAgGauge - Gauge chartsAgSparkline - SparklinesTransformation Steps:
Options -> Component Property: Options become class property
// Vanilla
const options: AgChartOptions = {
/* ... */
};
// Angular
export class AppComponent {
options: AgChartOptions = {
/* ... */
};
}
Template Generation: HTML is converted to Angular template
// Generated template in component
template: `
<div class="example-controls">
<button (click)="toggleSeries()">Toggle</button>
</div>
<ag-charts [options]="options"></ag-charts>
`;
Update Functions: Become component methods
export class AppComponent {
options: AgChartOptions = {
/* ... */
};
toggleSeries() {
const options = clone(this.options);
// ... modify options
this.options = options;
}
}
Components Used:
ag-charts selector for AgChartsAngularag-financial-charts for financial chartsag-gauge for gaugesTransformation Steps:
Options -> Reactive State: Options become ref
// Vanilla
const options: AgChartOptions = {
/* ... */
};
// Vue
const options = ref<AgChartOptions>({
/* ... */
});
Template: HTML converted to Vue template
<template>
<div class="example-controls">
<button @click="toggleSeries">Toggle</button>
</div>
<ag-charts :options="options"></ag-charts>
</template>
Update Functions: Functions that modify options.value
function toggleSeries() {
const nextOptions = clone(options.value);
// ... modify nextOptions
options.value = nextOptions;
}
Vanilla:
import { AgChartOptions, AgCharts } from 'ag-charts-community';
import { getData } from './data';
const options: AgChartOptions = {
container: document.getElementById('myChart'),
data: getData(),
series: [{ type: 'line', xKey: 'x', yKey: 'y' }],
};
AgCharts.create(options);
Result: Transforms cleanly to all frameworks
Vanilla:
import { AgChartOptions, AgCharts } from 'ag-charts-community';
const options: AgChartOptions = {
container: document.getElementById('myChart'),
series: [{ type: 'line', xKey: 'x', yKey: 'y' }],
};
const chart = AgCharts.create(options);
function toggleMarkers() {
const series = options.series![0];
series.marker = { enabled: !series.marker?.enabled };
chart.update(options);
}
HTML:
<button onclick="toggleMarkers()">Toggle Markers</button>
<div id="myChart"></div>
Result: Transforms cleanly - event handler and state management work
Vanilla:
const chart = AgCharts.create(options);
function changeTitle() {
chart.updateDelta({ title: { text: 'New Title' } });
}
Result: Transforms cleanly - updateDelta is handled for frameworks
Vanilla:
const chart = AgCharts.create(options);
function downloadChart() {
AgCharts.download(chart, { fileName: 'my-chart.png' });
}
Result: Transforms cleanly - chart ref is properly mapped
Vanilla:
const options: AgChartOptions = {
/* ... */
};
const chart = AgCharts.create(options);
function updateData() {
options.data = getNewData();
chart.update(options);
}
function changeTheme() {
options.theme = getNewTheme();
chart.update(options);
}
Result: Transforms cleanly - all functions access shared options
Vanilla:
function updateUI() {
const status = document.getElementById('status');
status.innerHTML = '<div class="updated">Updated!</div>';
status.classList.add('active');
}
Result: Does not transform - frameworks manage DOM differently
Solution: Use @ag-skip-fws or keep UI updates within framework templates
Vanilla:
import * as d3 from 'd3';
import { getData } from './data';
const scale = d3.scaleLinear().domain([0, 100]).range([0, 500]);
const options: AgChartOptions = {
container: document.getElementById('myChart'),
data: getData().map((d) => ({ ...d, scaled: scale(d.value) })),
};
Result: Does not transform - external library imports not handled
Solution: Use @ag-skip-fws
Vanilla:
async function loadAndUpdate() {
const response = await fetch('/api/data');
const data = await response.json();
const processed = await processData(data);
options.data = processed;
chart.update(options);
}
Result: May transform but framework timing issues likely
Solution: Simple async is OK, but complex workflows should use @ag-skip-fws
Vanilla:
const chart1 = AgCharts.create({
container: document.getElementById('chart1'),
/* ... */
});
const chart2 = AgCharts.create({
container: document.getElementById('chart2'),
/* ... */
});
function syncCharts() {
// Complex coordination between charts
}
Result: Does not transform well - multiple instances complex
Solution: Use @ag-skip-fws for multi-chart examples
Vanilla:
// Explicit global assignment
window.myChart = chart;
window.updateChart = updateChart;
Result: Does not transform
Note: Event handlers ARE automatically added to window/scope, but explicit assignments are not supported.
Symptom: Generated React/Vue code has type errors
Causes:
AgChartOptions instead of specific type)Solutions:
// Import all used types
import { AgCartesianChartOptions, AgCharts, AgLineSeriesOptions } from 'ag-charts-community';
// Use specific chart type
const options: AgCartesianChartOptions = {
/* ... */
};
// Use type assertions when needed
const series = options.series![0] as AgLineSeriesOptions;
Symptom: Clicking buttons doesn't trigger functions
Causes:
Solutions:
<!-- Good -->
<button onclick="updateChart()">Update</button>
<!-- Bad - inline arrow -->
<button onclick="() => updateChart()">Update</button>
<!-- Bad - inline logic -->
<button onclick="chart.update(options)">Update</button>
Symptom: Changes don't reflect in chart after state update
Cause: Not using proper state management or clone
Solution:
// Good - proper clone and state update
function updateChart() {
const nextOptions = clone(options);
nextOptions.data = newData;
setOptions(nextOptions);
}
// Bad - mutating state directly
function updateChart() {
options.data = newData;
setOptions(options); // Same reference, React won't update
}
@ag-skip-clone DirectiveFor performance-critical examples with frequent updates, use @ag-skip-clone:
// @ag-skip-clone
const options: AgChartOptions = {
/* ... */
};
This suppresses the clone() call in React/Vue, but be aware of state mutation implications.
# Generate framework variants for specific example
nx run ag-charts-website-${pageName}_${exampleName}_main.ts:generate
# Typecheck generated code
nx run ag-charts-website-${pageName}_${exampleName}_main.ts:typecheck
# Batch validate all examples
nx validate-examples
yarn nx devGenerated files are in dist/packages/ag-charts-website/public/generated-examples/:
dist/packages/ag-charts-website/public/generated-examples/
+-- ${pageName}/
+-- ${exampleName}/
|-- vanilla/
| |-- main.js
| +-- index.html
|-- typescript/
| +-- main.ts
|-- reactFunctional/
| +-- index.jsx
|-- reactFunctionalTs/
| +-- index.tsx
|-- angular/
| |-- app.component.ts
| +-- main.ts
+-- vue3/
+-- main.ts
Debugging Steps:
yarn nx generate-examples ag-charts-websiteMissing imports:
// Check generated file has all necessary imports
import { AgChartOptions /* other types */, AgCharts } from 'ag-charts-community';
Incorrect refs:
// React: ensure chartRef is created and used
const chartRef = useRef<AgChartsInstance>(null);
// ... later
AgCharts.download(chartRef.current!, { fileName: 'chart.png' });
Options not reactive:
// Vue: options should be ref
const options = ref<AgChartOptions>({
/* ... */
});
// Access with .value
options.value.data = newData;
@ag-skip-fwsSkip framework generation entirely:
// @ag-skip-fws
import { AgChartOptions, AgCharts } from 'ag-charts-community';
// Example will only generate vanilla and typescript variants
CRITICAL: This directive is ONLY for internal use (benchmarks and *-test pages). All public documentation examples MUST work across all frameworks.
When to Use (Internal Only):
benchmarks pages)*-test pages)NEVER Use For:
If a public example needs patterns that don't transform: Redesign the example to be framework-compatible. Complex features can be demonstrated with simpler, framework-compatible examples.
@ag-skip-cloneSkip clone() call in framework transformations:
// @ag-skip-clone
const options: AgChartOptions = {
/* ... */
};
When to Use:
Caution: May cause state mutation issues in React/Vue if not careful.
@ag-skip-container-checkSkip validation of container setup:
// @ag-skip-container-check
const options: AgChartOptions = {
container: someComplexContainerSetup(),
// ...
};
When to Use: Rarely - only when you have a custom container setup pattern that's valid but doesn't match the standard pattern.
@ag-options-extractExtract options for JSON serialization (used internally for option APIs):
// @ag-options-extract
const options: AgChartOptions = {
/* ... */
};
When to Use: Internal use for documentation generation. Most examples don't need this.
document.getElementById() for containerconst chart = AgCharts.create(options)AgCartesianChartOptions, etc.)@ag-skip-fws for public documentation examples (internal use only)window object explicitlychart.update() after changing options| Pattern | Vanilla -> Framework | Support |
|---|---|---|
| Static chart | Direct component props | Yes |
| Top-level options | State/reactive | Yes |
| Chart instance | Ref/component instance | Yes |
| Button onclick | Framework event handler | Yes |
| Select onchange | Framework event handler | Yes |
| chart.update() | State update | Yes |
| chart.updateDelta() | State update | Yes |
| AgCharts.download() | Via chart ref | Yes |
| Complex DOM queries | N/A | No |
| External libraries | N/A | No |
| Multiple charts | N/A | No |
| window assignments | N/A | No |
| Complex async | Framework-specific | Partial |
plugins/ag-charts-generate-example-files/src/executors/generate/generator/transformation-scripts/chart-vanilla-src-parser.tschart-vanilla-to-react-functional-ts.tschart-vanilla-to-angular.tschart-vanilla-to-vue3.ts