Customer Banners (Ads) - SpiceUp. AX and SpotfireX Disclaimer



If you find this site useful and you want to support, buy me a coffee   to keep this site alive and without ads.

Autocomplete

 Add autocomplete to an existing Spotfire input control (webplayer and cliente )


html

<div id="autocomplete"> 
<SpotfireControl id="spotfire_Input" />
</div>

<div id="autocomplete-data" hidden>
John Doe,Jane Smith,Robert Johnson,Michael Brown,Emily Davis,Sarah Miller,James Wilson,Patricia Moore,Richard Taylor,Linda Anderson
</div>

note: replace the autocomplete-csv-values with a uniqueConcatenate([column]) calculated value, but you can use as is to test the script



javascript

function setupAutocomplete(id){
    let currentFocus = -1;
    let isScriptTriggered = false;

    const autoCompleteDiv = document.getElementById(id);
    autoCompleteDiv.position = "relative";
    const spotfireInput = autoCompleteDiv.firstElementChild;
    const autocompleteInput = document.createElement('input');
    autocompleteInput.id = id + "Input";
    autocompleteInput.style.display = 'none';

    // Copy style from SpotfireControl to input
    for (let style in spotfireInput.style) {
        if (spotfireInput.style.hasOwnProperty(style) && spotfireInput.style[style]) {
            autocompleteInput.style[style] = spotfireInput.style[style];
        }
    }
    autoCompleteDiv.appendChild(autocompleteInput);

    //popup for autocomplete items
    const popup = document.createElement('div');
    popup.style.width = `${spotfireInput.offsetWidth}px`;

    popup.style.position = 'absolute';
    popup.style.zIndex = '100';
    popup.className = 'autocomplete-items';
    popup.style.display = 'none';
    autoCompleteDiv.appendChild(popup);

    //observer for csv values as it comes from a calculated value
    const csvObserver = new MutationObserver(() => {
        csvValues = document.getElementById(id + '-data').innerText.split(',');
    });

    csvObserver.observe(document.getElementById(id + '-data'), {
        childList: true,
        characterData: true,
        subtree: true
    });

    let csvValues = document.getElementById(id + '-data').innerText.split(',');


    function toggleInputDisplay() {
        spotfireInput.style.display = '';
        autocompleteInput.style.display = 'none';
        spotfireInput.value = autocompleteInput.value;
        isScriptTriggered = true;
        spotfireInput.focus();
        spotfireInput.blur();
        isScriptTriggered = false;

    }

    autocompleteInput.addEventListener('click', () => {
        autocompleteInput.value = "";
    });

    autocompleteInput.addEventListener('input', () => {
        const inputValue = autocompleteInput.value;
        const filteredValues = csvValues.filter(name => name.toLowerCase().includes(inputValue.toLowerCase()));
        popup.innerHTML = '';

        filteredValues.forEach(value => {
            const div = document.createElement('div');
            div.className = "sf-element-dropdown-list-item";
            div.innerHTML = value.replace(new RegExp(inputValue, 'gi'), match => "<span class='highlight'>" + match + "</span>");

            // Copy style from src input to div
            for (var style in autocompleteInput.style) {
                if (autocompleteInput.style.hasOwnProperty(style) && autocompleteInput.style[style]) {
                    div.style[style] = autocompleteInput.style[style];
                }
            }

            div.addEventListener('click', () => {
                autocompleteInput.value = value;
                popup.style.display = 'none';
                spotfireInput.value = value;
                currentFocus = -1;

                toggleInputDisplay();


            });
            popup.appendChild(div);
        });
        popup.style.display = filteredValues.length ? 'block' : 'none';
    });




    autocompleteInput.addEventListener('keydown', (e) => {
        const divs = popup.getElementsByTagName('div');
        if (e.keyCode == 40) { // Down arrow
            currentFocus++;
            if (currentFocus >= divs.length) currentFocus = 0;
        } else if (e.keyCode == 38) { // Up arrow
            currentFocus--;
            if (currentFocus < 0) currentFocus = divs.length - 1;
        } else if (e.keyCode == 13) { // Enter
            if (currentFocus > -1) {
                divs[currentFocus].click();
            } else {
                spotfireInput.value = autocompleteInput.value;
                isScriptTriggered = true;
                toggleInputDisplay();
                isScriptTriggered = false;
            }
        } else if (e.keyCode == 27) { // Escape key
            isScriptTriggered = true;
            toggleInputDisplay();
            isScriptTriggered = false;

        }
        for (let i = 0; i < divs.length; i++) {
            divs[i].classList.remove('over');
        }
        if (currentFocus > -1) {
            divs[currentFocus].classList.add('over');
        }
    });

    spotfireInput.addEventListener('focus', () => {
        if (isScriptTriggered) return;
        // When spotfireInput gets focus, hide it and show input
        spotfireInput.style.display = 'none';
        autocompleteInput.style.display = '';
        autocompleteInput.value = "";
        autocompleteInput.focus();
    });


    autocompleteInput.addEventListener('blur', () => {
        setTimeout(() => {
            popup.style.display = 'none';
            toggleInputDisplay();
        }, 200);
    });



    //styles
    const styleTag = `
    <style>

    #autocompleteInput{
        outline: none; 
    }

        .autocomplete-items{
        background-color: #fff;
        border:1px solid #c6c8cc;
        }

        .autocomplete-items div:hover, 
        .autocomplete-items div.over {
        color: #FFFFFF !important;
        background-color: #7289F9;
        cursor:default;
        }

        .highlight {
        font-weight: bold;
        text-decoration: underline;
        }
    </style>`

    autoCompleteDiv.insertAdjacentHTML('afterEnd', styleTag)

}

setupAutocomplete("autocomplete")




No comments: