I want to share this tweak to add feature filtered search in Admin for Dropdown and Checkbox with Multiple Value in Couchcms admin Panel

These are the script:
Code: Select all
<cms:config_form_view>
        <cms:script>
            //FOR CHECKBOX
            (function($) {
                $(document).ready(function() {
                    console.log("Custom script for checkboxes loaded");
           
                    // Create search and input fields
                    const searchField = $('<input type="text" id="searchInput" placeholder="Cari point of interest">');
                    const inputField = $('<input type="hidden" id="categoryInput" name="f_poi1[]" value="">'); // Hidden input to store selected values
           
                    // Create container for selected tags
                    const selectedTagsContainer = $('<div class="selected-tags"></div>').insertBefore(searchField);
           
                    // Find the checkbox container
                    const checkboxContainer = $('#k_element_poi1 .ctrls-checkbox');
           
                    // Append search field and selected tags container to the container
                    checkboxContainer.before(searchField);
                    checkboxContainer.before(selectedTagsContainer);
           
                    // Hide all original checkboxes
                    checkboxContainer.find('label').hide();
           
                    // Create dropdown-like menu for checkboxes
                    const dropdownMenu = $('<div class="dropdown-menu"></div>').appendTo('body');
                    //const dropdownSelect = $('<div class="dropdown-select">Pilih point of interest</div>').appendTo(dropdownMenu);
                    const dropdownItems = $('<div class="dropdown-items"></div>').appendTo(dropdownMenu);
           
                    // Populate dropdown items
                    checkboxContainer.find('label').each(function() {
                        const checkbox = $(this).find('input[type="checkbox"]');
                        const text = $(this).text().trim();
                        const dropdownItem = $(`<div class="dropdown-item" data-value="${checkbox.val()}">${text}</div>`).appendTo(dropdownItems);
           
                        // Handle click on dropdown item
                        dropdownItem.on('click', function() {
                            const value = $(this).data('value');
                            const isChecked = checkbox.prop('checked');
                            checkbox.prop('checked', !isChecked).trigger('change');
                            updateSelectedTags(); // Update selected tags display
                            updateCheckboxVisibility(); // Update checkbox visibility
                            dropdownMenu.hide(); // Hide dropdown menu after selection
                            searchField.val('').trigger('input'); // Clear and reset search field
                            updateHiddenInput(); // Update hidden input with selected values
                        });
                    });
           
                    // Append dropdown menu to document body
                    dropdownMenu.appendTo('body');
           
                    // Event listener for input field to add new checkboxes
                    inputField.on('change', function() {
                        const values = $(this).val().split('|').map(v => v.trim()).filter(v => v !== '');
                        const currentCheckboxes = checkboxContainer.find('input[type="checkbox"]');
                        currentCheckboxes.prop('checked', false);
           
                        values.forEach(value => {
                            let matchingCheckbox = currentCheckboxes.filter((_, checkbox) => $(checkbox).val().trim() === value);
           
                            if (matchingCheckbox.length === 0) {
                                const newCheckbox = $('<input type="checkbox" name="f_poi1[]" checked>').val(value);
                                const newLabel = $('<label>').append(newCheckbox).append('<span class="ctrl-option"></span>').append(value);
                                checkboxContainer.append(newLabel).append('<br>');
                            } else {
                                matchingCheckbox.prop('checked', true);
                            }
                        });
           
                        updateCheckboxVisibility(); // Update checkbox visibility after updating
                        updateSelectedTags(); // Update selected tags display
                        updateHiddenInput(); // Update hidden input with selected values
                    });
           
                    // Event listener for search field to filter dropdown items
                    searchField.on('input', function() {
                        const searchValue = $(this).val().toLowerCase();
                        const dropdownItems = dropdownMenu.find('.dropdown-item');
           
                        dropdownItems.each(function() {
                            const text = $(this).text().toLowerCase();
                            if (text.includes(searchValue)) {
                                $(this).show();
                            } else {
                                $(this).hide();
                            }
                        });
           
                        // Toggle dropdown menu visibility based on search value
                        if (searchValue.length > 0) {
                            positionDropdown(); // Reposition dropdown if shown
                            dropdownMenu.show();
                            checkboxContainer.find('label').hide(); // Hide all checkbox labels
                        } else {
                            dropdownMenu.hide();
                            updateCheckboxVisibility(); // Update checkbox visibility based on selected items
                        }
                    });
           
                    // Event listener for clicking on search field to show all dropdown items
                    searchField.on('click', function() {
                        dropdownItems.children('.dropdown-item').show(); // Show all dropdown items
                        dropdownMenu.show(); // Show dropdown menu
                        positionDropdown(); // Reposition dropdown if shown
                        checkboxContainer.find('label').hide(); // Hide all checkbox labels
                    });
           
                    // Event listener for checkbox clicks to reorder and update inputField
                    checkboxContainer.on('change', 'input[type="checkbox"]', function() {
                        updateSelectedTags(); // Update selected tags display
                        updateCheckboxVisibility(); // Update checkbox visibility after changing
                        updateHiddenInput(); // Update hidden input with selected values
                    });
           
                    // Function to update selected tags display
                    function updateSelectedTags() {
                        selectedTagsContainer.empty();
                        const selectedValues = getSelectedValues();
                        selectedValues.forEach((value, index) => {
                            const tag = $(`<div class="selected-tag">${value} <span class="remove-tag">&times;</span></div>`);
                            selectedTagsContainer.append(tag);
           
                            // Add remove functionality
                            tag.find('.remove-tag').on('click', function() {
                                const checkbox = checkboxContainer.find(`input[type="checkbox"][value="${value}"]`);
                                checkbox.prop('checked', false).trigger('change');
                                updateSelectedTags();
                                updateCheckboxVisibility();
                                updateHiddenInput();
                            });
                        });
                    }
           
                    // Function to get selected checkbox values
                    function getSelectedValues() {
                        return checkboxContainer.find('input[type="checkbox"]:checked').map((_, checkbox) => $(checkbox).val().trim()).get();
                    }
           
                    // Function to update checkbox visibility based on selected items
                    function updateCheckboxVisibility() {
                        const selectedValues = getSelectedValues();
                        checkboxContainer.find('label').each(function() {
                            const checkbox = $(this).find('input[type="checkbox"]');
                            const value = checkbox.val().trim();
                            if (selectedValues.includes(value)) {
                                $(this).show();
                            } else {
                                $(this).hide();
                            }
                        });
                    }
           
                    // Function to reposition dropdown menu
                    function positionDropdown() {
                        const searchOffset = searchField.offset();
                        dropdownMenu.css({
                            top: searchOffset.top + searchField.outerHeight(),
                            left: searchOffset.left,
                            width: searchField.outerWidth(),
                            zIndex: 999 // Adjust z-index as needed
                        });
                    }
           
                    // Function to update hidden input with selected values
                    function updateHiddenInput() {
                        const selectedValues = getSelectedValues();
                        inputField.val(selectedValues.join('|')); // Use | for backend processing
                    }
           
                    // Close dropdown menu if clicked outside
                    $(document).on('click', function(event) {
                        if (!$(event.target).closest('.dropdown-menu').length && !$(event.target).is(searchField)) {
                            dropdownMenu.hide();
                        }
                    });
           
                    // Initialize on page load
                    updateSelectedTags(); // Update selected tags display
                    updateCheckboxVisibility(); // Update checkbox visibility
                    updateHiddenInput(); // Update hidden input with selected values
                });
            })(jQuery);
       
           
            //FOR DROPDOWN
            (function($) {
                $(document).ready(function() {
                    console.log("Custom script loaded");
           
                    const selectNames = ["f_kecamatan", "f_kab_kota", "f_provinsi", "f_owner_space_chk" , "f_promo_space_chk"];
                    let currentOpenDropdown = null; // Variable to track the currently open dropdown
           
                    selectNames.forEach(name => {
                        const dropdowns = $(`select[name="${name}"]`);
           
                        if (dropdowns.length > 0) {
                            dropdowns.each((index, dropdown) => {
                                createCustomDropdown($(dropdown));
                            });
                        }
                    });
           
                    function createCustomDropdown($dropdown) {
                        const options = $dropdown.find('option');
                        const optionsArr = Array.from(options).map(option => ({
                            value: option.value,
                            text: option.textContent,
                            selected: option.selected
                        }));
           
                        const customDropdown = $('<div class="dropdown-filter"></div>').insertAfter($dropdown);
                        const selectedOption = optionsArr.find(option => option.selected) || optionsArr[0];
                        const selected = $('<div class="dropdown-select"></div>').text(selectedOption.text).appendTo(customDropdown);
                        const menu = $('<div class="dropdown-menu"></div>').appendTo(customDropdown);
                        selected.on("click", function() {
                            // Close the currently open dropdown if it's not the same as the clicked one
                            if (currentOpenDropdown && currentOpenDropdown !== menu) {
                                currentOpenDropdown.hide();
                            }
                            toggleDropdown.call(menu);
                        });
           
                        const search = $('<input type="text" class="dropdown-menu-search" placeholder="Search...">').appendTo(menu);
                        const menuInnerWrapper = $('<div class="dropdown-menu-inner"></div>').appendTo(menu);
           
                        // Create a document fragment to batch the DOM updates
                        const fragment = document.createDocumentFragment();
                        optionsArr.forEach(option => {
                            const item = $('<div class="dropdown-menu-item"></div>')
                                .data('value', option.value)
                                .text(option.text);
           
                            if (option.selected) {
                                item.addClass('is-select');
                            }
           
                            item.on("click", setSelected.bind(item, selected, $dropdown, menu));
                            fragment.appendChild(item[0]);
                        });
           
                        menuInnerWrapper.append(fragment);
                        menuInnerWrapper.children().first().addClass("selected");
           
                        search.on("input", debounce(filterItems.bind(search, optionsArr, menuInnerWrapper), 300));
                        $(document).on("click", closeIfClickedOutside.bind(customDropdown, menu));
                        $dropdown.hide();
                    }
           
                    function toggleDropdown() {
                        if (this.is(':visible')) {
                            this.hide();
                            currentOpenDropdown = null;
                        } else {
                            this.show();
                            this.find("input").focus();
                            currentOpenDropdown = this; // Track the currently open dropdown
                        }
                    }
           
                    function setSelected(selected, $dropdown, menu) {
                        const value = this.data('value');
                        const label = this.text();
           
                        selected.text(label);
                        $dropdown.val(value).change();
                        menu.hide();
                        currentOpenDropdown = null; // Clear the currently open dropdown
           
                        menu.find("input").val('');
                        menu.find('.dropdown-menu-inner div').each(function() {
                            $(this).show();
                        });
           
                        menu.find('.is-select').removeClass('is-select');
                        this.addClass('is-select');
                    }
           
                    function filterItems(itemsArr, menuInnerWrapper) {
                        const value = this.val().toLowerCase();
                        menuInnerWrapper.children().each(function() {
                            const itemText = $(this).text().toLowerCase();
                            $(this).toggle(itemText.includes(value));
                        });
                    }
           
                    function closeIfClickedOutside(menu, e) {
                        if (!$(e.target).closest(".dropdown-filter").length && menu.is(':visible')) {
                            menu.hide();
                            currentOpenDropdown = null; // Clear the currently open dropdown
                        }
                    }
           
                    function debounce(func, wait) {
                        let timeout;
                        return function(...args) {
                            clearTimeout(timeout);
                            timeout = setTimeout(() => func.apply(this, args), wait);
                        };
                    }
                });
            })(jQuery);

        </cms:script>
        <cms:style>
        .dropdown-menu,.dropdown-menu-search,.dropdown-select{width:100%;box-sizing:border-box}.dropdown-menu-item,.dropdown-select{cursor:pointer;box-sizing:border-box}.dropdown-filter{position:relative;display:inline-block;width:100%;min-width:300px}.dropdown-menu input[type=text]{border:0;border-bottom:1px solid #ccc;border-radius:0}.dropdown-select{background:#fff;border:1px solid #ccc;padding:10px;border-radius:4px;box-shadow:0 1px 3px rgba(0,0,0,.1)}.dropdown-menu{display:none;position:absolute;background-color:#fff;border:1px solid #ccc;max-height:200px;overflow-y:auto;z-index:1000;box-shadow:0 4px 6px rgba(0,0,0,.1);border-radius:4px}.dropdown-menu-search{padding:10px;border-bottom:1px solid #ccc;outline:0;border-top-left-radius:4px;border-top-right-radius:4px}.dropdown-menu-inner{padding:0;margin:0}.dropdown-menu-item{padding:10px;border-bottom:1px solid #eee}.dropdown-menu-item:last-child{border-bottom:none}.dropdown-menu-item.is-select,.dropdown-menu-item:hover{background-color:#f0f0f0}select[name=kab_kota]{display:none}.admin-panel .dropdown-filter{width:auto;max-width:300px}.admin-panel .dropdown-menu-item,.admin-panel .dropdown-menu-search,.admin-panel .dropdown-select{font-size:14px}
        /* Hide the input field when items are selected */
        #categoryInput {
            display: none;
        }
       
        #searchInput{width:100%}
       
        /* Style for selected tags */
        .selected-tags {
            margin-top: 10px;
            display: flex;
            flex-wrap: wrap;
        }
       
        .selected-tag {
            background-color: #007bff;
            color: #fff;
            padding: 4px 8px;
            margin-right: 5px;
            margin-bottom: 5px;
            border-radius: 4px;
            cursor: pointer;
            font-size:14px;
        }
       
        .selected-tag:hover {
            background-color: #0056b3;
        }
       
        /* Style for dropdown menu */
        .dropdown-menu {
            position: absolute;
            background-color: #f9f9f9;
            border: 1px solid #ccc;
            box-shadow: 0 4px 8px rgba(0,0,0,0.1);
            z-index: 999;
            display: none;
        }
       
        .dropdown-select {
            /*padding: 8px;
            background-color: #007bff;
            color: #fff;*/
            cursor: pointer;
        }
       
        .dropdown-items {
            max-height: 200px;
            overflow-y: auto;
            overflow-x: hidden;
        }
       
        .dropdown-item {
            padding: 8px;
            cursor: pointer;
        }
       
        .dropdown-item:hover {
            background-color: #e9ecef;
        }
        /* Hide checkboxes when dropdown menu is active */
        #k_element_poi1 .ctrls-checkbox  {
            display: none !important;
            visibility:hidden;
            opacity:0;
        }
        </cms:style>
    </cms:config_form_view>

