Skip to main content
April 1, 2026Dan Rodney/12 min read

Recreating the Photo Gallery Filter Using jQuery, Part 2

Master advanced jQuery filtering with JavaScript arrays

Tutorial Continuation

This is Part 2 of the photo gallery filter series. Complete Part 1 first to understand the foundation concepts and button functionality.

Topics Covered in This JavaScript & JQuery Tutorial:

Master advanced jQuery techniques by populating a Standard JavaScript Array Using JQuery, leveraging JavaScript to skip over the zero index, implementing dynamic photo visibility controls, testing checkbox functionality for robust user interaction, programming both inclusive & exclusive filter logic, creating responsive filter toggling, and enhancing overall user experience through sophisticated interaction patterns.

Key Learning Objectives

Array Population

Learn to populate JavaScript arrays using jQuery methods and handle data-filter attributes efficiently.

Filter Logic

Implement both inclusive and exclusive filtering systems with checkbox toggle functionality.

DOM Manipulation

Master jQuery methods for showing, hiding, and selecting elements based on dynamic criteria.

Exercise Preview

ex prev gallery jQuery 2

Exercise Overview

Building on our previous exercise's foundation, we'll now complete our jQuery-powered photo gallery by implementing the core filtering functionality. While the previous exercise established our navigation's select/deselect behavior, this tutorial focuses on the sophisticated logic that drives photo filtering—a crucial skill for modern web applications where dynamic content manipulation is essential.

  1. If you completed the previous exercise, gallery-with-jQuery.html and gallery-with-js.html should still be open in your code editor, and you can skip the following sidebar. We strongly recommend completing the previous exercise (B5) before proceeding, as the concepts build systematically upon each other.

If You Did Not Do the Previous Exercise (B5)

  1. Close any files you may have open.
  2. Navigate to Desktop > Class Files > yourname-JavaScript jQuery Class and open the Photo-Filter-jQuery-2 folder.
  3. Open gallery-with-jQuery.html. This is the photo gallery we'll be enhancing with jQuery functionality.
  4. Also open gallery-with-js.html from the Photo-Filter-jQuery-2 folder. This completed gallery from exercise 3D serves as our JavaScript reference implementation.

Setup Process

1

Close Existing Files

Close any currently open files in your code editor to start fresh.

2

Navigate to Project Folder

Go to Desktop > Class Files > yourname-JavaScript jQuery Class and open Photo-Filter-jQuery-2 folder.

3

Open Required Files

Open both gallery-with-jQuery.html for editing and gallery-with-js.html as reference.

Populating a Standard JavaScript Array Using JQuery

