Home > database >  How can I create functionality that allows the user to filter multiple times in JavaScript?
How can I create functionality that allows the user to filter multiple times in JavaScript?

Time:05-27

I have been working on a website that displays projects completed by students for their Senior Project. I wanted to be able to sort by project category to make it easier for the user. I added that functionality in and everything works well. I then decided since there are going to be multiple years worth of Senior projects on my website, I want to filter by year as well. However, I can't just add more buttons for years. For example, if I filtered by class of 2022, I wouldn't be able to filter by category within the class of 2022. More specifically, when I press 2022, it shows all of the students in that class. Then, if I press Creative Project for example, it goes back to showing every single Creative Project regardless of year instead of from the class of 2022. My initial thought process was to just make another function and div for the grad year buttons. However, that does not change anything. Here is my JavaScript code:

function filterProject(value){
    let buttons = document.querySelectorAll(".button-value");
    buttons.forEach((button) => {
        if(value.toUpperCase() == button.innerText.toUpperCase()){
            button.classList.add("active");
        }else{
            button.classList.remove("active");
        }
    });

    let elements = document.querySelectorAll(".card");
    elements.forEach((element) => {
        if(value == "all"){
            element.classList.remove("hide");
        }
        else{
            //having a space messes it up, make it _
            if(element.classList.contains(value.replace(" ", "_"))){
                element.classList.remove("hide");
            }
            else{
                element.classList.add("hide");
            }
        }
    });
}

function filterProject2(value){
    let buttons = document.querySelectorAll(".grad-button");
    buttons.forEach((button) => {
        if(value.toUpperCase() == button.innerText.toUpperCase()){
            button.classList.add("active");
        }else{
            button.classList.remove("active");
        }
    });

    let elements = document.querySelectorAll(".card");
    elements.forEach((element) => {
        if(value == "All Years"){
            element.classList.remove("hide");
        }
        else{
            //having a space messes it up, make it _
            if(element.classList.contains(value.replace(" ", "_"))){
                element.classList.remove("hide");
            }
            else{
                element.classList.add("hide");
            }
        }
    });
}

Here is the relevant HTML code as well:

<div id ="buttons">
        <button class = "button-value" onclick="filterProject('all')">All</button>
        <button class = "button-value" onclick="filterProject('Creative Project')">Creative Project</button>
        <button class = "button-value" onclick="filterProject('Developing Voice')">Developing Voice</button>
        <button class = "button-value" onclick="filterProject('Interdisciplinary Fusion')">Interdisciplinary Fusion</button>
        <button class = "button-value" onclick="filterProject('Personal Writing')">Personal Writing</button>
        <button class = "button-value" onclick="filterProject('Curriculum Designer')">Curriculum Designer</button>
        <button class = "button-value" onclick="filterProject('Internship')">Internship</button>
    </div>
    <div id ="gradbuttons">
        <button class = "grad-button" onclick="filterProject2('All Years')">All Years</button>
        <button class = "grad-button" onclick="filterProject2('2021')">2021</button>
        <button class = "grad-button" onclick="filterProject2('2022')">2022</button>
    </div>

I know that I could just add another page that separates the projects by grad year and has different buttons for each year, but I want to use JavaScript and make the website cleaner. Any suggestions will help. Thanks!

CodePudding user response:

I would use an object var filters = { "category": "", "year": "" }; as a state variable to store the current filter options. Since you do similar logic in both of your filter functions, I would combine them into a single function that accepts an additional parameter filterType which is either "category" or "year". Then in your filtering logic, you can update the current filter for the appropriate filter type and make sure every condition in your filters is met.

CodePudding user response:

Instead of using a unique class to hide elements, you can use two different classes, for example category-hidden and year-hidden.

Inside category filter:

button.classList.add('category-hidden')

Inside year filter:

button.classList.add('year-hidden')

Then, in your css, you hide the elements that have both classes.

<style>
 .category-hidden .year-hidden {
    display: none;
  }
</style>

EDIT

I've just realized that this approach won't work if you select only one filter. So, you'll need to add classes to the elements' container indicating which filters are currently active. For example, if you activate the year filter add the class year-filter-active.

<div id="container" >
  ...
  elements
  ...
</div>

And in your css put the following rules:

<style>
  div.year-filter-active .year-hidden, div.category-filter-active .category-hidden {
    display: none;
  }
</style>
  • Related