Manipulating items through the use of RemoveChild() and appendChild()

I'm currently working on a basic filter using Vanilla Javascript and CSS.

Whenever a user chooses a category, the articles that do not belong to that category are hidden by adding the class .hide. My goal is to then remove these hidden articles from the DOM completely, and later display them again when the user selects the relevant category.

The filtering mechanism successfully adds and removes the class .hide. However, the problem arises when the hidden articles are removed - they do not reappear upon selection.

Here's the JS logic:

const filterBox = document.querySelectorAll('.js-article');

document.querySelector('.js-filter-list').addEventListener('click', (event) => {

    if (event.target.tagName !== 'BUTTON') return false;
    let filterClass = event.target.dataset['filter'];

    filterBox.forEach(elem => {
        elem.classList.remove('hide');
        elem.parentNode.appendChild(elem);

        if (!elem.classList.contains(filterClass) && filterClass !== 'all') {
            elem.classList.add('hide');
            elem.parentNode.removeChild(elem);
        }
    });

});

This is how the HTML structure looks like:

<div class="c-filter__list js-filter-list">
    <button class="c-filter__list-item is-active js-filter-item" data-filter="all">All</button>
    <button class="c-filter__list-item o-font-title js-filter-item" data-filter="cat-1">Cat 1</button>
    <button class="c-filter__list-item o-font-title js-filter-item" data-filter="cat-2">Cat 2</button>
    <button class="c-filter__list-item o-font-title js-filter-item" data-filter="cat-3">Cat 3</button>
    <button class="c-filter__list-item o-font-title js-filter-item" data-filter="cat-4">Cat 4</button>
</div>

<article class="js-article cat-1"></article>
<article class="js-article cat-2"></article>
<article class="js-article cat-2 cat-3"></article>
<article class="js-article cat-1" ></article>
<article class="js-article cat-4"></article>
<article class="js-article cat-3 cat-4"></article>
...

Your assistance is much appreciated!

Answer №1

Using references to HTMLElement and TextNode can be seamlessly integrated into every JavaScript object without relying on the DOM.

To begin with, the OP should populate an array with references to all available article nodes, which can then be filtered based on the selected filter-name.

When a filter is changed, the re-render process involves...

  • Clearing the root or parent node of all its child nodes
  • Filtering the initial array of available article nodes based on the currently selected filter-name
  • Appending each node reference from the filtered array to the article's root or parent node

Additional improvements include...

  • Assigning a common parent node for ungrouped article nodes
  • Implementing event-delegation by adding a single event-listener to the filter's root node
  • Segregating the handling of filter changes from the (re-)rendering task

function clearElementNode(elmNode) {
  const nodeList = [...elmNode.childNodes];

  let node;
  while (node = nodeList.pop()) {

    elmNode.removeChild(node);    
  }
  return elmNode;
}

function renderFilteredArticles(filterName) {
  const articlesRoot =  clearElementNode(
    document.querySelector('.article-overview')
  );
  const filteredNodesList = (filterName === 'all')

    // ... either the initial array of every available article node.
    && listOfArticleNodes

    // ... or a filtered version of this array (by filter name).
    || listOfArticleNodes
        .filter(({ classList }) => classList.contains(filterName));

  filteredNodesList
    .forEach(elmNode => articlesRoot.appendChild(elmNode));
}
function handleFilterUpdate({ target }) {
  // utilizing event delegation.
  target = target.closest('[data-filter]');

  if (target !== null) {
    // retrieve the filter name from `dataset.filter`
    const filterName = target.dataset.filter ?? null;

    if (filterName !== null && !target.classList.contains('selected')) {
      // manage the selected states of all filter buttons.
      target
        .closest('.js-filter-list')
        .querySelectorAll('[data-filter]')
        .forEach(elm =>
          elm.classList.remove('selected')
        );
      target.classList.add('selected');

      // re-render the articles based on the provided filter name.
      renderFilteredArticles(filterName);
    }
  }
}
const listOfArticleNodes = [];

function initialize() {
  document
    .querySelector('.js-filter-list')
    .addEventListener('click', handleFilterUpdate);

  // create an array containing all available article nodes.
  listOfArticleNodes
    .push(
      ...document.querySelectorAll('article.js-article')
    );
}
initialize();
[data-filter].selected {
  transform: scale(1.1);
  color: #eee;
  background-color: #333;
}
.article-overview {
  margin: 10px 0;
}
<div class="js-filter-list">
  <button type="button" data-filter="all">All</button>
  <button type="button" data-filter="cat-1">Cat 1</button>
  <button type="button" data-filter="cat-2">Cat 2</button>
  <button type="button" data-filter="cat-3">Cat 3</button>
  <button type="button" data-filter="cat-4">Cat 4</button>
</div>

<div class="article-overview">
  <article class="js-article cat-1">cat-1</article>
  <article class="js-article cat-2">cat-2</article>
  <article class="js-article cat-2 cat-3">cat-2 cat-3</article>
  <article class="js-article cat-1" >cat-1</article>
  <article class="js-article cat-4">cat-4</article>
  <article class="js-article cat-3 cat-4">cat-3 cat-4</article>
</div>

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

