filtering multiple items using checkboxes in vanilla JavaScript

Currently, I am facing a challenge in creating filters for a dynamically generated table. I have implemented checkboxes as part of my solution, but I seem to be stuck at this point.

Despite conducting extensive research, I have been unable to find a suitable resolution to my problem.

My main objective is to filter the data displayed in the table based on the selected checkboxes. Unfortunately, I am struggling with the concept of connecting these checkboxes to the corresponding table rows that need to be filtered based on user input.

I attempted using event.target.getAttribute('data-filter'), however, I encountered difficulties filtering the array to align with the event triggered by the checkbox selection.

Is there a way to achieve this functionality using only pure JavaScript?

Below is the snippet of code I've been working on:

let array= [
    {
        "name": "John",
        "surname": "XYZ",
        "department": "IT"
    },
    {
        "name": "John",
        "surname": "XYZ",
        "department": "accountancy"
    },

]

function generateTableHead(table, data) {
    let thead = table.createTHead();
    let row = thead.insertRow();
    for (let key of data) {
        let th = document.createElement("th");
        let text = document.createTextNode(key);
        th.appendChild(text);
        row.appendChild(th);
    }
}

function generateTable(table, data) {
    for (let element of data) {
        let row = table.insertRow();
        for (key in element) {
            let cell = row.insertCell();
            let text = document.createTextNode(element[key]);
            cell.appendChild(text);
        }
    }
}

let table = document.querySelector("table");
let data = Object.keys(array[0]);

generateTable(table, array);
generateTableHead(table, data);



// FILTER: checkboxes 

const getDepartments = array.map(function (element) {
    return [element.department].join('');
});

let departmentFilters = [...new Set(getDepartments)];


let createFilters = function () {
    box = document.querySelector('#filterType');
    box.innerHTML = departmentFilters.map(function (department) {
        let checkboxes = '<label>' +
            '<input type="checkbox" data-filter="' + department + '" checked>' + department +
            '</label>';
        return checkboxes;
    }).join('');
};

Answer №1

Explanation of modifications highlighted during demonstration

let list = [{
    "name": "Jane",
    "surname": "Doe",
    "department": "IT"
  },
  {
    "name": "John",
    "surname": "Doe",
    "department": "Finance"
  },
  {
    "name": "Darth",
    "surname": "Vader",
    "department": "Sith Lord"
  }
];

const table = document.querySelector("table");
const filters = document.querySelector('#filterType');

function createTable(table, list) {
  let row, cell;
  list.forEach(function(obj) {
    row = table.insertRow();
    
    for (let [key, value] of Object.entries(obj)) {
      cell = row.insertCell()
      let text = document.createTextNode(value);
      cell.appendChild(text);
      cell.dataset.key = value;
    }
  });
  
  let keys = Object.keys(list[0]);
  return setTableHeaders(table, keys);
}

function setTableHeaders(table, keys) {
  let thead = table.createTHead();
  let row = thead.insertRow();
  for (let key of keys) {
    let th = document.createElement("th");
    let text = document.createTextNode(key);
    th.appendChild(text);
    row.appendChild(th);
  }
}

function getKey(target, list) {
  let keyArray = list.map(function(obj) {
    for (let [key, value] of Object.entries(obj)) {
      if (key === target) {
        return value;
      }
    }
  });
  
  filters.insertAdjacentHTML('beforeend', `<fieldset id='${target}'><legend>${target}</legend></fieldset>`)
  createFilters(keyArray);
}

function createFilters(array) {
  let set = Array.from(new Set([...array]));
  set.forEach(function(name) {
    let chk = `<label><input type="checkbox" data-filter="${name}" checked>${name}</label>`;
    filters.lastElementChild.insertAdjacentHTML('beforeend', chk);
  });
};

function filterKey(e) {
  const tgt = e.target;
  let name = tgt.dataset.filter;
  let keys = document.querySelectorAll(`[data-key="${name}"]`);
  for (let cell of keys) {
    if (tgt.checked) {
      cell.closest('tr').classList.remove('off');
    } else {
      cell.closest('tr').classList.add('off');
    }
  }
}