With our navigation elements functioning properly from the previous exercise, we now turn our attention to the data management layer. Our empty array awaits population with selected photo data-filter attributes—a process that requires cycling through DOM elements and extracting specific attribute values. This pattern forms the backbone of many dynamic web applications where user selections drive content visibility.

  1. To examine our reference implementation, switch to gallery-with-js.html in your code editor and locate the array population function around line 256. This standard JavaScript approach will inform our jQuery enhancement.

  2. Return to gallery-with-jQuery.html and integrate the populateArray() function call around line 180. This ensures our array updates with every user interaction:

    $filterNav.on('click', function() {
       toggleCategory($(this));
       populateArray();
    });
  3. For comparison purposes, examine the standard JavaScript implementation in gallery-with-js.html around lines 181–196. Notice the verbose iteration patterns we'll streamline with jQuery.

  4. In gallery-with-jQuery.html, declare our new function around line 178, maintaining clean code organization:

    function deselectOthers(filterChoice) {

    Code Omitted To Save Space

    }
    
    function populateArray() {
    
    }
    
    $filterNav.on('click', function() {
  5. Begin the function by resetting our array to ensure clean state management—a critical practice in dynamic applications where stale data can cause unexpected behavior:

    function populateArray() {
       selectedArray = [];
    }
  6. Implement conditional logic to handle the special case of the "All" button, which requires different processing logic than individual filter categories:

    function populateArray() {
       selectedArray = [];
       if($allButton.attr('data-selected') == 'yes') {
    
       } else {
    
       }
    }
  7. When the "All" button is selected, we need to populate our array with every available filter option except the "all" category itself. Reference the standard JavaScript implementation in gallery-with-js.html around lines 185–187 to see our original for loop approach.

    jQuery's philosophy differs significantly from traditional JavaScript loops. While jQuery methods like click() automatically apply to all matched elements through implicit iteration, our selectedArray requires explicit iteration since it's a standard JavaScript array, not a jQuery object. jQuery's .each() method provides an elegant solution—think of it as a more intuitive, less verbose alternative to JavaScript's traditional for loops.

  8. Implement the each method within our conditional statement, including diagnostic logging to verify our array population:

    function populateArray() {
       selectedArray = [];
       if($allButton.attr('data-selected') == 'yes') {
          $filterNav.each(function() {
             selectedArray.push($(this).attr('data-filter'));
          });
       } else {
    
       }
       console.log(selectedArray);
    }
  9. Save your changes and prepare for browser testing.

  10. Preview index.html in Chrome, which provides the most robust developer tools for debugging JavaScript applications.

  11. Access the Console using Cmd–Opt–J (Mac) or CTRL–Shift–J (Windows)—essential for monitoring JavaScript execution and debugging.

  12. Test the deselection behavior by clicking the All button. The Console should display [], confirming our empty array state.

  13. Re-select the All button to verify full population. The Console should display all filter values: ["all", "animals", "buildings", "trees", "bw"]

jQuery vs Standard JavaScript Loops

FeatureStandard JavaScriptjQuery Approach
Syntax Complexityfor(i=0; i<array.length; i++)$.each(array, function(i))
ReadabilityMore verboseCleaner and intuitive
Error HandlingManual bounds checkingBuilt-in safety
Recommended: Use jQuery.each() for cleaner, more maintainable code when working with arrays.

Using JavaScript to Skip over the Zero Index

Our current implementation includes the "all" value, which creates a problem since we don't have a corresponding CSS class for filtering. This scenario perfectly illustrates the symbiotic relationship between jQuery and JavaScript—while jQuery excels at DOM manipulation and event handling, certain array operations still require JavaScript's native methods for precision control.

  1. Keep gallery-with-jQuery.html open in Chrome for continued testing while we refine our implementation.

  2. Return to your code editor to address the index issue.

  3. Examine our current each() method around line 182. Notice that it processes every element in our navigation array, including the problematic first item at index 0.

  4. Implement JavaScript's native shift() method to elegantly remove the unwanted "All" selector while repositioning remaining array elements:

    if($allButton.attr('data-selected') == 'yes') {
       $filterNav.each(function() {
          selectedArray.push($(this).attr('data-filter'));
       });
       selectedArray.shift();
    } else {

    NOTE: The shift() method removes the first array element and automatically reindexes remaining items, making position 1 become 0, position 2 become 1, and so forth.

  5. Save your modifications for testing.

  6. Return to Chrome and reload gallery-with-jQuery.html to test our array manipulation.

  7. Ensure the Console remains open for monitoring our output.

  8. Test deselection by clicking the All button—you should continue seeing the empty array indicator: []

  9. Re-select the All button to verify our fix. The Console should now display the cleaned array without the problematic "all" value: ["animals", "buildings", "trees", "bw"]

Array Manipulation Insight

The shift() method removes the first array element and shifts remaining elements down by one index. This is perfect for removing the 'all' filter from our selection array.

The shift() method deletes the first item in the Array and shifts the other values so that 1 becomes 0, 2 becomes 1, etc.
Understanding how array indices change after using shift() method

Selecting Buttons Other Than the All Button

Individual filter selection requires different logic than our "All" button handling. When users select specific categories, we need conditional processing that only includes filters with active selection states. This granular control enables the sophisticated filtering behavior users expect in modern web applications.

  1. Return to your code editor to implement selective filter logic.

  2. Complete our conditional statement by adding selective processing logic to the else block around line 186:

    } else {
       $filterNav.each(function() {
          if($(this).attr('data-selected') == 'yes') {
             selectedArray.push($(this).attr('data-filter'));
          }
       });
    }
    console.log(selectedArray);
  3. Save your implementation for browser verification.

  4. Return to Chrome and reload gallery-with-jQuery.html to test individual filter selection.

  5. Verify the Console remains accessible for monitoring array changes.

  6. Test individual filter functionality by clicking any non-All filter button. The Console should display the corresponding filter values, confirming successful array population. This validates that our data layer correctly responds to user interactions.

Filter Selection Logic

0/4

Hiding the Photos

With our data management layer functioning correctly, we now implement the visual effects that bring our filtering system to life. Photo visibility control forms the foundation of our user interface, requiring careful coordination between data state and DOM manipulation.

  1. Return to your code editor to integrate photo filtering functionality.

  2. Connect our data processing to visual output by calling the filterPhotos() function in our event handler around line 198:

    $filterNav.on('click', function() {
       toggleSelector($(this));
       populateArray();
       filterPhotos();
    });
  3. Clean up our diagnostic code by removing the console.log(selectedArray); statement around line 192, along with any unnecessary whitespace.

  4. Establish our main filtering function around line 194, maintaining logical code organization:

    }
    
    function filterPhotos() {
    
    }
    
    $filterNav.on('click', function() {
  5. Reference our JavaScript implementation in gallery-with-js.html around line 237 to understand the photo hiding strategy employed in our original approach.

  6. Begin our filtering process by ensuring a clean visual state—hiding all photos before applying specific visibility rules:

    function filterPhotos() {
       hideAllPics();
    }
  7. Implement the photo hiding functionality as a dedicated function around line 194, promoting code reusability and maintainability:

    function hideAllPics() {
    
    }
    
    function filterPhotos() {
  8. Study the original implementation in gallery-with-js.html around lines 199–202. Notice the verbose loop structure required to iterate through imageContainers and manually set display properties.

  9. Leverage jQuery's superior DOM manipulation capabilities around line 195. jQuery's implicit iteration eliminates the need for manual loops while providing cleaner, more maintainable code:

    function hideAllPics() {
       $imageContainers.hide();
    }

    NOTE: jQuery's .hide() method provides semantic clarity, though we could achieve identical results with .css('display', 'none'). The hide() method is preferred for its expressiveness and potential animation capabilities.

  10. Save your implementation and prepare for browser testing.

  11. Return to Chrome and reload gallery-with-jQuery.html to verify photo hiding functionality.

  12. Test the hiding behavior by clicking any filter button. All images should disappear, confirming our foundation for selective visibility is working correctly.

Hide Methods Comparison

FeaturejQuery hide()jQuery css()
Code Syntax$imageContainers.hide()$imageContainers.css('display', 'none')
ReadabilityHighly readableMore explicit
FunctionalitySets display: noneSets display: none
Recommended: Use hide() method for cleaner, more semantic code when simply hiding elements.

Testing the Checkbox's Functionality

Our filtering system requires two distinct modes: inclusive filtering (showing photos that match any selected criteria) and exclusive filtering (showing only photos that match all selected criteria). The checkbox state determines which filtering logic to apply, making robust state detection crucial for proper functionality.

  1. Return to your code editor to implement checkbox state detection.

  2. Add diagnostic functionality to our filterPhotos() function around line 200, enabling real-time verification of checkbox state changes:

    function filterPhotos() {
       hideAllPics();
       if($exclusive.is(':checked')) {
          console.log('checked');
       } else {
          console.log('not checked');
       }
    }

    NOTE: The :checked pseudo-class provides reliable state detection for checkbox elements, similar to other CSS pseudo-classes like :hover but specifically for form element states.

  3. Save your diagnostic implementation for browser testing.

  4. Return to Chrome and reload the page to verify checkbox detection.

  5. Ensure the Console remains open for monitoring state changes.

  6. Test the default state by clicking any filter button. You should see not checked in the Console, confirming the checkbox's default unchecked state.

  7. Activate the checkbox and click another filter button. The Console should display checked, validating our state detection mechanism works reliably.

Pseudo-class Usage

The :checked pseudo-class works similarly to :hover. Use $exclusive.is(':checked') to test checkbox state in jQuery.

Programming the Inclusive Filter

Inclusive filtering represents the more intuitive filtering mode for most users—displaying photos that match any of the selected criteria. This approach maximizes content visibility while still providing meaningful categorization, making it ideal for exploratory browsing experiences.

  1. Return to your code editor to replace diagnostic code with functional filtering logic.

  2. Remove the temporary console.log() statements around lines 207 and 209, cleaning up our implementation.

  3. Implement the inclusive filtering logic in our else statement around line 209:

    function filterPhotos() {
       hideAllPics();
       if($exclusive.is(':checked')) {
    
       } else {
          filterInclusive();
       }
    }
  4. Define our inclusive filtering function around line 198, maintaining clean separation between the hideAllPics() and filterPhotos() functions:

    }
    
    function filterInclusive() {
    
    }
    
    function filterPhotos() {
  5. Study the reference implementation in gallery-with-js.html around lines 213–221. The original approach involved:

    • Creating a group variable for element collection
    • Iterating through selectedArray using traditional for loops
    • Building class selectors by prepending periods to array values
    • Using querySelectorAll() for element selection
    • Manually setting display properties to inline-block

    Our jQuery implementation will significantly streamline this process.

  6. Attempt to use jQuery's .each() method directly on selectedArray around line 199 to understand why this approach fails:

    function filterInclusive() {
       selectedArray.each(function() {
          console.log('hello');
       });
    }
  7. Save the file to test this intentional error.

  8. Return to Chrome and reload the page for error demonstration.

  9. With the Console open, click any filter button. The error message selectedArray.each is not a function appears because selectedArray is a standard JavaScript array, not a jQuery object. This limitation requires a different approach.

  10. Open a new browser tab and navigate to: api.jQuery.com for official documentation.

  11. Search for: $.each using the search functionality in the top right corner.

  12. Click on jQuery.each() in the results. This global jQuery utility function accepts non-jQuery arrays as its first argument, with the callback function as the second argument—exactly what we need for our selectedArray.

  13. Return to your code editor to implement the correct solution.

  14. Remove the problematic code from lines 199–201:

    selectedArray.each(function() {
       console.log('hello');
    });
  15. Replace it with the proper jQuery.each() syntax that accommodates non-jQuery arrays:

    function filterInclusive() {
       $.each(selectedArray, function(i) {
    
       });
    }

    NOTE: The function accepts an index parameter i representing the current array position during iteration.

  16. Complete the inclusive filtering logic around line 200:

    function filterInclusive() {
       $.each(selectedArray, function(i) {
          $('.' + selectedArray[i]).show();
       });
    }

    NOTE: This elegant solution constructs CSS class selectors by prepending periods to our array values, then uses jQuery's .show() method to reveal matching elements. The inclusive nature means photos matching any selected filter become visible.

  17. Save your implementation for comprehensive testing.

  18. Return to Chrome and reload the page to test inclusive filtering.

  19. Click the Black & White button first—this filter provides the most visually obvious results for verification.

  20. Add Trees to your selection. Notice that photos displaying either black & white OR trees become visible, demonstrating the inclusive OR logic working correctly.

jQuery Method Limitation

selectedArray.each() won't work because selectedArray is not a jQuery object. Use $.each(selectedArray, function(i){}) instead to iterate over standard JavaScript arrays.

Inclusive Filter Implementation

1

Use $.each() Method

Apply jQuery.each() to non-jQuery arrays by passing array as first argument

2

Build Class Selector

Concatenate '.' with selectedArray values to create valid CSS class selectors

3

Show Matching Elements

Use jQuery show() method to display elements matching the constructed selector

Programming the Exclusive Filter

Exclusive filtering implements AND logic, displaying only photos that match all selected criteria simultaneously. This mode proves invaluable for users seeking specific combinations—such as black and white photos of buildings—enabling precise content discovery in large image collections.

  1. Return to your code editor to implement exclusive filtering logic.

  2. Complete our conditional structure by calling the exclusive filter function around line 204:

    function filterPhotos() {
       hideAllPics();
       if($exclusive.is(':checked')) {
          filterExclusive();
       } else {
          filterInclusive();
       }
    }
  3. Define the filterExclusive() function around line 204, maintaining logical organization between filterInclusive() and filterPhotos():

    }
    
    function filterExclusive() {
    
    }
    
    function filterPhotos() {
  4. Study the reference implementation in gallery-with-js.html around lines 223–235. The original JavaScript approach built complex query strings by concatenating class names, then used querySelectorAll() for element selection. jQuery's selector engine provides a much more elegant solution.

  5. Initialize our query string variable around line 205:

    function filterExclusive() {
       var queryString = '';
    }
  6. Build the compound selector string by concatenating all selected filter classes around line 206:

    function filterExclusive() {
       var queryString = '';
       $.each(selectedArray, function(i) {
          queryString += ('.' + selectedArray[i]);
       });
       console.log(queryString);
    }
  7. Save your work for testing the query string generation.

  8. Return to Chrome and reload the page, ensuring the Console remains open.

  9. Activate the checkbox to enable exclusive filtering mode.

  10. Click the Trees button. The Console should display .trees, confirming single-class selection.

  11. Add Buildings to your selection. The Console should show .buildings.trees, demonstrating compound selector construction.

  12. Test comprehensive selection with the All button, which should display .animals.buildings.trees.bw in the Console.

Exclusive vs Inclusive Filtering

Pros
Shows only items matching ALL selected criteria
Provides precise filtering control
Reduces result set for focused searches
Better for finding specific combinations
Cons
May return no results if criteria too restrictive
Less flexible than inclusive filtering
Requires more complex queryString building

Key Takeaways

1jQuery's $.each() method enables iteration over standard JavaScript arrays that aren't jQuery objects
2The shift() method removes the first array element and shifts remaining indices, useful for removing unwanted items
3Inclusive filtering shows items matching ANY selected criteria, while exclusive filtering shows items matching ALL criteria
4jQuery's hide() and show() methods provide cleaner syntax than manually setting CSS display properties
5Checkbox state can be tested using the :checked pseudo-class with jQuery's is() method
6Event listeners on form elements like checkboxes enable dynamic filter behavior without page reloads
7Building dynamic CSS selectors by concatenating class names allows flexible DOM element targeting
8Console logging during development helps verify array population and filter logic functionality

RELATED ARTICLES