Failure to update the DOM after clicking a button and making an AJAX request

After experimenting with different iterations of this code, the outcomes have been mediocre and inconsistent. The concept is rather simple: A user inputs a search query into a text box, clicks a button, and the query is assigned to a var search. This varia ...

Having trouble with TypeScript configuration of typeRoots and types functionality not functioning correctly

My Current Directory Structure Let me show you the layout of my files: root ├──typings/ # currently empty ├──package.json ├──package-lock.json ├──tsconfig.json └──main.ts This is what my tsconfig.json looks like: { ...

Avoid unintended double-tapping on mobile devices

On my main page, I have a button that triggers an overlay with item details, including buttons like one that reveals a phone number. An issue arises when a user accidentally double-clicks the main page button. The first click is processed on the main page ...

What is the best way to alert a user before they navigate away from a page with content in a textarea?

I am attempting to recreate the functionality seen on textareas in Stack Overflow. UPDATE: Following the advice provided here, I have implemented something similar to the following: window.onbeforeunload = function() { var myTextArea = document.getE ...

What is the process for sending a data response with express?

Seeking guidance on running the .get operation on a JSON file I have stored at the path /scripts/src/data/*.json. When making the request, I am setting the headers but unsure how to retrieve the resulting data or where to view this request. Any assistance ...

When using jQuery's remove() or after() functions, be aware that they may inadvertently remove

Here is the html code I am working with: <p>This is some random text in a paragraph with a <span class="blue">blue</span> word.</p> <p>This is some random text in a paragraph with a <span class="blue">blue</span> ...

Ways to implement a custom scrollbar across an entire webpage:

I am trying to implement the Jquery custom content scroller on my webpage to replace the default scrollbar. However, I am facing difficulties in getting it to work properly. You can view my code on Codepen. Although the plugin works fine with smaller blo ...

How can I implement disabling buttons for specific IDs in React?

I'm currently developing an interactive quiz application with React that features multiple choice questions. I've implemented state management to track and increment the user's score when they select the correct answer option, but there&apos ...

Learn how to swap out the traditional "back to top" button with a customized image and make it slide onto or off the page instead of simply fading in and out

As a newcomer, I am trying to replicate a unique "back to top" effect that caught my eye on another website. Instead of the traditional fade-in approach when scrolling down, the "back to top" image in question elegantly slides out from the bottom right c ...

Does CSS delayed visibility transition fail to activate JavaScript transitionend event for elements' visibility changes?

My current approach involves using a clever method to delay the transition of visibility, in combination with opacity. So far, everything is working smoothly: <body> <button>run</button> <div class="box"></div> & ...

Troubleshooting sound problems in Angular JS

Can anyone help with pausing an AngularJS audio when the browser window is closed and resuming it when the window is maximized? I'm new to AngularJS and have no idea how to achieve this. var app=angular.module("myApp",['ngAudio']); ...

When Ajax responseText and echo fail, the header file contents are sent back instead

I have a section of code in my PHP file called thePhpFile.php that is used to handle an Ajax call: <?php require_once('usefulStuff.php'); // includes useful functions if (isset($_GET['zer'])) { $bFound = false; if(! $bF ...

Why is the `node-config` configuration undefined within a TypeScript Jest environment?

I have a TypeScript module that is functional in both development and production environments. It utilizes https://github.com/lorenwest/node-config. When I attempt to import it into Jest for testing purposes, I encounter an error suggesting that the config ...

Switching Formview mode using javascript

Currently, I have a formview on my website and I am looking to change the formview mode using JavaScript. Specifically, I want the formview to switch between insert mode and edit mode based on different interactions with buttons. I have a repeater on my p ...

Unexpected behavior encountered when using onClick in a material-ui List component containing Buttons

Looking to implement a customized list using React and Material-UI, where each item features a Checkbox, a text label, and a button. The onClick event for the Checkbox should be managed by a separate function from the onClick event for the Button. Encount ...

The initial value set for the innerHTML property of a div element

I have a requirement in my application where I need to confirm if the container div is empty before adding specific text elements to it. The innerHTML of this div is frequently created and removed within the app, so it's crucial to validate its emptin ...

Execute JavaScript code before analyzing the content

I need to extract data from a different website, but the challenge is that this website loads its content using JavaScript. Every solution I've found on platforms like Stackoverflow and Google attempts to parse the source before the content is fully l ...

What advantages does NextJS offer that set it apart from other frameworks that also provide Server Side Render solutions?

I'm diving into the world of NextJS and as I explore this topic, one burning question arises: "What is the necessity of utilizing NextJS?" From what I understand, NextJS excels in rendering pages from the server and is heavily reliant on ReactJS. Howe ...

Using React - What is the best way to invoke a function from within a different function?

Imagine this scenario: class Navigation extends React.Component { primaryFun() { console.log('funn') } secondaryFun() { this.primaryFun(); } } I assumed that calling primaryFun within secondaryFun would work as expected, but instead I rec ...

Issue with Java HtmlUnit - extracting null href value during website scraping

I'm currently working on a project that involves sending a URL to multiple websites for categorization and security risk scanning using Java and HtmlUnit. I have configured all the websites except www.virustotal.com, where I'm facing a challenge ...