createTable(table, list);

// Uncomment any or all 
getKey('department', list);

filters.onchange = filterKey;
.off {
  visibility: collapse;
}
<form id='filterType'></form>
<table></table>

Answer №2

Here is a possible solution:

let sampleData = [ 
  { 
    "name": "John", 
    "surname": "Doe", 
    "department": "HR" 
  }, 
  { 
    "name": "Jane", 
    "surname": "Smith", 
    "department": "Marketing" 
  }, 
  { 
    "name": "Michael", 
    "surname": "Johnson", 
    "department": "Finance"
   } 
];
  
const tableElement = document.querySelector("#employeeTable");
const tableHeaders = Object.keys(sampleData[0]);
let departmentFilters = [];

function createTableHeader(table, data) {
  const headerRow = table.createTHead().insertRow();
  for (const key of data) {
    const formattedKey = key.charAt(0).toUpperCase() + key.slice(1);
    const th = document.createElement("th");
    th.appendChild(document.createTextNode(formattedKey));
    headerRow.appendChild(th);
  }
}

function generateEmployeeTable(table, data) {
  for (let i = table.rows.length - 1; i > 0; i--) {
    table.deleteRow(i);
  }

  for (const obj of data) {
    const row = table.insertRow();
    for (const key in obj) {
      const cell = row.insertCell();
      cell.appendChild(document.createTextNode(obj[key]));
    }
  }
}

function handleDepartmentFilterChange(event) {
  const selectedDepartment = event.currentTarget.value;
  let filteredData = [];

  if (this.checked) {
    departmentFilters.push(selectedDepartment); 
  } else {
    departmentFilters = departmentFilters.filter(filter => filter !== selectedDepartment);
  }
  
  if (departmentFilters.length === 0) {
    filteredData = sampleData;
    generateEmployeeTable(tableElement, filteredData);
    return;
  }
  
  filteredData = sampleData.filter(entry => departmentFilters.includes(entry.department));
  generateEmployeeTable(tableElement, filteredData);
}

generateEmployeeTable(tableElement, sampleData);
createTableHeader(tableElement, tableHeaders);

document.querySelectorAll('[name=deptFilter]')
  .forEach(departmentCheckbox => departmentCheckbox.addEventListener('change', handleDepartmentFilterChange));
<table id="employeeTable">
</table>

<br>
<label>Filter by department: 
  <br>
  <span> 
    <input name="deptFilter" type="checkbox" value ="HR"/> HR
    <input name="deptFilter" type="checkbox" value ="Marketing" /> Marketing
    <input name="deptFilter" type="checkbox" value ="Finance" /> Finance
  </span>
</label>

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

Is there a way to identify which specific item in a watched array has been altered in VueJS?

Imagine having an array declared in the data section like this: data() { return { myData : [{foo:2, bar:3},{foo:4,bar:5}] } } If you want to identify when the bar property of the second element changes, what should your watch function look li ...

What is the best way to define dynamic array fields within a C++ class structure?

