The set of widgets available to report authors, and the configuration of each individual widget, can both be customised through the widgets property.
Available Widgets Copy Link
import {
createApp,
defineComponent,
onBeforeMount,
ref,
shallowRef,
} from "vue";
import { AgStudio } from "ag-studio-vue3";
import {
AgDataEngine,
AgDataSourcesDefinition,
AgDefaultRegistry,
AgReportState,
AgStudioApi,
AgStudioApiReadyEvent,
AgStudioMode,
AgStudioProperties,
AgWidgetsConfig,
enableStudioDevValidations,
} from "ag-studio";
import { createWidgets } from "ag-studio-vue3";
if (process.env.NODE_ENV !== "production") {
// Enable extended validations only for development
enableStudioDevValidations();
}
const VueExample = defineComponent({
template: `
<div style="height: 100%">
<div style="display: flex; flex-direction: column; height: 100%">
<ag-studio
style="width: 100%; height: 100%;"
class="my-studio-container"
@api-ready="onApiReady"
:initialState="initialState"
:mode="mode"
:widgets="widgets"
:data="data"></ag-studio>
</div>
</div>
`,
components: {
"ag-studio": AgStudio,
},
setup(props) {
const studioApi = shallowRef<AgStudioApi | null>(null);
const initialState = ref<AgReportState>({
pages: [
{
id: "a",
widgets: {
"1": {
type: "grid",
dataMapping: {
cols: [
{ id: "medals.country" },
{ id: "medals.sport" },
{ id: "medals.gold", aggregation: "sum" },
{ id: "medals.silver", aggregation: "sum" },
{ id: "medals.bronze", aggregation: "sum" },
{ id: "medals.total", aggregation: "sum" },
],
},
},
},
widgetLayout: {
"1": {
xTrack: 0,
yTrack: 0,
xSpan: 24,
ySpan: 16,
},
},
},
],
selectedPageId: "a",
panels: {
filters: {
collapsed: true,
},
data: {
collapsed: true,
},
},
});
const mode = ref<AgStudioMode>("edit");
const widgets = ref<
| AgWidgetsConfig
| ((widgets: AgWidgetsConfig<AgDefaultRegistry>) => AgWidgetsConfig)
>((config: AgWidgetsConfig) =>
createWidgets({
menu: [
{
label: "Popular",
widgetIds: ["grid", "value"],
},
{
label: "Other",
widgetIds: ["text", "button-filter"],
collapsed: true,
},
config.menu[0],
],
defaultType: "value",
}),
);
const data = ref<AgDataSourcesDefinition | AgDataEngine>(null);
const onApiReady = (params: AgStudioApiReadyEvent) => {
studioApi.value = params.api;
const toStudioData = (data) => ({ sources: [{ id: "medals", data }] });
fetch("https://www.ag-grid.com/studio/example-assets/olympic-winners.json")
.then((resp) => resp.json())
.then((respData) => (data.value = toStudioData(respData)));
};
return {
studioApi,
initialState,
mode,
widgets,
data,
onApiReady,
};
},
});
const app = createApp(VueExample);
app.mount("#app");
The example above changes the list of available widgets to:
- Add new groups of widgets
- Show one of the groups collapsed by default
- Re-use one of the default widget groups
- Change the default widget type when dragging fields to the Value widget
<ag-studio
:widgets="widgets"
/* other studio properties ... */>
</ag-studio>
this.widgets = createWidgets({
menu: [
// new menu configuration
],
defaultType: 'value',
});See the Widget Configuration API for details on the createWidgets helper function.
Widget Overrides Copy Link
import {
createApp,
defineComponent,
onBeforeMount,
ref,
shallowRef,
} from "vue";
import { AgStudio } from "ag-studio-vue3";
import {
AgBaseWidgetDefinition,
AgDataEngine,
AgDataSourcesDefinition,
AgDefaultRegistry,
AgFormTabGroup,
AgGridWidget,
AgPath,
AgReportState,
AgStudioApi,
AgStudioApiReadyEvent,
AgStudioMode,
AgStudioProperties,
AgWidgetsConfig,
enableStudioDevValidations,
} from "ag-studio";
import { createWidgets } from "ag-studio-vue3";
if (process.env.NODE_ENV !== "production") {
// Enable extended validations only for development
enableStudioDevValidations();
}
const VueExample = defineComponent({
template: `
<div style="height: 100%">
<div style="display: flex; flex-direction: column; height: 100%">
<ag-studio
style="width: 100%; height: 100%;"
class="my-studio-container"
@api-ready="onApiReady"
:initialState="initialState"
:mode="mode"
:widgets="widgets"
:data="data"></ag-studio>
</div>
</div>
`,
components: {
"ag-studio": AgStudio,
},
setup(props) {
const studioApi = shallowRef<AgStudioApi | null>(null);
const initialState = ref<AgReportState>({
pages: [
{
id: "a",
widgets: {
"1": {
type: "grid",
dataMapping: {
cols: [
{ id: "medals.country" },
{ id: "medals.sport" },
{ id: "medals.gold", aggregation: "sum" },
{ id: "medals.silver", aggregation: "sum" },
{ id: "medals.bronze", aggregation: "sum" },
{ id: "medals.total", aggregation: "sum" },
],
},
},
"2": {
type: "column-chart-grouped",
dataMapping: {
categoryKey: [{ id: "medals.country" }],
valueKey: [
{ id: "medals.gold", aggregation: "sum" },
{ id: "medals.silver", aggregation: "sum" },
{ id: "medals.bronze", aggregation: "sum" },
],
tooltipKey: [],
},
},
},
widgetLayout: {
"1": {
xTrack: 0,
yTrack: 0,
xSpan: 24,
ySpan: 16,
},
"2": {
xTrack: 0,
yTrack: 16,
xSpan: 24,
ySpan: 16,
},
},
selection: {
type: "widget",
id: "1",
},
},
],
selectedPageId: "a",
panels: {
filters: {
collapsed: true,
},
data: {
collapsed: true,
},
},
});
const mode = ref<AgStudioMode>("edit");
const widgets = ref<
| AgWidgetsConfig
| ((widgets: AgWidgetsConfig<AgDefaultRegistry>) => AgWidgetsConfig)
>((config: AgWidgetsConfig) => {
const existingGridDef = config.widgets.find(
({ id }) => id === "grid",
) as AgBaseWidgetDefinition<"grid", AgGridWidget>;
const newGridDef: Pick<
AgBaseWidgetDefinition<"grid", AgGridWidget>,
"id" | "label" | "form"
> = {
id: "grid",
label: "Grid",
form: (params) => {
// update the grid form to remove the widget type selector
const oldTabGroup = existingGridDef.form(params) as AgFormTabGroup<
AgPath<AgGridWidget>
>;
const [oldSetupTab, oldFormatTab] = oldTabGroup.items;
const newSetupTab = {
...oldSetupTab,
items: [...oldSetupTab.items.slice(1), oldSetupTab.items[0]],
};
return {
...oldTabGroup,
items: [newSetupTab, oldFormatTab],
};
},
} as const;
return createWidgets({
overrides: [newGridDef],
});
});
const data = ref<AgDataSourcesDefinition | AgDataEngine>(null);
const onApiReady = (params: AgStudioApiReadyEvent) => {
studioApi.value = params.api;
const toStudioData = (data) => ({ sources: [{ id: "medals", data }] });
fetch("https://www.ag-grid.com/studio/example-assets/olympic-winners.json")
.then((resp) => resp.json())
.then((respData) => (data.value = toStudioData(respData)));
};
return {
studioApi,
initialState,
mode,
widgets,
data,
onApiReady,
};
},
});
const app = createApp(VueExample);
app.mount("#app");
The example above changes the configuration for the Table widget to update the label from 'Table' to 'Grid', and move the widget selection input to the bottom of the setup tab.
<ag-studio
:widgets="widgets"
/* other studio properties ... */>
</ag-studio>
this.widgets = createWidgets({
overrides: [
{
id: 'grid',
label: 'Grid',
// ... other overrides
}
]
});Updating the form property for a widget allows the items in the Edit Panel to be customised, including changing their default values. See Form Configuration for more details.
Pre-Configured Widgets Copy Link
import {
createApp,
defineComponent,
onBeforeMount,
ref,
shallowRef,
} from "vue";
import { AgStudio } from "ag-studio-vue3";
import {
AgBaseRegistry,
AgBaseWidgetDefinition,
AgColumnChartGrouped,
AgDataEngine,
AgDataSourcesDefinition,
AgDefaultRegistry,
AgReportState,
AgSortConfig,
AgStudioApi,
AgStudioApiReadyEvent,
AgStudioMode,
AgStudioProperties,
AgWidgetFieldReference,
AgWidgetsConfig,
enableStudioDevValidations,
} from "ag-studio";
import { createWidgets } from "ag-studio-vue3";
if (process.env.NODE_ENV !== "production") {
// Enable extended validations only for development
enableStudioDevValidations();
}
interface CustomColumnChart<TType extends string> extends Omit<
AgColumnChartGrouped,
"type"
> {
type: TType;
}
interface MyRegistry extends AgBaseRegistry {
widgets: readonly (
| CustomDef1
| CustomDef2
| AgBaseWidgetDefinition<"column-chart-grouped", AgColumnChartGrouped>
)[];
}
const VueExample = defineComponent({
template: `
<div style="height: 100%">
<div style="display: flex; flex-direction: column; height: 100%">
<ag-studio
style="width: 100%; height: 100%;"
class="my-studio-container"
@api-ready="onApiReady"
:initialState="initialState"
:widgets="widgets"
:mode="mode"
:data="data"></ag-studio>
</div>
</div>
`,
components: {
"ag-studio": AgStudio,
},
setup(props) {
const studioApi = shallowRef<AgStudioApi<MyRegistry> | null>(null);
const initialState = ref<AgReportState<MyRegistry>>({
pages: [
{
id: "a",
},
],
selectedPageId: "a",
panels: {
filters: {
collapsed: true,
},
data: {
collapsed: true,
},
},
});
const widgets = ref<
| AgWidgetsConfig<MyRegistry>
| ((
widgets: AgWidgetsConfig<AgDefaultRegistry>,
) => AgWidgetsConfig<MyRegistry>)
>((config: AgWidgetsConfig<AgDefaultRegistry>) => {
const existingColumnChartDef = config.widgets.find(
({ id }) => id === "column-chart-grouped",
) as AgBaseWidgetDefinition<"column-chart-grouped", AgColumnChartGrouped>;
// only show the widget type selector
const form: CustomDef1["form"] = (params) => ({
type: "tab-group",
key: "config",
items: [
{
type: "tab",
key: "setup",
label: "widgetFormSectionSetup",
items: [params.createWidgetSection()],
},
],
});
const def1: CustomDef1 = {
...existingColumnChartDef,
id: "pre-configured-column-chart-1",
label: "Gold Chart",
defaultState: {
dataMapping: {
categoryKey: [{ id: "medals.country" }],
valueKey: [
{
id: "medals.gold",
aggregation: "sum",
},
],
},
sort: [
{
field: { id: "medals.gold", aggregation: "sum" },
direction: "desc",
},
],
format: {
title: {
enabled: true,
text: "Gold Medals by Country",
},
},
},
form,
formatShape: undefined,
extends: "column-chart-grouped",
};
const def2: CustomDef2 = {
...existingColumnChartDef,
id: "pre-configured-column-chart-2",
label: "Silver Chart",
defaultState: {
dataMapping: {
categoryKey: [{ id: "medals.country" }],
valueKey: [
{
id: "medals.silver",
aggregation: "sum",
},
],
},
sort: [
{
field: { id: "medals.silver", aggregation: "sum" },
direction: "desc",
},
],
format: {
title: {
enabled: true,
text: "Silver Medals by Country",
},
},
},
form,
formatShape: undefined,
extends: "column-chart-grouped",
};
return createWidgets<MyRegistry>({
menu: [
{
label: "Pre-Configured",
widgetIds: [
"pre-configured-column-chart-1",
"pre-configured-column-chart-2",
],
},
{
label: "Existing",
widgetIds: ["column-chart-grouped"],
},
],
additionalTypes: [def1, def2],
});
});
const mode = ref<AgStudioMode>("edit");
const data = ref<AgDataSourcesDefinition | AgDataEngine>(null);
const onApiReady = (params: AgStudioApiReadyEvent) => {
studioApi.value = params.api;
const toStudioData = (data) => ({ sources: [{ id: "medals", data }] });
fetch("https://www.ag-grid.com/studio/example-assets/olympic-winners.json")
.then((resp) => resp.json())
.then((respData) => (data.value = toStudioData(respData)));
};
return {
studioApi,
initialState,
widgets,
mode,
data,
onApiReady,
};
},
});
const app = createApp(VueExample);
app.mount("#app");
The example above updates the widget configuration to have two pre-configured widgets. These re-use the existing grouped column chart widgets, but set the fields and title, and hide all of the form options except for the widget selection input.
The pre-configured widgets are set up in a similar way to Creating a Custom Widget, but they copy the existing grouped column chart widget definition.
The extends property is set to 'column-chart-grouped' so that all of the default values are set correctly, and the defaultState property is set with the desired data mapping, sort and title details.
Cell Renderers Copy Link
Table and pivot table widgets can render their cells with your own components, using AG Grid cell renderers.
import {
createApp,
defineComponent,
onBeforeMount,
ref,
shallowRef,
} from "vue";
import { AgStudio } from "ag-studio-vue3";
import {
AgDataEngine,
AgDataSourcesDefinition,
AgDefaultRegistry,
AgFieldDefinition,
AgGridWidgetOptions,
AgPivotGridWidgetOptions,
AgReportState,
AgStudioApi,
AgStudioApiReadyEvent,
AgStudioMode,
AgStudioProperties,
AgWidgetField,
AgWidgetsConfig,
enableStudioDevValidations,
} from "ag-studio";
import { createWidgets } from "ag-studio-vue3";
import CountryFlagCellRenderer from "./countryFlagCellRendererVue.ts";
import GoldCellRenderer from "./goldCellRendererVue.ts";
import OlympicSeasonCellRenderer from "./olympicSeasonCellRendererVue.ts";
if (process.env.NODE_ENV !== "production") {
// Enable extended validations only for development
enableStudioDevValidations();
}
// The shipped flag assets cover 20 of the 110 countries in the data, so the pivot widget is
// filtered to those countries to keep every visible row's flag resolvable.
const COUNTRIES_WITH_FLAGS = [
"United States",
"Germany",
"Great Britain",
"France",
"Italy",
"Netherlands",
"Spain",
"Sweden",
"Norway",
"Argentina",
"Brazil",
"Belgium",
"Greece",
"Ireland",
"Iceland",
"Portugal",
"Denmark",
"Colombia",
"Uruguay",
"Venezuela",
];
const fields: AgFieldDefinition[] = [
{
id: "country",
name: "Country",
format: "textFormat",
context: { cellRenderer: "countryFlag" },
},
{
id: "sport",
name: "Sport",
format: "textFormat",
},
{
id: "year",
name: "Year",
format: "integerFormat",
formatOptions: { format: "0" },
context: { cellRenderer: "olympicSeason" },
},
{
id: "gold",
name: "Gold",
format: "integerFormat",
context: { cellRenderer: "gold" },
},
{
id: "silver",
name: "Silver",
format: "integerFormat",
},
{
id: "bronze",
name: "Bronze",
format: "integerFormat",
},
];
const gridWidgetOptions: AgGridWidgetOptions = {
createCellRenderer: (field: AgWidgetField) =>
field.context?.cellRenderer === "gold" ? GoldCellRenderer : undefined,
};
const pivotGridWidgetOptions: AgPivotGridWidgetOptions = {
createCellRenderer: (field: AgWidgetField) => {
switch (field.context?.cellRenderer) {
case "countryFlag":
return CountryFlagCellRenderer;
case "olympicSeason":
return OlympicSeasonCellRenderer;
case "gold":
return GoldCellRenderer;
default:
return undefined;
}
},
};
const VueExample = defineComponent({
template: `
<div style="height: 100%">
<div style="display: flex; flex-direction: column; height: 100%">
<ag-studio
style="width: 100%; height: 100%;"
class="my-studio-container"
@api-ready="onApiReady"
:initialState="initialState"
:widgets="widgets"
:mode="mode"
:data="data"></ag-studio>
</div>
</div>
`,
components: {
"ag-studio": AgStudio,
CountryFlagCellRenderer,
GoldCellRenderer,
OlympicSeasonCellRenderer,
},
setup(props) {
const studioApi = shallowRef<AgStudioApi | null>(null);
const initialState = ref<AgReportState>({
pages: [
{
id: "a",
widgets: {
"1": {
type: "grid",
dataMapping: {
cols: [
{ id: "medals.country" },
{ id: "medals.sport" },
{ id: "medals.gold", aggregation: "sum" },
{ id: "medals.silver", aggregation: "sum" },
{ id: "medals.bronze", aggregation: "sum" },
],
},
format: { title: { enabled: true, text: "Medals by Sport" } },
},
"2": {
type: "pivot-grid",
dataMapping: {
rows: [{ id: "medals.country" }, { id: "medals.year" }],
// Left empty so the values stay flat columns and the row groups render expanded.
columns: [],
values: [
{ id: "medals.gold", aggregation: "sum" },
{ id: "medals.silver", aggregation: "sum" },
{ id: "medals.bronze", aggregation: "sum" },
],
},
format: {
title: { enabled: true, text: "Medals by Country and Year" },
},
},
},
widgetLayout: {
"1": { xTrack: 0, yTrack: 0, xSpan: 24, ySpan: 16 },
"2": { xTrack: 0, yTrack: 16, xSpan: 24, ySpan: 16 },
},
filter: {
widget: {
"2": [
{
field: { id: "medals.country" },
model: { operator: "isIn", value: COUNTRIES_WITH_FLAGS },
},
],
},
},
},
],
selectedPageId: "a",
panels: {
filters: {
collapsed: true,
},
data: {
collapsed: true,
},
},
});
const widgets = ref<
| AgWidgetsConfig
| ((widgets: AgWidgetsConfig<AgDefaultRegistry>) => AgWidgetsConfig)
>(
createWidgets({
overrides: [
{
id: "grid",
options: gridWidgetOptions,
},
{
id: "pivot-grid",
options: pivotGridWidgetOptions,
},
],
}),
);
const mode = ref<AgStudioMode>("edit");
const data = ref<AgDataSourcesDefinition | AgDataEngine>(null);
const onApiReady = (params: AgStudioApiReadyEvent) => {
studioApi.value = params.api;
const toStudioData = (data) => ({
sources: [{ id: "medals", name: "Medals", data, fields }],
});
fetch("https://www.ag-grid.com/studio/example-assets/olympic-winners.json")
.then((resp) => resp.json())
.then((respData) => (data.value = toStudioData(respData)));
};
return {
studioApi,
initialState,
widgets,
mode,
data,
onApiReady,
};
},
});
const app = createApp(VueExample);
app.mount("#app");
.gold-cell-renderer {
display: inline-flex;
align-items: center;
gap: 6px;
height: 100%;
}
.gold-cell-renderer-dot {
width: 10px;
height: 10px;
border-radius: 50%;
background-color: #d4af37;
flex-shrink: 0;
}
.country-flag-cell-renderer,
.olympic-season-cell-renderer {
display: inline-flex;
align-items: center;
gap: 6px;
height: 100%;
}
.country-flag-cell-renderer-flag,
.olympic-season-cell-renderer-icon {
height: 14px;
width: auto;
flex-shrink: 0;
}
const COUNTRY_FLAGS: Record<string, string> = {
'United States': 'us',
Germany: 'de',
'Great Britain': 'gb',
France: 'fr',
Italy: 'it',
Netherlands: 'netherlands',
Spain: 'es',
Sweden: 'se',
Norway: 'no',
Argentina: 'ar',
Brazil: 'br',
Belgium: 'be',
Greece: 'gr',
Ireland: 'ie',
Iceland: 'is',
Portugal: 'pt',
Denmark: 'den',
Colombia: 'co',
Uruguay: 'uy',
Venezuela: 've',
};
export default {
template: `<span class="country-flag-cell-renderer"><img v-if="flag" class="country-flag-cell-renderer-flag" :src="flagSrc" alt="" />{{ countryName }}</span>`,
computed: {
countryName() {
return String(this.params.value ?? '');
},
flag() {
return COUNTRY_FLAGS[this.countryName];
},
flagSrc() {
return `https://www.ag-grid.com/studio/example-assets/flags/${this.flag}.png`;
},
},
};
export default {
template: `<span class="gold-cell-renderer"><span class="gold-cell-renderer-dot"></span>{{ displayValue }}</span>`,
computed: {
displayValue() {
return this.params.valueFormatted ?? this.params.value ?? '';
},
},
};
const WINTER_YEARS = [2002, 2006, 2010];
export default {
template: `<span class="olympic-season-cell-renderer"><img class="olympic-season-cell-renderer-icon" :src="iconSrc" alt="" />{{ params.value }}</span>`,
computed: {
iconSrc() {
const year = Number(String(this.params.value ?? '').replace(/[^0-9]/g, ''));
const icon = WINTER_YEARS.includes(year) ? 'frost' : 'sun';
return `https://www.ag-grid.com/studio/example-assets/weather/${icon}.png`;
},
},
};
The example above renders a gold circle next to each value in the 'Gold' column of both widgets, a flag next to each country and a weather icon next to each year on the pivot table widget's Row Labels axis.
A field or Format definition can carry a context property holding any data your application needs. The createCellRenderer option on the table and pivot table widgets receives each field and can return a cell renderer, or undefined to keep the default rendering.
On the pivot table widget the option also covers the fields on the Row Labels axis, with two differences worth knowing:
- A Row Labels renderer is rendered inside the row's group cell, alongside its expand control and indentation, rather than replacing the cell.
- A Row Labels renderer receives no field information in its cell renderer params, so a renderer that needs to know which field it is rendering should close over the field passed to the callback.
const fields = [
// ... other fields
{ id: 'gold', context: { cellRenderer: 'gold' } },
{ id: 'country', context: { cellRenderer: 'countryFlag' } },
{ id: 'year', context: { cellRenderer: 'olympicSeason' } },
]<ag-studio
:widgets="widgets"
/* other studio properties ... */>
</ag-studio>
this.widgets = createWidgets({
overrides: [
{
id: 'grid',
options: {
createCellRenderer: (field) =>
field.context != null && field.context.cellRenderer === 'gold'
? GoldCellRenderer
: undefined,
},
},
{
id: 'pivot-grid',
options: {
createCellRenderer: (field) => {
switch (field.context != null ? field.context.cellRenderer : undefined) {
case 'countryFlag':
return CountryFlagCellRenderer;
case 'olympicSeason':
return OlympicSeasonCellRenderer;
case 'gold':
return GoldCellRenderer;
default:
return undefined;
}
},
},
},
],
});Refer to the AG Grid Cell Component Documentation for more details on how to create custom cell renderers.
Toolbar Actions Copy Link
Each widget has a toolbar containing buttons that trigger various actions.
To customise the toolbar, follow the steps for Widget Overrides and set the toolbar property.
The following actions are available by default:
| Action | ID | Widgets |
|---|---|---|
| Duplicate widget | 'duplicate' | All |
| Delete widget | 'delete' | All |
| CSV export | 'export' | Grid and chart widgets |
| Download as image | 'download' | Chart widgets |
Actions can also be executed via the API method performWidgetAction.
Execute an action for a widget.
Action can be one of the default actions ( 'duplicate' or 'delete'),
or an action specific to that widget. |
import {
createApp,
defineComponent,
onBeforeMount,
ref,
shallowRef,
} from "vue";
import { AgStudio } from "ag-studio-vue3";
import {
AgDataEngine,
AgDataSourcesDefinition,
AgReportState,
AgStudioApi,
AgStudioApiReadyEvent,
AgStudioMode,
AgStudioProperties,
enableStudioDevValidations,
} from "ag-studio";
if (process.env.NODE_ENV !== "production") {
// Enable extended validations only for development
enableStudioDevValidations();
}
const VueExample = defineComponent({
template: `
<div style="height: 100%">
<div style="display: flex; flex-direction: column; height: 100%">
<div class="example-controls">
<div class="controls-row">
<button v-on:click="exportWidget()">Export Widget to CSV</button>
</div>
</div>
<ag-studio
style="width: 100%; height: 100%;"
class="my-studio-container"
@api-ready="onApiReady"
:initialState="initialState"
:mode="mode"
:data="data"></ag-studio>
</div>
</div>
`,
components: {
"ag-studio": AgStudio,
},
setup(props) {
const studioApi = shallowRef<AgStudioApi | null>(null);
const initialState = ref<AgReportState>({
pages: [
{
id: "a",
widgets: {
"1": {
type: "grid",
dataMapping: {
cols: [
{ id: "medals.country" },
{ id: "medals.sport" },
{ id: "medals.gold", aggregation: "sum" },
{ id: "medals.silver", aggregation: "sum" },
{ id: "medals.bronze", aggregation: "sum" },
{ id: "medals.total", aggregation: "sum" },
],
},
format: {
title: {
text: "Medals by Country and Sport",
},
},
},
"2": {
type: "column-chart-grouped",
dataMapping: {
categoryKey: [{ id: "medals.country" }],
valueKey: [
{ id: "medals.gold", aggregation: "sum" },
{ id: "medals.silver", aggregation: "sum" },
{ id: "medals.bronze", aggregation: "sum" },
],
tooltipKey: [],
},
},
},
widgetLayout: {
"1": {
xTrack: 0,
yTrack: 0,
xSpan: 24,
ySpan: 16,
},
"2": {
xTrack: 0,
yTrack: 16,
xSpan: 24,
ySpan: 16,
},
},
},
],
selectedPageId: "a",
panels: {
filters: {
collapsed: true,
},
data: {
collapsed: true,
},
edit: {
collapsed: true,
},
},
});
const mode = ref<AgStudioMode>("edit");
const data = ref<AgDataSourcesDefinition | AgDataEngine>(null);
function exportWidget() {
studioApi.value!.performWidgetAction("1", "export");
}
const onApiReady = (params: AgStudioApiReadyEvent) => {
studioApi.value = params.api;
const toStudioData = (data) => ({ sources: [{ id: "medals", data }] });
fetch("https://www.ag-grid.com/studio/example-assets/olympic-winners.json")
.then((resp) => resp.json())
.then((respData) => (data.value = toStudioData(respData)));
};
return {
studioApi,
initialState,
mode,
data,
onApiReady,
exportWidget,
};
},
});
const app = createApp(VueExample);
app.mount("#app");
The example above demonstrates exporting data for the first widget via the API when the button is clicked.
CSV Export Copy Link
When performing CSV export, values are formatted the same way as in the widget.
By default, exports are limited to 1,000 rows by applying a limit on the related query. Set maxExportRows on dataOptions to change this.
<ag-studio
:dataOptions="dataOptions"
/* other studio properties ... */>
</ag-studio>
this.dataOptions = {
maxExportRows: 5000,
};maxExportRows supports -1 for unlimited exports. Depending on the size of your data, you may get unexpected or undesired results, including but not limited to: memory, bandwidth or resource exhaustion.