Cross-Widget Interactivity and Dynamic Filtering with Scripting APIs
Learn how to wire chart, table, and filter-line widgets together using Analytics Designer scripting so that a click, dropdown change, or input control drives filters and selections across an entire analytic application.
Explanation
Analytics Designer separates layout (widgets placed on the canvas) from behavior (scripts attached to widget events). The core value of the tool over plain SAC stories is that you can script exactly what happens when a user interacts with one widget so that other widgets respond in a controlled, testable way. This lesson focuses on the intermediate skill of cross-widget interactivity: capturing a user action on one object (a chart bar click, a dropdown selection, an input field change) and propagating that as a filter or selection onto other data-bound widgets. The foundation is the onClick (or onSelect) event available on chart and table widgets. Inside the event handler you receive a ResultCellData or Selection object that tells you which member, dimension, and measure the user touched. You then call setDimensionFilter, setFilter, or setVariableValue on the target widgets' data sources to push that context forward. Because each widget in Analytics Designer is bound to its own DataSource object (even when multiple widgets share the same underlying model), filters must generally be applied to each DataSource individually unless you use a shared filter or global application variable to centralize state. A second interactivity pattern uses standalone controls: Dropdown, InputField, RadioButton, and Popup widgets are not bound to a model directly but raise onSelect or onChange events. Scripts read the selected value with getSelectedKey() and apply it via setVariableValue (for prompted variables) or setDimensionFilter (for straightforward member filters). This lets you build parameter-driven applications, for example a region selector that filters five charts and a table simultaneously, or a scenario switcher for planning versions. A third and more advanced but still intermediate-level pattern is using an Application-level script variable (a global variable defined in the Analytics Designer variables panel, not a model variable) to hold shared state, such as the currently selected KPI or currently selected time period. Widgets read this global variable in their onInitialization or refresh scripts, which keeps the filtering logic centralized and avoids duplicating the same filter-setting code in every event handler. This is important for larger applications where ten or more widgets need to respond consistently to the same selection. Runtime flow matters here: scripts execute on the client (browser) within the SAC runtime, calling back to the server for each data refresh. Excessive chained filter calls (setting a filter on widget A, which triggers an onResultChanged event that sets a filter on widget B, which triggers another refresh) can cause visible flicker and slow response times. A disciplined design applies all filters needed for a given user action in one script block, then triggers a single refresh cycle, rather than nesting reactive events that fire further events. Troubleshooting typically involves the browser console and the built-in script debugger. Common issues are: filtering on a dimension that does not exist in the target data source (causes a runtime error visible in the console, not a silent failure), using getSelectedKey() before the widget has completed initialization (returns undefined on first load), and mismatched dimension technical names between models when trying to apply the same filter value across data sources built from different fact/dimension structures. For planning applications specifically, similar interactivity patterns apply to version selection and category filtering, but you must also account for whether a change should trigger a data entry validation or a publish action, which uses separate planning-specific script APIs rather than plain filter APIs. This distinction between analytic filtering and planning actions is a frequent point of confusion for consultants moving from reporting-only stories into Analytics Designer applications.
Code example
// Example: chart click drives filter on two other widgets, plus a global variable // Global script variable (defined in Analytics Designer's Variables panel): // gv_SelectedRegion (type: String) // Script attached to Chart_1.onResultChanged or Chart_1.onClickChart_1.onClick = function(selection){ // selection is an array of ResultCellData objects if (selection.length > 0) { var clickedRegion = selection[0].dimensionMembers["Region"].id; // Update the shared global variable so any widget can read it Application.setVariableValue("gv_SelectedRegion", clickedRegion); // Apply the filter directly to related widgets' data sources Table_1.getDataSource().setDimensionFilter("Region", clickedRegion); Chart_2.getDataSource().setDimensionFilter("Region", clickedRegion); }}; // Dropdown-driven filter, independent of the chart click aboveDropdown_TimePeriod.onSelect = function(selectedKey, selectedText){ Table_1.getDataSource().setDimensionFilter("Time.Period", selectedKey); Chart_2.getDataSource().setDimensionFilter("Time.Period", selectedKey);}; // Reset button clears both filters and the global variableButton_Reset.onClick = function(){ Table_1.getDataSource().removeDimensionFilter("Region"); Chart_2.getDataSource().removeDimensionFilter("Region"); Table_1.getDataSource().removeDimensionFilter("Time.Period"); Chart_2.getDataSource().removeDimensionFilter("Time.Period"); Application.setVariableValue("gv_SelectedRegion", "");};Real project scenario
A retail FP&A team requested an executive dashboard where clicking a bar in a regional sales chart would filter a detail table, a trend chart, and a KPI card simultaneously, while a separate dropdown let users override the time period independently. The initial build applied filters directly inside each chart's onClick script with duplicated logic across three widgets. When the team later added a fourth widget, two of the four filter calls were forgotten, causing inconsistent results that were only caught during user acceptance testing. The team refactored to a global script variable holding the selected region, with each widget reading that variable in a shared function called from an initialization script, which made adding future widgets a one-line change instead of a multi-widget edit.
Common mistakes
⢠Duplicating filter-setting logic in every widget's event script instead of centralizing state in a global variable or shared function, making the application fragile to extend ⢠Calling getSelectedKey() or reading selection data before the widget has finished its onInitialization, resulting in undefined values on first page load ⢠Assuming a dimension filter set on one widget's DataSource automatically applies to other widgets bound to a different DataSource instance, even when they use the same underlying model ⢠Chaining reactive onResultChanged events across multiple widgets, causing visible flicker and unpredictable refresh order ⢠Filtering on a technical dimension ID that does not exist identically across all target models, causing a silent mismatch or runtime script error
Best practices
⢠Centralize cross-widget filter state in a global Application-level script variable rather than repeating setDimensionFilter calls in every widget's event handler ⢠Apply all filters needed for one user action within a single script block to avoid triggering cascading refresh events ⢠Guard against undefined selections by checking array length or null before reading selection or dropdown values ⢠Use consistent technical dimension names across models feeding the same application, or map values explicitly when names differ ⢠Provide an explicit reset/clear action so users can return widgets to an unfiltered state without reloading the application ⢠Test interactivity scripts with the browser developer console open during build to catch silent script errors early
Interview angle
Interviewers assess whether a candidate understands that Analytics Designer widgets are independently bound to their own DataSource objects, so cross-widget filtering must be explicitly scripted rather than assumed to propagate automatically as it might in a standard SAC story. Strong answers describe centralizing shared filter state in a global script variable versus duplicating logic per widget, explain the risk of chained reactive events causing performance or ordering issues, and can articulate the difference between applying a dimension filter and setting a prompted variable value.