curriculum/challenges/english/blocks/lab-favorite-icon-toggler/66bf6bacf178eac7b96d4f5e.md
In this lab you will use JavaScript click events to toggle the appearance of a favorite icon. When the heart icon is clicked, the appearance of the heart changes from empty to filled, and vice versa.
Objective: Fulfill the user stories below and get all the tests to pass to complete the lab.
User Stories:
item-list.button element with the class favorite-icon.button element should contain the code ♡ initially to represent an empty heart.button element containing a heart is clicked, you should add a class named filled to the clicked button if it's not already present, and remove it, if it is.filled class and sets some CSS properties.button element containing a heart is clicked, the heart symbol should toggle between ♡ (empty heart) and ❤ (filled heart), depending on its current state.Note: Be sure to link your JavaScript file in your HTML. (Ex. <script src="script.js"></script>)
You should have an unordered list.
assert.exists(document.querySelector('ul'));
Your unordered list should have 3 items.
assert.lengthOf(document.querySelectorAll('ul li'), 3);
Your unordered list should have the class item-list.
assert.exists(document.querySelector('ul.item-list'));
Your individual list items should contain the item name.
assert.exists(document.querySelector('ul li').textContent);
Your individual list item should contain a button element with the class favorite-icon.
assert.exists(document.querySelector('ul li button.favorite-icon'));
Initially, the button elements should contain the code ♡ to represent an empty heart.
const inputs = document.querySelectorAll('ul li button.favorite-icon');
assert.isNotEmpty(inputs);
for (let input of inputs) {
assert.strictEqual(input.innerHTML.charCodeAt(0), 9825);
}
You should have a .filled selector that sets some CSS properties.
const filled = new __helpers.CSSHelp(document).getStyle('.filled');
assert.exists(filled);
assert.isNotEmpty([...filled]);
When the button element is clicked, and it contains the class filled, you should remove the class filled from the button element and change the innerHTML of the button element to ♡.
const buttonElements = document.querySelectorAll('.favorite-icon');
assert.isNotEmpty(buttonElements);
buttonElements.forEach(button => button.classList.add('filled'));
buttonElements.forEach(button => {
button.dispatchEvent(new Event('click', { bubbles: true }));
assert.isFalse(button.classList.contains('filled'));
assert.equal(button.innerHTML.charCodeAt(0), 9825);
});
When the button element is clicked, and it doesn't contain the class filled, you should add the class filled to the button element and change the innerHTML of the button element to ❤.
const buttonElements = document.querySelectorAll('.favorite-icon');
assert.isNotEmpty(buttonElements);
buttonElements.forEach(button => button.classList.remove('filled'));
buttonElements.forEach(button => {
button.dispatchEvent(new Event('click', { bubbles: true }));
assert.isTrue(button.classList.contains('filled'));
assert.equal(button.innerHTML.charCodeAt(0), 10084);
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Favorite Icon Toggler</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Favorite Icon Toggle</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<h1>Art Supplies</h1>
<ul class="item-list">
<li>
120 gm paper
<button class="favorite-icon" id="favoriteIcon1">♡</button>
</li>
<li>
Watercolor set
<button class="favorite-icon" id="favoriteIcon2">♡</button>
</li>
<li>
Lead pencil 6B
<button class="favorite-icon" id="favoriteIcon3">♡</button>
</li>
</ul>
<script src="script.js"></script>
</body>
</html>
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
font-family: Arial, sans-serif;
}
h1 {
margin-bottom: 20px;
}
.item-list {
list-style-type: none;
padding: 0;
}
.item-list li {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
border-bottom: 1px solid #ddd;
width: 200px;
}
.favorite-icon {
font-size: 1.25rem;
background-color: transparent;
border: none;
cursor: pointer;
}
.filled {
color: #d22b2b;
}
document.addEventListener("DOMContentLoaded", () => {
const favoriteIcons = document.querySelectorAll(".favorite-icon");
favoriteIcons.forEach(icon => {
icon.addEventListener("click", () => {
if (icon.classList.contains("filled")) {
icon.classList.remove("filled");
icon.innerHTML = "♡"; // Empty heart
} else {
icon.classList.add("filled");
icon.innerHTML = "❤"; // Filled black heart
}
});
});
});