As a beginner in C++, I am looking to create a class with 5 arrays as fields. The size of these arrays should be initialized dynamically. Although I have written some code, it is currently not functioning correctly: class ParsedData { public: int g ...

Transform the v-model value from numerical to textual representation

Currently, I am using the <q-select> component and populating it with options fetched from an API. The issue arises when setting the value as the ID of the object, which is a number while the component expects a string, resulting in an error. <s- ...

Adjust the value of a variable within a module using Angular JS

Within my module, I have the code below: var mod; mod = angular.module('ajax-interceptor', []); mod.config(function($httpProvider) { $httpProvider.interceptors.push(["$q", function($q, dependency1, dependency2) { return { ...

Comparing the size of pointers to arrays and strings in C++

string x = "Example Text"; char y[] = "Example Text"; cout<<sizeof(x)<<","<<sizeof(y)<<endl; The result of the above code is 4,13 Due to 'x' pointing to the string, it has a size of 4 which is typical for a string on t ...

The primary controller in AngularJS

I am currently facing an issue where I am unable to load a page to its home page. When I first load the page, it redirects me to app/index.html. Is there a way to redirect the page to app/home instead? Below is my app.js code: (function () { "use strict ...

Creating a singly linked list in JavaScript that behaves like a single indexed array

I am faced with an array structure like this: var arrays = [ { "value": "$6" }, { "value": "$12" }, { "value": "$25" }, { "value": "$25" }, { "value": "$18" }, { "value": "$22" }, { "value": "$10" ...

Constructing an array in an asynchronous manner while simultaneously iterating through other arrays

In my attempt to create a comprehensive keyword list from the existing keywords, I successfully retrieved them all and displayed them in the debug console. However, I am facing confusion regarding the appropriate time and method to call resolve(taxonomyKe ...

React: Implementing localStorage token addition in loginHandler function using State hook is not functioning as expected

I've implemented an AuthContextProvider in my React application to handle user authentication and logout functionality: import React, { useState } from "react"; import axios from "axios"; import { api } from "../api"; co ...

After refreshing, the LocalStorage in Angular 2 seems to disappear

Something a little different here :) So, when attempting to log a user in, I am trying to store the access_token and expires in localStorage. It seems to be working "okay". However, if I refresh the page, the tokens disappear. Also, after clicking the log ...

Pressing a button triggers an Ajax response, but in CasperJS it results in the entire page being refreshed

Recently, I've been experimenting with CasperJS in an attempt to identify Free-Email Alias on My focus is on the input field labeled "E-Mail-Wunschname:" where I intend to input a name, click the "Prüfen" button, and then extract the suggested accou ...

Show a brief glimpse of the JS/jQuery object on the screen

Exploring JavaScript objects today and encountered an unusual glitch. <form method="get" action="" name="start" > <fieldset> <label for="date">Date</label> <input type="date" name="date" id="date" /> <div>&nbsp; ...

"Encountering a 404 error with the angular2-in-memory-web-api

Currently, I am in the process of developing a 5 minute application using Angular 2 with reference to this particular guide: https://angular.io/docs/ts/latest/tutorial/toh-pt6.html. While working on the HTTP section, I encountered a 404 error due to the a ...

Obtaining the sum of two variables from two separate functions results in a value of NaN

Why is it that I'm seeing a NaN result when trying to access a variable in two different functions? This is my code var n_standard = 0; var n_quad = 0; var totalQuad; var totalStandard; var total = totalStandard + totalQuad; ...

Utilize JavaScript to communicate with the backend server

I'm embarking on my first Cordova application, utilizing HTML, CSS, and JavaScript. My current objective is to trigger a local server call upon button click, with the intention of logging something to confirm functionality. However, I'm encounter ...

Implementing a Next.js server-side permanent redirection instead of displaying a 404 error page

My Next.js application consists of three routes: /home, /about, and /contact. When a user accesses a route that doesn't exist, Next.js automatically redirects them to the 404 page. However, I want to change this behavior and permanently redirect use ...

Why is my React component not being updated with Routes?

I'm new to using react-router and I'm struggling with it for the first time. Here is the code snippet: App.tsx import React from 'react'; logo = require('./logo.svg'); const { BrowserRouter as Router, Link, Route } = require ...

The request for an advertisement was successful, however, no ad could be displayed as there was insufficient ad inventory available. Please handle the situation appropriately with the

Using react-native, I am trying to incorporate ads into my app but encountering an error. Despite attempting various solutions, nothing seems to work. It appears that the issue may lie with the AdMob Android SDK. While I have reviewed SDK videos related to ...

Having trouble loading items in a <select> tag with Jquery?

Dealing with a seemingly simple issue, I am struggling to figure out how to load items into a select using jQuery. Working with the Materialize theme available at: The code snippet in question: <div class="input-field col s12"> <s ...

The ngIf statement in the template isn't functioning properly after a refresh; instead, it is causing a redirection to the homepage

I've been developing with Angular 7, trying to display a <div> ... </div> based on multiple values that I declared as : Boolean = false; in the .ts file. These values are updated in ngOnInit, but for some reason, the page keeps redirecting ...