Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery callback - seems to switch elements "on and off" when adding new elements

To preface, I'm a student and just started learning Javascript and jQuery. So, my goal here is to take the information from the form fields and add it to the page in "contact cards" which can then be clicked to change between two sets of information, in this case the name and the description.

So, once new cards have been added I have a callback to make the cards clickable. Where it breaks down is the first card works as expected, adding a second card the second card then works but the first doesn't, adding a third card the third and the first work and the second no longer works, and so on. Using $(document).on instead a callback gets everything working, but I'd really like to figure out why the callback isn't working.

Any suggestions would be much appreciated, thanks!

var users = [];
var identifier = 0;

function cardFlipHandler(){
	$(".card").click(function(){
		var tempID = $(this).attr("identifier");
		if($(this).attr("state") === "front"){
			$(this).html("<p>" + users[tempID].description + "</p>");
			$(this).attr("state", "back");
		}
		else {
			$(this).html("<h1>" + users[tempID].first_name + " " + users[tempID].last_name + "</h1><p>Click for description</p>");
			$(this).attr("state", "front");
		}
	});
}

$(document).ready(function(){
	cardFlipHandler();
	$("#addUser").click(function(){
		var fname = $("form").find("input[name='first_name']").val();
		var lname = $("form").find("input[name='last_name']").val();
		var desc = $("form").find("input[name='description']").val();
		users.push({first_name: fname, last_name: lname, description: desc});
		$("#rightSide").append("<div class='card' identifier='" + identifier + "' state='front'><h1>" +fname + " " + lname + "</h1><p>Click for description</p></div>");
		identifier++;
		cardFlipHandler();
	});

	/*$(document).on("click", ".card", function(){
		var tempID = $(this).attr("identifier");
		if($(this).attr("state") === "front"){
			$(this).html("<p>" + users[tempID].description + "</p>");
			$(this).attr("state", "back");
		}
		else {
			$(this).html("<h1>" + users[tempID].first_name + " " + users[tempID].last_name + "</h1><p>Click for description</p>");
			$(this).attr("state", "front");
		}
	});*/
});
*{
	margin: 5px;
	padding: 0px;
}

#wrapper {
	width: 970px;
	margin: 0 auto;
}

#userTable tr td, tr th{
	border: 1px solid black;
}

#leftSide {
	display: inline-block;
	width: 400px;
	vertical-align: top;
}

#rightSide {
	display: inline-block;
	width: 400px;
	vertical-align: top;
}

.card {
	width: 300px;
	height: 150px;
	background-color: #F1F1F1;
}
<!DOCTYPE HTML>
<html lang="en">
	<head>
		<meta charset="utf-8">
		<title>Contact Cards</title>
		<meta name="description" content="Coding Dojo assignment to create a page where contact cards can be added.">
		<link rel="stylesheet" type="text/css" href="style.css">
		<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
		<script type="text/javascript" src="card.js"></script>
	</head>
	<body>
		<div id="wrapper">
			<div id="leftSide">
				<form>
					<label>First Name:</label>
					<input type="text" name="first_name">

					<label>Last Name:</label>
					<input type="text" name="last_name">

					<label>Description:</label>
					<input type="text" name="description">
				</form>
				<button id="addUser">Add User</button>
			</div>
			
			<div id="rightSide">
				
			</div>

		</div>
	</body>
</html>
like image 354
Laez Avatar asked Dec 18 '25 01:12

Laez


1 Answers

Well, this one is interesting.

First off, $(document).on("click", ".card", function); is the correct way to do this.

I'd just stick with that if I were you.

But to explain what is going on with your code. (follow along here)

In the JSFiddle I added a console.log to line 7 of the JS. It will fire every time you click on a card. So open up your console (F12), and make a card.

When you click on it, it will function as intended. So make another card.

Now you'll see the first card's click event firing TWICE every time you click. Basically flipping, then flipping again, bringing you back to the original state. The second card works as intended. Make another card.

The first card is now firing THREE times, and the second card TWICE. So now the first appears to be working because it stops on a different face, and the second is "broken" because it ends on its original face.

Essentially, by running the callback each time you make a card, not only are you adding an event listener to the new element (as intended), you are adding ANOTHER event listener to the older cards.

This, among other reasons, is why we use $(document).on(event, selector, function); for dynamically created elements.

Further reading about the .on() event and the .click() event can be found below.

.on() | jQuery API Docs

.click() | jQuery API Docs

like image 137
amflare Avatar answered Dec 20 '25 19:12

amflare



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!