How to:
1. Add the script to <cms:template> couchcms using <cms:config_form_view> include with styling css
2. Adjust the necessary class/id or name of your template and save.
3. Visit your frontend clonable template (for registering the template)
4. Finish, if all the requirements correct, your filter search will be appear on the admin panel.

Don't forget to adjust the script based on Class or ID on your admin template e.g:

Please adjust this part: id/class of your dropdown/checkbox template (#k_element_poi1)
Code: Select all
//For Checkbox
// Find the checkbox container
const checkboxContainer = $('#k_element_poi1 .ctrls-checkbox');

// For Dropdowns
const selectNames = ["f_kecamatan", "f_kab_kota", "f_provinsi", "f_owner_space_chk" , "f_promo_space_chk"];
let currentOpenDropdown = null; // Variable to track the currently open dropdown

And also this part: name of your checkbox (name="f_poi1[]"):
Code: Select all
const inputField = $('<input type="hidden" id="categoryInput" name="f_poi1[]" value="">'); // Hidden input to store selected values
const newCheckbox = $('<input type="checkbox" name="f_poi1[]" checked>').val(value);

Note:
Please adjust: f_[your-dropdown or checkbox id/class]

Here's the working screenshot:

Filtered Checkbox with Multiple value:
Image

Filtered Dropdown:
Image