Damn, these bugs! |
For this episode of Spot The Bug, we will dive into jQuery. I know it's not exactly fashionable anymore, but what the heck...
What I was trying to do in the code below, was have this box where anything text I entered would just appear in there.
<!DOCTYPE html>
<html>
<head>
<title>Easter Egg Hunt</title>
<style>
.tags
{
width: 600px;
height: 200px;
border: 1px solid rgb(255, 200, 0);
border-radius: 5px;
margin-bottom: 5px;
padding: 10px;
}
.tag
{
border: 1px solid rgb(255, 200, 0);
border-radius: 10px;
font-family: Verdana;
font-size: 12px;
display: inline-block;
height: 1.5em;
padding: 2px;
text-align: center;
margin-right: 1em;
margin-bottom: 1em;
cursor: pointer;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script>
$(document).ready(function()
{
$("#btnAddTag").click(function() { addTag(); });
$(".tag").click(function() { removeTag($(this)) });
});
function addTag()
{
var tagText = $("#txtTag").val();
var newTag = $("<div></div>");
newTag.addClass("tag");
newTag.html(tagText);
$(".tags").append(newTag);
}
function removeTag(obj)
{
obj.remove();
}
</script>
</head>
<body>
<div class="tags">
</div>
<input id="txtTag" maxlength="8"/><button id="btnAddTag">Add Tag</button>
</body>
</html>
<html>
<head>
<title>Easter Egg Hunt</title>
<style>
.tags
{
width: 600px;
height: 200px;
border: 1px solid rgb(255, 200, 0);
border-radius: 5px;
margin-bottom: 5px;
padding: 10px;
}
.tag
{
border: 1px solid rgb(255, 200, 0);
border-radius: 10px;
font-family: Verdana;
font-size: 12px;
display: inline-block;
height: 1.5em;
padding: 2px;
text-align: center;
margin-right: 1em;
margin-bottom: 1em;
cursor: pointer;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script>
$(document).ready(function()
{
$("#btnAddTag").click(function() { addTag(); });
$(".tag").click(function() { removeTag($(this)) });
});
function addTag()
{
var tagText = $("#txtTag").val();
var newTag = $("<div></div>");
newTag.addClass("tag");
newTag.html(tagText);
$(".tags").append(newTag);
}
function removeTag(obj)
{
obj.remove();
}
</script>
</head>
<body>
<div class="tags">
</div>
<input id="txtTag" maxlength="8"/><button id="btnAddTag">Add Tag</button>
</body>
</html>
Like so...
...and so on...
...and so for.
What went wrong
Looks great so far, right? Well, the thing is, the tags were also supposed to remove themselves from the box if I clicked on them. But no matter how I did it, they stubbornly remained in the box like turds that just refuse to be flushed away.Why it went wrong
It was all in this line. It worked just fine when I was using it on the btnAddTag button. But now it was supposed to work on all elements styled using tag. Why didn't it work?$(".tag").click(function() { removeTag($(this)) });
Because, the simple fact of the matter was, at the time this line was run, no such element existed. No elements styled using tag had been created yet. They would only get created when the btnAddTag button was clicked.
How I fixed it
For cases like this, we need event delegation. We need to tell the system to apply that rule to all future instances of that element. So we change the code this way. First, apply it to the container instead. In this case, it is the div that is styled using tags.$(".tags").click(function() { removeTag($(this)) });
Then instead of using the click() method, use the on() method.
$(".tags").on(function() { removeTag($(this)) });
Add "click" to ensure that this is the event that is watched for.
$(".tags").on("click", function() { removeTag($(this)) });
And add the class name tag as the next argument, to indicate that these are the elements to apply the callback to.
$(".tags").on("click", ".tag", function() { removeTag($(this)) });
For illustration purposes, I'm going to add a lot more tags.
Now see what happens when I click on "CSS"?
And "HTML"?
Moral of the story
The click() method is deprecated anyway. But jQuery event delegation is still a thing.Also, when you're dealing with front-end DOM manipulation, these are things to watch out for.
$(bugs).remove(),
T___T
T___T