Jonnie Grieve Digital Media: Blog

Home
by on 25th May, 2023 - 3:02pm (0)

Blog: Filtering Content: Second and final solution (More Posts)

In the last blog, I spoke about requiring a solution to the problem of how to “filter” out a large list of content depending on what category that content has been assigned to. I needed this to happen based on the toggle of a checkbox.  The last one was functional but didn’t quite do what I needed from it because the filtering was removing the wrong items or keeping items visible that should have been toggled to no display.

Today I want to explain how I found the answer to my brief with the aid of AI.

This is what I asked ChatGPT:

Input: "use input checkboxes to filter a set of child elements 
according to the class they're assigned"

I asked it to show me just one solution, using JavaScript, that allows me to use checkboxes to toggle the display of certain groups of content.  Below is some of the code that I was supplied; An expandable solution that gets me started with 2 checkboxes and a small set of div elements. With these elements, a class called “elements” is shared across them all. Each child element also has another set of classes i.e. class1, and class2 with alternating instances in each.

<input type="checkbox" id="filter1" value="class1"
onchange="filterElements()" />
<label for="filter1">Class 1</label>

<input type="checkbox" id="filter2" value="class2"
onchange="filterElements()" />
<label for="filter2">Class 2</label>

<div id="container">
    <div class="element class1">Element 1</div>
    <div class="element class2">Element 2</div>
    <div class="element class1">Element 3</div>
    <div class="element class2">Element 4</div>
    <div class="element class1">Element 5</div>
</div>

Each of the checkboxes has a call to a function using the onchange event, which is good for form inputs like checkboxes which can change the state between checked and not checked.  The function call is to the filterElements() function.

function filterElements() {

    var filters = [];
    var checkboxes = document.querySelectorAll('input[type="checkbox"]:checked');

    checkboxes.forEach(function(checkbox) {
        filters.push(checkbox.value);
    });

    // checkbox
    for (var i = 0; i < checkbox_items.length; i++) { 
        // loop code goes here... 
    }

}

In this code, Filters is a variable that stores an empty array that will contain the values of filtered classes. For simplicity’s sake, I’ll simply use the class 1, class2 to numbered names for now.

Next, the function adds class values to the array every time a filter checkbox is checked. We then use a loop that performs some actions on what exists inside the filters array at any given time.

Each checkbox will have those values assigned as its value attribute – the matching names of those classes. We use the push method to add those values to the empty array when the appropriate checkboxes are checked.

In this example, the class value element is used in each child div element of its container and is the same value as the checkboxes ID attribute.

That’s why in the filterElements function we can select to using a variable called elements.

var elements = document.getElementsByClassName('element');

And once selected we can iterate through all the elements with a for loop

for (var i = 0; i < elements.length; i++) {

}

If the length property of filters array is zero that means there are no values in it and the array is empty. if it is greater than 0 there are values we can filter

var element = elements[i];
    var elementClasses = element.className.split('
');

if (filters.length === 0) {
    element.style.display = 'block';
} else {
    var showElement = false;

    // inner for loop
}

For the inner loop, its job is to check if any of its classes match the filters and to display that element if it does. 

for (var j = 0; j < elementClasses.length; j++) {


    if (filters.includes(elementClasses[j])) {

        showElement = true;
        break;
}

You can programmatically manipulate the display property of the child elements based on the boolean value of the show element variable.

if (showElement) {
    element.style.display = 'block';
} else {
    element.style.display = 'none';
}

Finally, add the event listener to the checkbox elements.

onchange="filterElement()"

So. How does this apply to my new website

What I need to do is identify the containing elements in my new blog for the checkbox and the filtered blog items.

.filter_categories_container {

    .filter_categories {

        div {

            input {
            }
        }
    }

}

And I have a containing element where side-by-side, blog items are displayed using the inline-block property.

<section class="blog_list"> 

</section>
.blog-items {

    ...
    display: inline-block;
}

changed DOM Selector to select that set of elements for the purposes of my example which have a class value of blog-item.

var checkbox_items = document.getElementsByClassName('blog-item');

Next, set programmatically to inline-block rather than block, as this is how the blog items are displayed in their default state. If I didn’t do this each blog item would be stacked in a single column leaving some ugly white space on the right hand side.

if (filters.length === 0) {

element.style.display = 'inline-block';

} else {
... 

Next, I added 5 more filter checkboxes each with values that matched the required WordPress category slugs.  Here are the classes I used.

Existing class values.

  • web_design
  • hundred_days_code
  • jgdm_features
  • learning_journal
  • news
  • news_and_comment
  • uncategorised
<div>

<input type="checkbox" class="checkbox_items input_chkbx checked" 
onchange="filterElements()" 
id="category_one" value="jgdm_features"></div>
<label for="category_one">JGDM Features</label>

...

</div>

With just a few tweaks to the classes and selectors, I can expand the markup. For the purposes of testing the code, I create 7 instances of the blog item class each with a unique class. I created these 7 initial elements to test that they were correctly assigned to the corrext checkboxes.

<div class="blog-item jgdm_features"> ... </div>
<div class="blog-item news"> ... </div>
<div class="blog-item hundred_days_code"> ... </div>
<div class="blog-item web_design"> ... </div>
<div class="blog-item news_and_comment"> ... </div>
<div class="blog-item learning_journal"> ... </div>
<div class="blog-item uncategorised"> ... </div>

If none of the checkboxes are displayed there is no filter applied so that is treated as if all blog items should display, which I think is ideal.

Anway, let’s test this solution by assigning a number to each blog item. First in the class and then in theparagraph text.

e.g.

<div class="1 blog-item news"> ... </div>

. . . 
<p>1 Communication is not possible. The shuttle has no power. Using the gravitational 
pull of a star toslingshot back in time. Probes have recorded unusual levels 
of geological activity in all five planetarysystems. Assemble a team. Make It So!</p>

When I add unique classes to each blog item, only one blog item appears. Which is the desired result. And shows the filtering is working.

I’ll now add another instance of the JGDM features class  (“jgdm_features”) to do another functionality test.

<div class="1 blog-item jgdm_features"> ... </div>
<div class="2 blog-item hundred_days jgdm_features"> ... </div>

If I only select the jgdm_features checkbox, 2 blog items are displayed. If I then toggle the hundred_days_code checkbox which has no affect on display. This is the desired behaviour because jgdm_features class exists across both elements. It only takes the existence of one class

Let’s do the same test for the learning journal and news classes.

<div class="4 blog-item news"> ... </div>
<div class="5 blog-item learning_journal news"> ... </div>

At the time of writing, learning_journal has one blog item div element assigned to it while news is assigned to both item 4 and item 5.   If I check the box for news, 2 items should then appear. If I toggle the box for learning journal on and off, again there is no effect on what is displayed on the screen. This tells me that the code is doing what it is designed to do because while there is an instance of one class per blog item that item should always be displayed.

I am now satisfied that I have the functionality and styling I need to create a dynamic content filtering system in a WordPress theme.

This post has been assigned to the following categories

    Leave a Reply

    Your email address will not be published. Required fields are marked *