Is there a way I can get these 2 dropdowns to "work together" to filter the table

87 views Asked by At

Hi I've got a table that I wanted to filter using a custom JavaScript dropdown filter function. Separately they work perfectly, but the issue comes in when I try to use both at the same time to filter the table contents. Here is my JavaScript code:

function searchUserName(input, tableName) {
        dropDown(input, tableName, 0);
    }

    function searchSupervisorName(input, tableName) {
        dropDown(input, tableName, 1);
    }

    var dropdown0 = false;
    var dropdown1 = false;

    function dropDown(input, tableName, colPos) {
    var table = document.getElementById(tableName);
    var tr = table.getElementsByTagName("tr");
    var userDropdown;
    var userNamesArray = [];

    if (colPos == 0) {
        if (!dropdown0) {
            createDropdown();
            dropdown0 = true;
        }
    }
    else if (colPos == 1) {
        if (!dropdown1) {
            createDropdown();
            dropdown1 = true;
        }
    }

    function createDropdown() {
        if (!userDropdown) {
            userDropdown = document.createElement("div");
            userDropdown.id = "userDropdown";
            userDropdown.className = "dropdown";

            userNamesArray = Array.from(tr).map(row => {
                var td = row.getElementsByTagName("td")[colPos];
                if (td) {
                    return td.textContent.trim();
                }
            }).filter(Boolean);

            // Sort the user names alphabetically
            userNamesArray.sort((a, b) => a.localeCompare(b));

            var userNamesSet = new Set(userNamesArray);

            // Add "Deselect All" option
            var deselectAllContainer = createOptionContainer("Deselect All");
            userDropdown.appendChild(deselectAllContainer);

            // Add separator line after "Deselect All"
            var separator = document.createElement("hr");
            userDropdown.appendChild(separator);

            userNamesSet.forEach(name => {
                var optionContainer = createOptionContainer(name);
                userDropdown.appendChild(optionContainer);
            });

            input.parentNode.insertBefore(userDropdown, input.nextSibling);

        } else {
            userDropdown.style.display = '';
        }
        removeOptionFromDropdown("null, null");
    }

    function removeOptionFromDropdown(optionText) {
        if (userDropdown) {
            Array.from(userDropdown.children).forEach(optionContainer => {
                var optionContainerText = optionContainer.textContent.trim();
                if (optionContainerText === optionText) {
                    userDropdown.removeChild(optionContainer);
                }
            });
        }
    }

    function createOptionContainer(name) {
        var optionContainer = document.createElement("label");
        optionContainer.className = "option-container";

        if (name === "Deselect All") {
            var checkbox = document.createElement("input");
            checkbox.type = "checkbox";
            checkbox.value = name;
            optionContainer.appendChild(checkbox);
            optionContainer.classList.add("deselect-option");
        } else {
            var checkbox = document.createElement("input");
            checkbox.type = "checkbox";
            checkbox.value = name;
            optionContainer.appendChild(checkbox);
        }

        var optionText = document.createTextNode(name);
        optionContainer.appendChild(optionText);

        return optionContainer;
    }

    //showing dropdown onclick event
    function showDropdown() {
        if (userDropdown) {
            userDropdown.style.display = 'block';
        }
    }

    function moveSelectedOptionsToTop() {
        var deselectAllContainer = userDropdown.querySelector('input[value="Deselect All"]').parentNode;

        var selectedOptions = Array.from(userDropdown.getElementsByClassName("option-container"))
            .filter(optionContainer => {
                var checkbox = optionContainer.querySelector('input[type="checkbox"]');
                return checkbox.checked && checkbox.value !== "Deselect All";
            });

        if (selectedOptions.length > 0) {
            // Sort selected options alphabetically
            selectedOptions.sort((a, b) => {
                var textA = a.textContent.trim();
                var textB = b.textContent.trim();
                return textB.localeCompare(textA);
            });

            // Move all selected options to the top
            selectedOptions.forEach(optionContainer => {
                userDropdown.insertBefore(optionContainer, userDropdown.firstChild.nextSibling); // Insert after "Deselect All"
            });


        } else {

            // If no options are selected, move "Deselect All" to the top
            userDropdown.insertBefore(deselectAllContainer, userDropdown.firstChild.nextSibling);


            var allOptions = Array.from(userDropdown.getElementsByClassName("option-container"));

            allOptions = allOptions.filter(optionContainer => {
                var checkbox = optionContainer.querySelector('input[type="checkbox"]');
                return checkbox.value !== "Deselect All";
            });

            allOptions.sort((a, b) => {
                var textA = a.textContent.trim();
                var textB = b.textContent.trim();
                return textB.localeCompare(textA);
            });

            // Move all options below "Deselect All"
            allOptions.forEach(optionContainer => {
                userDropdown.insertBefore(optionContainer, deselectAllContainer.nextSibling);
            });
        }
    }

    function filterTable() {
        var visibleRows = [];
        var searchValue = input.value.trim().toUpperCase();
        var selectedusers = Array.from(userDropdown.getElementsByClassName("option-container"))
            .filter(optionContainer => {
                var checkbox = optionContainer.querySelector('input[type="checkbox"]');
                return checkbox.checked && checkbox.value !== "Deselect All";
            })
            .map(optionContainer => optionContainer.textContent.trim().toUpperCase());

        // Include all options if "Deselect All" is checked
        var deselectAllCheckbox = userDropdown.querySelector('input[value="Deselect All"]');
        if (deselectAllCheckbox && deselectAllCheckbox.checked) {
            // Uncheck all other checkboxes and remove selected options
            Array.from(userDropdown.getElementsByClassName("option-container")).forEach(function (optionContainer) {
                var checkbox = optionContainer.querySelector('input[type="checkbox"]');
                checkbox.checked = false;
            });

            var deselectAllContainer = userDropdown.querySelector('input[value="Deselect All"]').parentNode;
            userDropdown.removeChild(deselectAllContainer);
            userDropdown.insertBefore(deselectAllContainer, userDropdown.firstChild.nextSibling); // Insert after the separator line

            selectedusers = [];
        }

        // Move "Deselect All" to the top after checking selected options
        moveSelectedOptionsToTop();

        Array.from(tr).forEach(function (row) {
            var td = row.getElementsByTagName("td")[colPos];
            if (td) {
                var userName = td.textContent.trim().toUpperCase();

                var matchesSearch = userName.includes(searchValue);

                var isInSelectedusers = selectedusers.length === 0 || selectedusers.includes(userName);

                var displayRow = matchesSearch && isInSelectedusers;
                row.style.display = displayRow ? "" : "none";

                var hasVisibleRowClass = row.classList.contains('visible-row-dp1');

                    if (colPos == 0) {
                        if (displayRow && hasVisibleRowClass) {
                            row.classList.add('visible-row-dp0');
                            visibleRows.push(row);
                        } else {
                            row.classList.remove('visible-row-dp0');
                        }
                    }
                    else if (colPos == 1) {
                        if (displayRow) {
                            row.classList.add('visible-row-dp1');
                            visibleRows.push(row);
                        } else {
                            row.classList.remove('visible-row-dp1');
                        }
                    }
                
                
                applyEvenOddStyling(visibleRows);
            }
        });

// Display "No matching records found" message if no visible rows
var dataTable = $('#maintable').DataTable();
if (visibleRows.length === 0) {
    dataTable.rows().nodes().to$().hide(); // Hide all rows
    dataTable.draw(); // Redraw the DataTable
    $('#maintable tbody').append('<tr class="no-records"><td colspan="colspan">No matching records found</td></tr>'); // Display no records message
} else {
    // If there are visible rows, redraw the DataTable and remove the no records message if present
    dataTable.rows().nodes().to$().show(); // Show all rows
    $('#maintable tbody .no-records').remove(); // Remove no records message if present
    dataTable.draw();
}



        Array.from(userDropdown.getElementsByClassName("option-container")).forEach(function (optionContainer) {
            var optionText = optionContainer.textContent.trim().toUpperCase();
            var displayOption = optionText.includes(searchValue);

            optionContainer.style.display = displayOption ? "block" : "none";
        });

        if (colPos == 1) {
            var SuperVisorSearchbar = document.getElementById("searchSupervisorInput");
            if (selectedusers.length > 0) {
                SuperVisorSearchbar.classList.add("selected-search-bar");
            } else {
                SuperVisorSearchbar.classList.remove("selected-search-bar");
            }
        } else if (colPos == 0) {
            var UserSearchbar = document.getElementById("searchInput");
            if (selectedusers.length > 0) {
                UserSearchbar.classList.add("selected-search-bar");
            } else {
                UserSearchbar.classList.remove("selected-search-bar");
            }
        }
    }

    function applyEvenOddStyling(rows) {
        rows.forEach(function (row, index) {
            if (index % 2 === 0) {
                row.classList.add('odd-row');
                row.classList.remove('even-row');
            } else {
                row.classList.add('even-row');
                row.classList.remove('odd-row');
            }
        });
    }

    userDropdown.addEventListener('change', function () {
        filterTable();
        moveSelectedOptionsToTop();
    });

    input.addEventListener("keyup", function () {
        filterTable();
    });

    input.addEventListener("click", function () {
        showDropdown();
    });

    document.addEventListener("click", function (event) {
        if (userDropdown && !userDropdown.contains(event.target) && event.target !== input) {
            userDropdown.style.display = 'none';
        }
    });

    }

Since there can be multiple rows of a single supervisor, the supervisor dropdown will filter the table and the rows that are visible will be dynamically picked up by the username dropdown. Then, I can filter the username. The options in both dropdowns would also be multiselect and the table would be filtered accordingly. I also have an option open where the User can type out and filter either dropdown options and the separate columns they are in.

I will admit I used a lot of AI to help fix some bugs I had, so I might not be able to explain reasoning for everything but I'll try my best if you have any questions.

1

There are 1 answers

0
ASP On

I haven't read through all the filtering logic. I also don't know what the table data is.

To filter an array, you could use the filter method on the array object.

Say you have an array of students;

let students = [
    {name: 'std1' , age: 23, sex: 'male'},
    {name: 'std2' , age: 29, sex: 'male'},
    {name: 'std3' , age: 25, sex: 'female'},
]

To get only male students, you would filter the students array like so:

let maleStudents = students.filter((student) => student.sex == "male")

To filter the male students further say only male students less than the age of 26:

let maleStudentsBelow26 = maleStudents.filter((maleStudent) => maleStudent.age < 26)

Or you could apply the sex and age filter at once on the students array:

let maleStudentsBelow26 = students.filter((student) => student.sex == 'male' && student.age < 26)

You could then display the filtered array in your table.