Read the filters and parameters
Report the exact state the viewer has put the dashboard in — every filter on every worksheet, every parameter value.
Why it matters
Summary data tells you what the viewer sees; filters and parameters tell you what they asked for. An export extension that stamps the filter state onto its output turns 'here is a CSV' into 'here is a CSV you can trust'; a write-back app that records parameter values captures the scenario, not just the numbers. Filters are per-worksheet and typed — categorical, range, relative-date — and each type answers differently, so the switch on filterType is the idiom to internalize. Parameters are simpler: workbook-global, one current value each.
Write the JavaScript for a Tableau dashboard extension that renders a 'current state' panel: for every worksheet in the dashboard, call getFiltersAsync() and describe each filter — categorical filters as fieldName plus the appliedValues' formattedValues (noting when isAllSelected or isExcludeMode is true), range filters as fieldName plus minValue and maxValue formattedValues, and any other filterType by name only. Then call dashboard.getParametersAsync() and list each parameter's name and currentValue.formattedValue. De-duplicate filters that appear on multiple worksheets by fieldName before rendering.
Step 1 — Filters: per worksheet, and typed
Filters live on worksheets, not the dashboard — the same field filtered on three sheets is three filter objects, so a state panel de-duplicates by fieldName. The filterType switch is the whole trick: categorical filters carry appliedValues, range filters carry minValue/maxValue, relative-date filters describe a period. One honest subtlety: a categorical filter set to All reports isAllSelected as true — and its appliedValues may be empty, which is not the same as nothing selected. Check the flag before you trust the list.
(async () => {
await tableau.extensions.initializeAsync();
const dashboard = tableau.extensions.dashboardContent.dashboard;
for (const ws of dashboard.worksheets) {
const filters = await ws.getFiltersAsync();
for (const f of filters) {
switch (f.filterType) {
case 'categorical': {
const values = f.isAllSelected
? '(all)'
: f.appliedValues.map(v => v.formattedValue).join(', ');
const mode = f.isExcludeMode ? ' [excluding]' : '';
console.log(ws.name + ': ' + f.fieldName + ' = ' + values + mode);
break;
}
case 'range':
console.log(ws.name + ': ' + f.fieldName + ' between ' +
(f.minValue && f.minValue.formattedValue) + ' and ' +
(f.maxValue && f.maxValue.formattedValue));
break;
default:
console.log(ws.name + ': ' + f.fieldName +
' (' + f.filterType + ' filter)');
}
}
}
})();Step 2 — Parameters: workbook-global, one value each
Parameters belong to the workbook, so they hang off the dashboard object and there is exactly one current value per parameter — no per-worksheet walk, no type switch beyond the value itself. getParametersAsync() for the inventory, findParameterAsync(name) when you already know which one you want.
Together with the filter walk above, this is a complete snapshot of viewer intent — the block worth stamping onto every export your extension produces.
(async () => {
await tableau.extensions.initializeAsync();
const dashboard = tableau.extensions.dashboardContent.dashboard;
const params = await dashboard.getParametersAsync();
for (const p of params) {
console.log('parameter: ' + p.name + ' = ' +
p.currentValue.formattedValue +
' (' + p.dataType + ')');
}
// Direct lookup when the name is known:
const topN = await dashboard.findParameterAsync('Top N');
if (topN) {
console.log('Top N is currently ' + topN.currentValue.value);
}
})();Got what you came for? Mark the stop and the line fills in beneath you.