javascripthtmlcss

querySelectorAll not working to find classes that end with text


I would like a JS function to remove a class from any div that has a class name ending with a specific value.

Here's my example:

const elements = document.querySelectorAll('[class$="-lvl1"]');

elements.forEach(element => {
    element.classList.remove('hidden');
});
.hidden
{
  display: none;
}
<div class="A-lvl1 hidden">
A
</div>
<div class="B-lvl1 hidden">
B
</div>
<div class="C-lvl1 hidden">
C
</div>
<div class="D-lvl2 hidden">
D
</div>

I would like the "hidden" class removed from any element that has has a classname ending in "-lvl1". Currently querySelectorAll does not return any elements.

I have tried printing the output of "elements" to the console, but it does not return any. If I try to select a specific class querySelectorAll('.A-lvl1'), it works, so I presume there is an issue with the selector ('[class$=-lvl1]')

I'm expecting all of the "-lvl1" divs to appear after the code runs, as the "hidden" class should be removed.


Solution

  • Based on the order of your classes, you should be using *= in your selector, rather than $= because your class attributes actually end with hidden. The *= allows for matching against values that contain the specified string. But note that using this wildcard search could wind up matching on classes you didn't intend to match.

    document.querySelectorAll('[class*="-lvl1"]').forEach(element => {
        element.classList.remove('hidden');
    });
    .hidden { display: none; }
    <div class="A-lvl1 hidden">A</div>
    <div class="B-lvl1 hidden">B</div>
    <div class="C-lvl1 hidden">C</div>
    <div class="D-lvl2 hidden">D</div>

    You could also just swap the order of the class names so that hidden is listed first and then use $=.

    document.querySelectorAll('[class$="-lvl1"]').forEach(element => {
        element.classList.remove('hidden');
    });
    .hidden { display: none; }
    <div class="hidden A-lvl1">A</div>
    <div class="hidden B-lvl1">B</div>
    <div class="hidden C-lvl1">C</div>
    <div class="hidden D-lvl2">D</div>