Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to return an index of an object after being clicked?

I am doing The Odin Library Project and I created a function that lets you change a status of a book depending on if you’ve read it and it changes the color of the little bar on top but the problem is that I have no idea how to access that object’s properties so the read status can get modified there too (so for example if you mark the first book as read the property of that object will be read = true). I’ve tried to get the index of the selected element like this:

markReadBtn.forEach(mark =>
  addEventListener('click', e => {
    if (e.target == mark) {
      if (!e.target.checked) {
        e.target.parentNode.nextSibling.nextElementSibling.classList.remove(
          'read'
        );
        e.target.parentNode.nextSibling.nextElementSibling.classList.add(
          'not-read'
        );
        console.log(i);

But for some reason it returns indexes of all objects at the same time. I am still very new to programming so sorry if the code is a mess.

const title = document.querySelector('#book-title');
const author = document.querySelector('#book-author');
const pages = document.querySelector('#book-pages');
const read = document.querySelector('#book-status');
const addBtn = document.querySelector('form');
const cardContainer = document.querySelector('.card-container');
const openFormBtn = document.querySelector('#open-form');
const form = document.querySelector('.form-modal');
const overlay = document.querySelector('.form-overlay');
let myLibrary = [];

// show form
openFormBtn.addEventListener('click', () => form.classList.remove('hidden'));
// close form
overlay.addEventListener('click', closeForm);
function closeForm() {
  form.classList.add('hidden');
  // clear input fields
  title.value = '';
  author.value = '';
  pages.value = '';
  read.checked = false;
}

// create a new book
function Book(title, author, pages, read) {
  this.title = title;
  this.author = author;
  this.pages = pages;
  this.read = read;
}

// add book to myLibrary array
addBtn.addEventListener('submit', addBookToLibrary);
function addBookToLibrary(e) {
  e.preventDefault();
  const book = new Book(title.value, author.value, pages.value, read.checked);
  myLibrary.push(book);
  closeForm();
  displayBooks();
}

// display myLibrary
function displayBooks() {
  cardContainer.innerHTML = '';
  myLibrary.forEach((book, i) => {
    const displayBook = document.createElement('div');
    displayBook.className = 'card';
    displayBook.setAttribute('data-index', `${i}`);
    displayBook.innerHTML = `<h1 class="title">${book.title}</h1>
    <h2 class="author">${book.author}</h2>
    <h3 class="pages">${book.pages} pages</h3>
    <h2 class="status">${
      book.read
        ? `<input type="checkbox" class="mark-read" checked>`
        : `<input type="checkbox" class="mark-read">`
    } mark read</h2>
    <div class="status-bar ${book.read ? `read` : 'not-read'}">`;
    cardContainer.appendChild(displayBook);

    // mark read
    const markReadBtn = document.querySelectorAll('.mark-read');
    markReadBtn.forEach(mark =>
      addEventListener('click', e => {
        if (e.target == mark) {
          if (!e.target.checked) {
            e.target.parentNode.nextSibling.nextElementSibling.classList.remove(
              'read'
            );
            e.target.parentNode.nextSibling.nextElementSibling.classList.add(
              'not-read'
            );
          } else if (e.target.checked) {
            e.target.parentNode.nextSibling.nextElementSibling.classList.remove(
              'not-read'
            );
            e.target.parentNode.nextSibling.nextElementSibling.classList.add(
              'read'
            );
          }
        }
      })
    );
  });
}

// test books
const ISOLT = new Book('In Search of Lost Time', 'Marcel Proust', 4215, true);
myLibrary.push(ISOLT);
const Hamlet = new Book('Hamlet', 'William Shakespeare', 104, false);
myLibrary.push(Hamlet);
displayBooks();
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap');

:root {
  --font: #252425;
  --card-bg: #F5F5F5;
  --red: #E93643;
  --green: #AEBE4D;
}

* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
  font-size: 16px;
}

body {
  font-family: 'Poppins', sans-serif;
  color: var(--font);
  width: 100vw;
  height: 100vh;
  position: relative;
}


/* header */
header {
  background-color: var(--card-bg);
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem 2rem;
  height: 100px;
}

header h1 {
  font-size: 2.5rem;
}

header h2 {
  font-weight: 400;
  cursor: pointer;
}
 
header h2:hover {
  border-bottom: 1px solid var(--font);
}

/* main */
.card-container {
  display: flex; 
  padding: 2rem;
}

.card {
  background-color: var(--card-bg);
  width: 300px; /* change later */
  margin-right: 1rem;
  padding: 1rem;
  height: 155px;
  position: relative;
}

.card h1 {
  font-size: 1rem;
}

.card h2 {
  font-weight: 500;
  font-size: 1rem;
}

.card h3 {
  font-size: 0.8rem;
  font-weight: 400;
}

.card .status {
  margin-top: 2rem;
}

.status-bar {
  width: 50px;
  height: 10px;
  position: absolute;
  top: 0;
  right: 10%;
}

input[type="checkbox"] {
  accent-color: var(--font);
}

.status-bar.read {
  background-color: var(--green);
}

.status-bar.not-read {
  background-color: var(--red);
}

/* form */
.form-overlay {
  width: 100%;
  height: 100%;
  position: absolute;
  background-color: #25242588;
  top: 0;
  left: 0;
  z-index: 1;
}

form { 
  position: absolute;
  z-index: 2;
  background-color: var(--card-bg);
  width: 400px;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  text-align: center;
  display: flex;
  flex-direction: column;
  padding: 2rem;
}

form label {
  margin: 0.5rem 0;
  font-weight: 600;
  text-align: left;
}

form input {
  width: 100%;
  padding: 0.3rem 0.3rem;
  font-family: inherit;
  font-size: 0.9rem;
  margin-top: 0.3rem;
}

form input[type="checkbox"] {
  width: initial;
  margin: 0;
  padding: 0;
  margin-right: 0.3rem;
}

form button {
  padding: 1rem 2rem;
  font-family: inherit;
  font-size: 1rem;
  font-weight: 600;
  margin-top: 2rem;
  background-color: var(--font);
  border: none;
  outline: none;
  color: white;
  cursor: pointer;
}

form button:hover {
  background-color: #050505;
}

.hidden {
  display: none;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="styles.css">
  <title>Library</title>
</head>
 
<body>
  <header>
    <h1>library</h1>
    <div class="options">
      <h2 id="open-form">+ add book</h2>
    </div>
  </header>
  <main>
    <div class="form-modal hidden">
      <form>
        <h2>add book</h2>
        <label>Title <input type="text" id="book-title" required></label>
        <label>Author <input type="text" id="book-author" required></label>
        <label>Pages <input type="number" id="book-pages" required min="1"></label>
        <label class="checkbox-container"><input type="checkbox" id="book-status"> Mark read</label>
        <button id="add-book">Add</button>
      </form>
      <div class="form-overlay"></div>
    </div>


    <div class="card-container"></div>
  </main>

  <script src="script.js"></script>
</body>

</html>

.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

Two issues:

  • addEventListener('click', …) is short for window.addEventListener('click', …). Maybe you meant mark.addEventListener('click', …)? That way you won’t need if (e.target == mark).
  • document.querySelectorAll('.mark-read'); selects all buttons in the whole document, all the ones you’ve added so far in the myLibrary.forEach(…) loop. You probably want only the last one, the one added to the current iteration’s card, so use const markReadBtn = displayBook.querySelector('.mark-read'); (and with querySelector instead of querySelectorAll, you don’t need to loop)
const markReadBtn = displayBook.querySelector('input.mark-read');
const statusBar = displayBook.querySelector('.status-bar');
markReadBtn.addEventListener('change', e => {
  // const statusBar = e.currentTarget.parentNode.nextSibling.nextElementSibling;
  statusBar.classList.toggle('read', markReadBtn.checked);
  statusBar.classList.toggle('not-read', !markReadBtn.checked);
});
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading