MoMN MoMN - 4 months ago 11
jQuery Question

(Filtering w/ JS) Why does "#" not work while everything else in the alphabet does

So, I was retrieving elements from another webpage and was attempting to make an organized list out of them that, when a letter was clicked, would hide all titles except for the ones whose single-letter generated classes matched.

My Problem; This worked well for all of them except for the '#' class, which is designated to those elements whose starting letters are not A-Z (i.e. "3", ".", "/", etc.). Notice how when you click the "#" in the snippet, it will either display all of them (if it is hit first) and display an error, or will just display an error. Why does that, and only that, not work.

I have duplicated the issue with jsfiddle here, replacing all of my php functionality with imitations (the program itself is not this useless, this is just to isolate the issue). The original post I made was probably way too intimidating, with a slew of scattered but relevant php scripts including a dom reader, so this makes it easier and more relevant:

Steps to reproduce




  • Click on the "Click Here" button

  • Click on the
    #
    , the first item on the list



Expected beahvior:




  • Sub items should show next to
    #



Actual behavior:




  • A JS error occurs





$(document).ready(function(){
pelement = 0;
a = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ"; i = 0;
while(i<27){
$("#letters").append("<li onclick='letShow(this);' class='"+a[i]+"'>"+a[i]+"</li>");
$("#selection").append(
"<li class='"+a[i]+"'>"+a[i]+"1</li>"+
"<li class='"+a[i]+"'>"+a[i]+"2</li>"+
"<li class='"+a[i]+"'>"+a[i]+"3</li>");
i+=1;
}
});

function displayToggle(element) {
$("#"+element).css("display", (($("#"+element)
.css("display") == "none")?"block":"none"));
}
function letShow(element) {
if(pelement == "0" || pelement == element ||
$("#selection").css("display") == "none")
displayToggle('selection');
$("#selection li").not("."+$(element).
attr("class")).hide();
$("."+$(element).attr("class")).show();
pelement = element;
}

ul {
list-style-type:none;
display:none;
float:left;
}

/*Just to achieve fixed positioning*/
#anchor {
float: left;
position: relative;
} #anchor div {
position: fixed;
margin: 15px 0 0 25px;
}

<script src="https://code.jquery.com/jquery-1.10.2.js"></script>

<div onClick='displayToggle("letters");'>Click Here</div>
<ul id="letters"></ul>
<div id="anchor"><div><ul id="selection"></ul></div></div>




Answer

You have to escape # when putting them in a selector. Look for the line that says

var escapedClassName = $(element).attr("class").replace('#', '\\#');

See https://api.jquery.com/category/selectors/ and https://mathiasbynens.be/notes/css-escapes

To use any of the meta-characters ( such as !"#$%&'()*+,./:;<=>?@[]^`{|}~ ) as a literal part of a name, it must be escaped with with two backslashes: \. For example, an element with id="foo.bar", can use the selector $("#foo\.bar").

$(document).ready(function(){
   pelement = 0;
   a = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ"; i = 0;
   while(i<27){
      $("#letters").append("<li onclick='letShow(this);' class='"+a[i]+"'>"+a[i]+"</li>");
      $("#selection").append(
         "<li class='"+a[i]+"'>"+a[i]+"1</li>"+
         "<li class='"+a[i]+"'>"+a[i]+"2</li>"+
         "<li class='"+a[i]+"'>"+a[i]+"3</li>");
      i+=1;
   }
});

function displayToggle(element) {
   $("#"+element).css("display", (($("#"+element)  
      .css("display") == "none")?"block":"none"));
}
function letShow(element) {
   if(pelement == "0" || pelement == element ||   
      $("#selection").css("display") == "none") 
         displayToggle('selection');
   var escapedClassName = $(element).attr("class").replace('#', '\\#');
   $("#selection li").not("."+escapedClassName).hide();
   $("."+escapedClassName).show();
   pelement = element;
}
ul {
  list-style-type:none; 
  display:none;
  float:left;
}

#anchor { 
    float: left;
    position: relative;
} #anchor div {
    position: fixed;
    margin: 15px 0 0 25px;
}
<script src="https://code.jquery.com/jquery-1.10.2.js"></script>

<div onClick='displayToggle("letters");'>Click Here</div>
<ul id="letters"></ul>
<div id="anchor"><div><ul id="selection"></ul></div></div>