Creating a custom filter

I am working on creating a filter and I could use some assistance with making minimal changes to my code. I am confident that there is a practical solution for what I am trying to achieve and would appreciate any corrections or suggestions.

Button01's function is to hide/show all elements with the class name filter01,
Button02's function is to hide/show all elements with the class name filter02,
Both buttons have control over ElementX.
My goal is to have ElementX remain hidden until the button is clicked again, even if the other button is clicked in between.

HTML:

<div class="button01" onclick="filter01()">Filter 01</div>
<div class="button02" onclick="filter02()">Filter 02</div>

<div class="filter01 filter02">ElementX</div></a>

JS:

function filter01() {
    var i;
    var filter = document.getElementsByClassName("filter01");
    for (i=0; i<filter.length; i++) {
        if (filter[i].style.display) {filter[i].style.display = null; button01.style.color = null;}
        else {filter[i].style.display = "none"; button01.style.color = "rgb(200,200,200)}
    }
}
function filter02() {
    var i;
    var filter = document.getElementsByClassName("filter02");
    for (i=0; i<filter.length; i++) {
        if (filter[i].style.display) {filter[i].style.display = null; button02.style.color = null;}
        else {filter[i].style.display = "none"; button.style.color = "rgb(200,200,200)}
    }
}

Answer №1

To optimize the event organization, consider moving it outside of the HTML structure. Utilize data attributes on buttons to determine their corresponding hidden items. Consolidate button click handling into a single function that interprets the data attribute.

Create a Set containing selectors for items to be hidden and toggle these elements within the click handler function.

For adding a selector to hide, target the elements and hide them accordingly. When removing a selector from the set, display the elements again before selectively hiding those still selected within the set.

Check out the code snippet below:

for (let button of document.querySelectorAll(".filterbutton")) {
    button.addEventListener("click", filter);
}

let filters = new Set;

function toggleDisplay(selector, display) {
    let elems = document.querySelectorAll(selector);
    for (let elem of elems) {
        elem.style.display = display;
    }
}

function filter() {
    let filterSelector = this.dataset.filter;
    let show = filters.delete(filterSelector);
    this.style.color = show ? "" : "rgb(200,200,200)";
    if (!show) {
        filters.add(filterSelector); // toggle this filter
    } else {
        toggleDisplay(filterSelector, "");
    }
    if (filters.size) {
        toggleDisplay([...filters].join(","), "none");
    }
}
.filterbutton { 
    border: 1px solid;
    display: inline-block;
    background: lightblue;
    padding: 5px;
    cursor: pointer }
<div class="filterbutton" data-filter=".filter01">Filter 01</div>
<div class="filterbutton" data-filter=".filter02">Filter 02</div>
<div class="filterbutton" data-filter=".filter03">Filter 03</div>

<div class="filter01 filter02 filter03">This element has filter01, filter02 and filter03</div>
<div class="filter01 filter02">This element has filter01 and filter02</div>
<div class="filter01 filter03">This element has filter01 and filter03</div>
<div class="filter02 filter03">This element has filter02 and filter03</div>
<div class="filter01">This element has filter01 only</div>
<div class="filter02">This element has filter02 only</div>
<div class="filter03">This element has filter03 only</div>

Answer №2

A modified version of trincots code that utilizes CSS filtering instead of JavaScript.

for (let button of document.querySelectorAll(".filterbutton")) {
  button.addEventListener("click", filter);
}

function filter() {
  document.querySelector(".container").classList.toggle(this.dataset.filter);
}
.filterbutton {
  border: 1px solid;
  display: inline-block;
  background: lightblue;
  padding: 5px;
  cursor: pointer
}

.container.filter01 .filter01,
.container.filter02 .filter02,
.container.filter03 .filter03 {
  display: none;
}

.container.filter01 .filterbutton[data-filter=filter01],
.container.filter02 .filterbutton[data-filter=filter02],
.container.filter03 .filterbutton[data-filter=filter03] {
  color: rgb(200, 200, 200);
}
<div class="container">
  <div class="filterbutton" data-filter="filter01">Filter 01</div>
  <div class="filterbutton" data-filter="filter02">Filter 02</div>
  <div class="filterbutton" data-filter="filter03">Filter 03</div>

  <div class="filter01 filter02 filter03">This element has filter01, filter02 and filter03</div>
  <div class="filter01 filter02">This element has filter01 and filter02</div>
  <div class="filter01 filter03">This element has filter01 and filter03</div>
  <div class="filter02 filter03">This element has filter02 and filter03</div>
  <div class="filter01">This element has filter01 only</div>
  <div class="filter02">This element has filter02 only</div>
  <div class="filter03">This element has filter03 only</div>
</div>

Answer №3

Is this the solution you were looking for? I utilized the window.getComputedStyle() method to access the pointerEvents property of the adjacent button in order to toggle it based on its current value. The same logic applies to the other button as well. Take a look and test it out.

function toggleFilter01() {
    var i;
    var filters = document.getElementsByClassName("filter01");
    for (i=0; i<filters.length; i++) {
        if (filters[i].style.display) {
            filters[i].style.display = null; 
            filters[i].style.color = null;
        } else {
            filters[i].style.display = "none"; 
            filters[i].style.color = "rgb(200,200,200)";
        }
    }
    let buttons = document.getElementsByClassName("button02");
    let styles = window.getComputedStyle(buttons[0]);
    if(styles.pointerEvents === 'auto') {
        buttons[0].style.pointerEvents = 'none';
    } else if(styles.pointerEvents === 'none') {
        buttons[0].style.pointerEvents = 'auto';
    }
 
}

function toggleFilter02() {
    var i;
    var filters = document.getElementsByClassName("filter02");
    for (i=0; i<filters.length; i++) {
        if (filters[i].style.display) {
            filters[i].style.display = null; 
            filters[i].style.color = null;
        }
        else {
            filters[i].style.display = "none"; 
            filters[i].style.color = "rgb(200,200,200)"
        }
    }

    let buttons = document.getElementsByClassName("button01");
    let styles = window.getComputedStyle(buttons[0]);
    if(styles.pointerEvents === 'auto') {
        buttons[0].style.pointerEvents = 'none';
    } else if(styles.pointerEvents === 'none') {
        buttons[0].style.pointerEvents = 'auto';
    }
}
 <div class="button01" onclick="toggleFilter01()">Toggle Filter 01</div>
    <div class="button02" onclick="toggleFilter02()">Toggle Filter 02</div>

    <div class="filter01 filter02">ElementX</div></a>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Issue with Flask app's template rendering when trying to search for a book

Currently, I am working on a Flask web application that has the functionality for users to search for books and view detailed information about them. However, an obstacle I am encountering is that the form does not get sent to the specified URL. Below is ...

What is the best way to prevent right floated DIVs from interfering with each other's positioning, specifically within a specified space?

Despite feeling like this question may have been asked numerous times before, I've searched high and low for an answer to no avail - both here and on Google. My HTML page has a maximum width that limits the size of the content. This content includes ...

Error: Unable to assign value to property 'src' because it is null

Currently, I am attempting to display a .docx file preview using react-file-viewer <FileViewer fileType={'docx'} filePath={this.state.file} //the path of the url data is stored in this.state.file id="output-frame-id" ...

Converting Strings into Variable Names in Vue.js: A Step-by-Step Guide

Hi everyone, I was wondering if there's a way to convert a string into a variable name. For example, I want to convert "minXLabel" to minXLabel so that I can use it within span tags like this: <span>{{minXLabel}</span>. I current ...

Safari does not display disabled input fields correctly

I have designed a simple angular-material form with various inputs that are organized using angular flex-layout. The form displays correctly in all browsers except for Safari on iOS devices. The problem in Safari arises when loading a form that contains d ...

Ways to rearrange an object with javascript

I am looking to restructure my object by removing a nesting. How can I achieve this using JavaScript? Actual: var a = [ { clickedEvents: { 'event-element': 'a', 'event-description': & ...

Ways to both retrieve a variable and clear it simultaneously

In my validator library, there are functions that sanitize and validate strings. These validator functions add error messages to an array called "errors" for each invalid input they encounter. After completing validation on all inputs, I collect the error ...

Resize the image to fit the dimensions of a div, but unfortunately, the overflow: hidden property is not effective in this

I'm looking to set up an image gallery using the Bootstrap grid layout. The gallery should span 100% width and consist of two grids in a row, each containing one picture. I want the height of the second picture to match that of the first, with croppin ...

Issue with React-Native Picker - managing item selection

Encountering an issue with the Picker picker component. There is an array of currencies as strings. Using the Picker to select items from this array, and have a function included in the onValueChange prop in Picker. The problem arises when trying to select ...

Issues with the parallax zooming out effect

Delving into the world of parallax effects, I'm on a quest to achieve a captivating zoom-out effect while scrolling. However, I'm encountering an issue where the image shrinks beyond the browser width and the div's height. In the example pr ...

Issue with HTML 5 audio player not functioning correctly in Chrome browsers when trying to forward or rewind playback

I am encountering an issue with running the HTML5 audio player in Chrome. It works perfectly fine in IE 9+ and Firefox. I have implemented JavaScript functions for forwarding and rewinding the audio player on F7 and F8 key press. These functions work seaml ...

Embed Text inside an HTML Canvas

As someone who is relatively new to working with html canvas, I am having a bit of trouble when it comes to containing text within the canvas area. Specifically, I am pulling text from a textarea and displaying it on the canvas, but it seems to stay as one ...

What is the best way to manage user sessions for the Logout button in Next.js, ensuring it is rendered correctly within the Navbar components?

I have successfully implemented these AuthButtons on both the server and client sides: Client 'use client'; import { Session, createClientComponentClient } from '@supabase/auth-helpers-nextjs'; import Link from 'next/link'; ...

Incorporating an npm reference into a personalized node within Node-RED

As a novice in both the NodeRed and NodeJs/npm realms, I am embarking on the journey of creating a custom node for the first time. Despite my efforts to follow the official documentation on Creating your first node, I seem to have hit a roadblock. Everyth ...

What is the best way to transfer an object between views in Django?

Background/Issue In my web application, I have a job that involves running a python script to log into LinkedIn. This script launches headless chromium, navigates to the LinkedIn login page, and logs in with the proper credentials. However, sometimes Link ...

React function does not provide a return value

In my function, I am calculating the current sum of elements. Within my Api, there is a method called Getcoin that works correctly when I log each element during the foreach cycle. However, I am not getting any results in the return statement or console.lo ...

Find a way to avoid Google's site-blocking measures

Currently developing a website. I am looking into restricting access to only logged-in users on the site. How can I parse the pages in a way that Google does not block the site? ...

Mastering the art of resolving a dynamic collection of promises with '$.all'

Imagine having 3 promises and passing them to $q.all. This results in a new promise that resolves when the 3 promises are resolved. But what if I realize before the 3 promises resolve that I also want a 4th promise to be resolved? Can this be achieved? I ...

There seems to be an issue with loading data for the grid from the JSON

I need some help with creating a fiddle that loads data from a json file. I'm not sure why the data is not loading properly. You can view my fiddle here: Fiddle This is my code for the data store: Ext.create('Ext.data.Store', { storeI ...

Adjust the stacking order of bars in a vertical chart and exclude negative values with Vega-Lite

I am utilizing this chart as a guide for my current project Explore Vega Editor here https://i.sstatic.net/VGOee.png Is there a way to rearrange the order of the 'Measure' while keeping 'Measure 1' at the top, disregarding its negati ...