Scripting Widget Interactions and Data Source Filtering in Analytics Designer
Learn how to use Analytics Designer's scripting language to wire up widget events, control filters on data sources, and synchronize multiple charts/tables so an analytic application behaves like a purpose-built app rather than a static story.
Explanation
Analytics Designer separates itself from standard Stories by giving consultants a scripting layer (a JavaScript-like language specific to SAC) that runs against Application, Page, and Widget objects. Once a project moves past simple drag-and-drop dashboards, script becomes necessary to deliver behaviors like: filtering one chart based on selection in another, showing/hiding panels based on user role or dropdown value, resetting filters with a button, or triggering data refresh only after several inputs are set. This is the core reason Analytics Designer exists as a separate tool from Optimized Story Experience with basic interactivity. The object model matters: an Application contains Pages, Pages contain Widgets (charts, tables, dropdowns, buttons, shapes, script variables), and Widgets expose Data Sources when bound to a model (SAC live/import model, which may itself be sourced from a Datasphere space via live connection or replication). Each widget type exposes a scripting API surface - for example a Chart widget exposes methods like getDataSource(), setDimensionFilter(), and event handlers like onResultChanged or onSelect. A Dropdown/Input Control exposes onSelect with the selected value, and a Button exposes onClick. A typical interaction pattern: a Dropdown widget's onSelect script calls Chart_1.getDataSource().setDimensionFilter('Region', Dropdown_1.getSelectedKey()) to filter a chart by the chosen region. More advanced flows chain filters across multiple widgets, use Script Variables to hold intermediate state (e.g., a selected year that several widgets read), and use Application-level scripts (onInitialization) to set default filters/date ranges before the user does anything, avoiding an initial full-context expensive query. Data source scripting also covers cross-widget synchronization: when a Table widget's selection changes (onSelect), a script can propagate that selection as a filter to a separate Chart's data source, creating a master-detail experience. Because Analytics Designer scripts execute in the browser against the SAC runtime engine, every setDimensionFilter or setVariableValue call typically triggers a new query against the backend model - which, if that model uses a Datasphere live connection, becomes a live query pushed down to Datasphere/HANA. This has real performance implications: scripts that fire multiple sequential filter calls without batching can cause multiple round trips; some APIs support batch operations or waiting for onResultChanged before triggering dependent logic, which is important to avoid race conditions where a dependent widget queries before the upstream filter has actually been applied. Debugging is done via the built-in Application script console/log and by inspecting variable values at runtime; there is no traditional ABAP-style debugger, so console.log-style output and stepping through business logic manually is standard practice. Error handling should account for undefined selections (e.g., a user clicking a button before making a dropdown selection) using conditional checks before calling data source methods, since calling a filter method with an undefined key can throw a runtime script error and halt further script execution silently in some cases, which is a common source of 'my app breaks intermittently' defects reported by end users. From a project perspective, script correctness must be verified against both import and live data sources: filter and variable APIs sometimes behave differently depending on whether the underlying model is a live SAC model, a Datasphere-backed live connection, or an imported/acquired dataset, particularly around variable prompting and default value handling. Consultants should always test scripted behavior against the actual target connection type used in production, not just against a convenient offline model.
Code example
// Application-level script: set on Application 'onInitialization' event// Sets a sensible default period filter so the first render is not a full-context queryApplication.onInitialization = function() { var defaultYear = "2024"; Chart_1.getDataSource().setDimensionFilter("Year", defaultYear); Table_1.getDataSource().setDimensionFilter("Year", defaultYear); Dropdown_Year.setSelectedKey(defaultYear);}; // Dropdown widget: onSelect event - propagate region selection to two widgetsDropdown_Region.onSelect = function(selectedKey, selectedText) { if (selectedKey === undefined || selectedKey === null) { return; // guard against empty/undefined selection before filtering } Chart_1.getDataSource().setDimensionFilter("Region", selectedKey); Table_1.getDataSource().setDimensionFilter("Region", selectedKey);}; // Table widget: onSelect - master/detail drill into a chartTable_1.onSelect = function(selections) { if (selections.length === 0) { return; } var productKey = selections[0].Product; // depends on dimension key exposed in selection Chart_Detail.getDataSource().setDimensionFilter("Product", productKey);}; // Button widget: onClick - reset all filters back to defaultsButton_Reset.onClick = function() { Chart_1.getDataSource().removeDimensionFilter("Region"); Table_1.getDataSource().removeDimensionFilter("Region"); Dropdown_Region.setSelectedKey(null);};Real project scenario
A retail client wanted a planning review app: users pick a region and year from dropdowns, see a summary chart and a detail table, and can click a table row to drill into a product-level trend chart. The underlying model was a live connection to a Datasphere space combining sales actuals and a planning version. The consultant built the app in Analytics Designer using onSelect scripts to chain the dropdown, table, and detail chart filters, and used Application.onInitialization to default to the current fiscal year so the app didn't run an unfiltered multi-year query on load, which had caused a 20+ second initial load in an earlier prototype. During UAT, business users reported the drill-down chart sometimes stayed blank after clicking a table row - traced to the table's selection object using a different dimension key format than the detail chart's filter API expected, requiring a small key-mapping fix in the onSelect script.
Common mistakes
⢠Calling setDimensionFilter or setVariableValue with an undefined/null value when no prior selection exists, causing a silent script failure that stops subsequent lines in the same handler ⢠Chaining many sequential filter calls across widgets without considering that each triggers its own query, leading to visible flicker and unnecessary backend load ⢠Not testing scripted variable/filter behavior against the actual production connection type (live Datasphere connection vs. import model), assuming behavior is identical across both ⢠Forgetting Application.onInitialization defaults, so the app's first render runs a full unfiltered query against a large live dataset ⢠Using hardcoded dimension member keys in scripts instead of deriving them from user selections, breaking when master data changes ⢠Not wrapping cross-widget dependent logic in onResultChanged handlers, causing a dependent widget to query before the upstream filter has actually taken effect
Best practices
⢠Always guard script logic against undefined/null selections before calling filter or variable-setting APIs ⢠Set sensible default filters in Application.onInitialization to avoid expensive first-load queries on large live models ⢠Use Script Variables to centralize shared state (like a selected year or region) that multiple widgets read, instead of duplicating logic per widget ⢠Test scripted behavior against the actual target connection type (live Datasphere connection, import, acquired) used in production before sign-off ⢠Use onResultChanged handlers when a widget's logic depends on another widget's query having completed, rather than assuming synchronous timing ⢠Keep script logic modular with small reusable functions rather than large duplicated event handlers across widgets, to ease maintenance
Interview angle
Interviewers assess whether a candidate understands the Analytics Designer object model (Application/Page/Widget/DataSource) and can explain a real event-driven scripting pattern such as master-detail filtering or cascading dropdowns, rather than only listing widget types. Be ready to explain why guard checks for undefined selections matter, how onResultChanged differs from onSelect, and how scripted filters behave differently on live versus import/acquired data sources - this shows hands-on build experience rather than only story-authoring familiarity.