2025 Feb 11 7:19 PM - edited 2025 Feb 12 5:24 AM
I want to show the story filter value in a textbox. If 'All' is selected in the filter, then it should show 'All Business Units' otherwise it should show only the specific value that is selected.
Currently what I did: I used a dynamic text & added that in the textbox. It shows 'All Business Units' when 'All' is selected in the filter, but if other options are selected (for example X or Y), then it is showing 'X Business Units' or 'Y Business Units' because the Business Units section is hardcoded in the textbox. I only want to show X or Y when the specific option is selected in the filter.
Is this possible to achieve? Kindly suggest if there's any way to achieve this!
Request clarification before answering.
Hi,
Yes, this is possible. The key is understanding how .getDimensionFilters() works. If ‘All’ is selected in the story filter, it returns a zero-length array. If any specific values are selected, it returns an array of length 1 containing a filter object. To access the selected values, you need to cast the filter object to either SingleFilterValue or MultipleFilterValue before you can access .value or .values. Although these casted objects have a .description property, it unfortunately remains an empty string (perhaps a bug), so it is necessary to then call .getMember() for the actual description.
Using a dynamic text element in a text box to display the story filter natively is more responsive, but the scripted approach allows greater customisation of how the text is displayed. For example, both the native dynamic text and the scripted approach preserve the order in which users select values. If they should always be sorted alphabetically, memberNames.sort() can be used before joining them. The separator can also be modified by adjusting .join(), or the approach can be changed entirely to display a count, such as “17 Business Units” instead of listing each name.
If your list of Business Units is not too long, performance could be improved by calling .getMembers() during story initialization to store all member IDs and descriptions in global variables. This would avoid repeated costly .getMember() calls each time the filter changes.
Here’s a script that will correctly update a textbox:
var displayText = "";
// Retrieve the dimension Story Filter.
// Do this on Application.getFileDataSource() as getDataSource() on a widget won't return the Story filter
var dimensionFilters = Application.getFileDataSource("YOUR_DATASOURCE_ID")
.getDimensionFilters("BUSINESS_UNIT_DIMENSION");
// If 'All' is selected, the array will be empty
var dimensionFilter = dimensionFilters[0];
if (dimensionFilter === undefined) {
displayText = "All Business Units";
} else {
// Now cast to the appropriate filter type before .value or .values can be accessed.
switch (dimensionFilter.type) {
case FilterValueType.Single:
var singleValue = cast(Type.SingleFilterValue, dimensionFilter);
// Retrieve description via getMember() since .description is empty
displayText = this.getDataSource()
.getMember("BUSINESS_UNIT_DIMENSION", singleValue.value)
.description;
break;
case FilterValueType.Multiple:
var multipleValues = cast(Type.MultipleFilterValue, dimensionFilter).values;
var memberNames = ArrayUtils.create(Type.string);
for (var i = 0; i < multipleValues.length; i++) {
var memberDescription = this.getDataSource()
.getMember("BUSINESS_UNIT_DIMENSION", multipleValues[i])
.description;
memberNames.push(memberDescription);
}
// Sort alphabetically before joining (optional)
memberNames.sort();
displayText = memberNames.join(", ");
break;
}
}
// Apply the text to the textbox
Text_1.applyText(displayText);
You would add this script to the onResultChanged event of an appropriate widget.
For additional detail on .getDimensionFilters() see: https://help.sap.com/docs/SAP_ANALYTICS_CLOUD/00f68c2e08b941f081002fd3691d86a7/646826977afe4709af322...
Cheers, Ivan.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Just checked, and you can definitely make this substantially faster by preloading all Business Unit values during initialisation. One approach is to store them in two separate string arrays: one for the keys and one for the descriptions. When needed, you can find the index of a key in the first array and use it to access the corresponding description in the second array.
A cleaner approach I have used in other situations is to repurpose the ResultMemberInfo datatype for a global script variable. This allows you to efficiently store and retrieve Business Unit descriptions without repeatedly calling .getMember(). If using the ResultMemberInfo approach, your initialisation script would look something like this, assuming you have created the script variable BUs with type ResultMemberInfo:
if (BUs === undefined) {
// First need to initialise the variable to access .properties
BUs = cast(Type.ResultMemberInfo, {
id: "1",
properties: {
INIT: "" // Placeholder property for initialisation
}
});
}
var buMembers = Chart_1.getDataSource().getMembers("BUSINESS_UNIT_DIMENSION", {limit: 1000});
for (var i = 0; i < buMembers.length; i++) {
// Leverage the .properties object to store the descriptions by key
BUs.properties[buMembers[i].id] = buMembers[i].description;
}
Once the key:description pairs have been stored in the properties object of the BUs variable during initialisation, the onResultChanged script can be significantly condensed. Instead of calling .getMember() repeatedly, we can simply retrieve the descriptions directly from BUs.properties, making the script significantly more efficient. The updated script would look like this:
var displayText = "";
// Retrieve the dimension filter
var dimensionFilters = Application.getFileDataSource("YOUR_DATASOURCE_ID")
.getDimensionFilters("BUSINESS_UNIT_DIMENSION");
// If 'All' is selected, the array will be empty
var dimensionFilter = dimensionFilters[0];
if (dimensionFilter === undefined) {
displayText = "All Business Units";
} else {
switch (dimensionFilter.type) {
case FilterValueType.Single:
var singleValue = cast(Type.SingleFilterValue, dimensionFilter);
// Retrieve description from preloaded properties
displayText = BUs.properties[singleValue.value];
break;
case FilterValueType.Multiple:
var multipleValues = cast(Type.MultipleFilterValue, dimensionFilter).values;
var memberNames = ArrayUtils.create(Type.string);
for (var i = 0; i < multipleValues.length; i++) {
// Retrieve description from preloaded properties
memberNames.push(BUs.properties[multipleValues[i]]);
}
// Sort alphabetically before joining (optional)
memberNames.sort();
displayText = memberNames.join(", ");
break;
}
}
// Apply the text to the textbox
Text_1.applyText(displayText);
By using the preloaded BUs.properties object, this approach eliminates the costly .getMember() API calls, making the overall result just as fast as the native Dynamic Text approach in my testing.
Cheers, Ivan.
@Ivan_CThis works! Thanks!
Hello,
I wanted to say, that you can use a script for that, but it seems that the getdimensionfilter on the story filter is full buggy.
As workaround, you can place an inputcontrol with same dimension as the story filter and you use the inputcontrol as dynamic test link. For me it's working. And then you hide the input control.
I hope this works for you too
cya
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
59 | |
8 | |
7 | |
6 | |
5 | |
5 | |
5 | |
4 | |
4 | |
4 |
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.