Introduction
The default Spotfire Property Controls have some limitation such as the maximum 1,000 items a Dropdown Property Control can hold. In addition, it can be hard to find elements not to mention Input fields. In most cases, the use of filters is a great way to limit data, but what if for some reason you need to stick to Property Controls?
Even if you use filters to drive your visualizations and there is no need to pass the selection from the filters to document properties, you can use this technique to show and hide them as needed and use labels to make selections as per the last example
Examples
We can combine dropdown, input and labels with one or more filters.
Here is an example with multiple filters to help narrow down the value for the document property. A great way to save space on your analysis or dashboard
Example 1: List Box Filter for Drop-down list, label or Input field Property Controls
In this example we use a List Box Filter to assist the selection of a value for the Drop-down list Property Control
html
<div id="myInput" > <span class="ddown"><SpotfireControl dropdown /> <span class='srchBtn'>⋯</span> </span> <span class="sfFltr hidden"><SpotfireControl filter /> <span class='closeBtn'>✕</span> </span> <div class="sfCalcVal hidden"><SpotfireControl calculated value /></div> <div class="sfInput hidden"><SpotfireControl input /></div> </div>
Script
//script params target = "myInput" //node elements container = document.getElementById(target); dropdown = document.querySelector(".ddown"); filter = document.querySelector(".sfFltr"); searchButton= document.querySelector(".srchBtn"); closeButton = document.querySelector(".closeBtn"); selection = document.querySelector(".sfCalcVal"); sfInput = document.querySelector(".sfInput input"); //events searchButton.addEventListener("click",()=>{ dropdown.classList.add("hidden") filter.classList.replace("hidden","visible") oldValue = sfInput.value }) closeButton.addEventListener("click",()=>{ dropdown.classList.remove("hidden") filter.classList.replace("visible","hidden") sfInput.focus(); sfInput.blur(); }) //monitor selection observer = new MutationObserver((x)=>{ sfInput.value = selection.innerText; closeButton.click(); }) observer.observe(selection, {childList: true,subtree: true}); //apply styling and attributes css = `<style> .closeBtn, .srchBtn, .resetBtn, .okBtn{ vertical-align:top; cursor:pointer; } .visible{ position:fixed; z-index:1; } .hidden{ position:fixed; z-Index:-1; } </style>` container.insertAdjacentHTML('afterend',css)
Procedure
-
Open the Sales and Marketing analysis from the library/samples folder
- Delete all but Sales performance and just keep the map
- Limit the SalesAndMarketing map layer with expression: upper([store Name]) ~= Upper("${selection}") and disable any filtering schemes
- Create a new filtering scheme called "filtersForPropertyControls" or something like that. you can do that by right clicking the filter panel and show the filtering scheme menu
- Change the [store Name] filter type to use for the input property control as List Box Filter
- Make sure the "filtersForPropertyControls" filtering scheme IS NOT selected in the filters panel to avoid other visualizations to be affected by the current filtering scheme
- Add a Text area, edit in html and copy the above html
- Create an input or dropdown property control linked to a new document property called "selection" from a Text area. Place the control as the first child of the <span class="ddown"> element. if using a dropdown, make sure to select unique values from the [store Name] column
- Add the filters from the "filtersForPropertyControls" filtering scheme inside the <span class="sfFltr"> element
-
Create a calculated value inside the <div class="sfCalcVal"> to get the first element from the filter and limit the data only from the "filtersForPropertyControls" filtering scheme: First([store Name]). It is very important not to leave any spaces. For example:
- <div class="sfCalcVal"><SpotfireControl id="2d1..26cc" /></div>
- Insert an Input field property control inside the <div class="sfInput"> element and link it to the "selection" document property
- Save the text area and Insert the JavaScript
Example 2: Multiple List Box Filters for a Drop-down list , label or Input field Property Controls
The steps are the same as the previous example, but the html and JavaScript changes a bit. Requires also a reset link Action Control [↻] that resets the filtersForPropertyControls filtering scheme when the filters are visible.
html
<div class="sfInput hidden"><SpotfireControl input field /></div> <div class="sfCalcVal hidden"><SpotfireControl calculated value /></div> <div id="myInput" > <span class="ddown"><SpotfireControl dropdown, label or input field /> <span class='srchBtn'>⋯</span> </span> <span class="sfFltr hidden"> <SpotfireControl List Box Filter 1 /> <SpotfireControl List Box Filter 2 /> : <SpotfireControl List Box Filter N /> <span title="cancel" class='closeBtn'>✕</span> <span title="cancel" class='okBtn'>✓</span> <span title="reset" class='resetBtn'><SpotfireControl action control /> </span> </span> </div>
JavaScript
//node elements container = document.querySelector("#myInput"); dropdown = document.querySelector(".ddown"); filter = document.querySelector(".sfFltr"); searchButton= document.querySelector(".srchBtn"); closeButton = document.querySelector(".closeBtn"); okButton = document.querySelector(".okBtn"); selection = document.querySelector(".sfCalcVal"); sfInput = document.querySelector(".sfInput input"); oldValue = null //events searchButton.addEventListener("click",()=>{ dropdown.classList.add("hidden") filter.classList.replace("hidden","visible") oldValue = sfInput.value }) closeButton.addEventListener("click",()=>{ dropdown.classList.remove("hidden") filter.classList.replace("visible","hidden") sfInput.value = oldValue sfInput.focus(); sfInput.blur(); }) okButton.addEventListener("click",()=>{ dropdown.classList.remove("hidden") filter.classList.replace("visible","hidden") }) //monitor selection observer = new MutationObserver((x)=>{ sfInput.value = selection.innerText; sfInput.focus(); sfInput.blur(); }) observer.observe(selection, {childList: true,subtree: true}); //apply styling and attributes css = `<style> .closeBtn, .srchBtn, .resetBtn, .okBtn{ vertical-align:top; cursor:pointer; } .visible{ position:fixed; z-index:1; } .hidden{ position:fixed; z-Index:-1; } </style>` container.insertAdjacentHTML('afterend',css)
IronPython script
This script is for the reset action control link that resets the filtersForPropertyControls filtering scheme. It goes inside the <span title="reset" class='resetBtn'><SpotfireControl action control /> </span>
filteringSchemeName= "filtersForPropertyControls" dataFilteringSelectionCollection = Document.Data.Filterings[filteringSchemeName] filteringScheme = Document.FilteringSchemes[dataFilteringSelectionCollection] filteringScheme.ResetAllFilters()
Example 3: Multi Selection Label
The procedure is the same as the Example 2. The only difference is that we are using a calculated value to display the selection. This calculated value goes inside the <span class="ddown srchBtn"> tag. The expression is:
if(UniqueCount([store Name])<5,UniqueConcatenate([store Name]),UniqueCount([store Name]) & " stores selected")
Create a list box (multiselect) Property Control to create a 'selections' document property array. You can delete or hide the Control, but not the document property. Add a script to the 'selection' document property when its value changes to update the 'selections' document property array:
vals = Document.Properties["selection"] vals = [val.strip() for val in vals.split(",")] Document.Properties["selections"] = vals
Now you can use this document property for on-demand settings, or limiting the data by this expression used in other visualizations:
[store Name] in ($map("'${selections}'", ","))
Back to the JavaScript Component Hub for Spotfire
Disclaimer
This method makes assumptions about the inner workings of Spotfire version 12.0.0 LTS Any analyses created using this hack may cause instability and performance issues and are likely to break when Spotfire is upgraded or hotfixed in the future. Any issues resulting from applying this hack are not covered by Spotfire maintenance agreements and Support will not assist in troubleshooting problems with analysis files where this approach is used.
Recommended Comments
There are no comments to display.