Jump to content
  • Use filters to enhance the functionality of the default Spotfire Property Controls

    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. 

     

    dropdown-autocomplete.gif.b0131a3f308fa84a4fed67bdbaaf0325.gifinput-filter.gif.f247eb121769c29306318fdc72bd6fa3.giflabel-filter.gif.32582518cf3dbfa2773cd1109e3d23e3.gif 

     

    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 dashboardinput-multifilter.thumb.gif.078547312546f26777cce8d2a05801c9.gif

    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

    dropdown-autocomplete.gif.2fc4dd61972e2874c909ad1dad5a8f00.gif

    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

    1. Open the Sales and Marketing analysis from the library/samples folder
      1. Delete all but Sales performance and just keep the map
      2. Limit the SalesAndMarketing map layer with expression:  upper([store Name]) ~= Upper("${selection}") and disable any filtering schemes
    2. 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
    3. Change the [store Name] filter type to use for the input property control as List Box Filter
    4. 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
    5. Add a Text area, edit in html and copy the above html 
    6. 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
    7. Add the filters from the "filtersForPropertyControls" filtering scheme inside the <span class="sfFltr"> element
    8. 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>
    9. Insert an Input field property control inside the <div class="sfInput"> element and link it to the "selection" document property
    10. 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.

    input-multifilter.thumb.gif.fec1486d2ce60215763d607efd98dffa.gifhtml

    <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.

     


    User Feedback

    Recommended Comments

    There are no comments to display.


×
×
  • Create New...