Home > Software design >  How to return an index of an object after being clicked?
How to return an index of an object after being clicked?

Time:07-28

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 >${book.title}</h1>
    <h2 >${book.author}</h2>
    <h3 >${book.pages} pages</h3>
    <h2 >${
      book.read
        ? `<input type="checkbox"  checked>`
        : `<input type="checkbox" >`
    } mark read</h2>
    <div >`;
    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 >
      <h2 id="open-form">  add book</h2>
    </div>
  </header>
  <main>
    <div >
      <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 ><input type="checkbox" id="book-status"> Mark read</label>
        <button id="add-book">Add</button>
      </form>
      <div ></div>
    </div>


    <div ></div>
  </main>

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

</html>

.

CodePudding user response:

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);
});
  • Related