dLucs
dLucs

Reputation: 49

updating Object field, using eventListener

I am currently doing a Book Library project and I am having trouble updating the status of Read/Unread field of each object. I currently have it set up so that when a button is toggled it changes to Read/Unread and also changes the CSS style accordingly. the status is working on already created books, but dynamically created ones do not work. so my question is, how can I set up the event listener so that when I press the button it also updates the status field on each object to Read Unread. Thank you!

const readButtons = document.querySelectorAll(".book__read-button");
const bookList = document.querySelector(".booklist");

let library = [];

// ---------------------- Book Constructor -------------------------------
class Book {
  constructor(title, author, pages, status) {
    this.title = title;
    this.author = author;
    this.pages = pages;
    this.status = status;
  }
}

// ---------------------- Add a new book to list -------------------------------

bookList.addEventListener("submit", (event) => {
  event.preventDefault();

  const title = document.getElementById("new-book").value.trim();
  const author = document.getElementById("author").value.trim();
  const pages = document.getElementById("pages").value.trim();
  const status = document.querySelector(".book__read-button").textContent;

  if (!title) return;
  if (!author) return;
  if (!pages) return;

  const book = new Book(title, author, pages, status);

  library.push(book);

  const bookElement = document.createElement("li");
  const bookCollection = bookList.querySelector(".booklist__books");

  library.forEach((book) => {
    bookElement.classList.add("book");
    bookElement.innerHTML = DOMPurify.sanitize(` <span class="book__info"
      ><span class="title_info">${title}</span> ⏤ <span class="author_info">${author}</span> ⏤ <span class="pages_info">${pages} Pages</span></span
    >
    <button class="book__read-button">Unread</button>
    <button type="button" class="book__delete-button">
   
    </button>`);
    bookCollection.appendChild(bookElement);
    clearInputs();
    document.getElementById("new-book").focus();
  });
});

function clearInputs() {
  document.querySelector("#new-book").value = "";
  document.querySelector("#author").value = "";
  document.querySelector("#pages").value = "";
}

//-------------------Toggle Read or Unread Button --------------------------

bookList.addEventListener("click", (e) => bookRead(e));

function bookRead(event) {
  if (event.target.classList.contains("book__read-button")) {
    console.log(event.target);
    event.target.classList.toggle("clicked");
    event.target.textContent =
      event.target.textContent == "Unread" ? "Read" : "Unread";
  }
}
<!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="https://fonts.googleapis.com/css?family=Roboto:300,400,700"
    />

    <link rel="stylesheet" href="styles.css" />
    <title>Book Library</title>
  </head>
  <body>
    <main>
      <div class="top">
        <img src="img/Open Book.png" alt="open book icon" />
        <h2>Book Library</h2>
      </div>

      <form action="#" class="booklist" autocomplete="off">
        <div class="booklist__new-book">
          <div class="new-book__input-group">
            <label for="new-book">Add a Book</label>
            <input
              type="text"
              id="new-book"
              name="new-book"
              placeholder="Book name" 
            />
            <input type="text" id="author" name="author" placeholder="Author" />
            <input
              type="number"
              id="pages"
              name="pages"
              placeholder="Number of Pages" 
            />
          </div>

          <button type="submit" id="submit">
           
            <span>Add Book</span>
          </button>
        </div>

        <!-- List of Books -->
        <ul class="booklist__books">
          <li class="book">
            <span class="book__info"
              ><span class="title_info">The Catcher in the Rye</span> ⏤ <span class="author_info">J. D. Salinger</span> ⏤ <span class="pages_info">277 Pages</span></span
            >
            <button class="book__read-button">Unread</button>
            <button type="button" class="book__delete-button">
              
            </button>
          </li>
          <li class="book">
            <span class="book__info"
            >Maid | A.Sommer | 277 Pages</span
          >
          <button class="book__read-button">Unread</button>
          <button type="button" class="book__delete-button">
            
          </li>
        </ul>
        <div class="booklist__empty-state">Your Book Library is empty, add some more books!📚</div>
      </form>
    </main>
  <!-- Adds DOMPurify library -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/1.0.7/purify.min.js"></script>

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

</html>

Upvotes: 0

Views: 40

Answers (1)

vanowm
vanowm

Reputation: 10201

You can append book object into html element so you have access to it when button clicked:

const readButtons = document.querySelectorAll(".book__read-button");
const bookList = document.querySelector(".booklist");

let library = [];

// ---------------------- Book Constructor -------------------------------
class Book {
  constructor(title, author, pages, status) {
    this.title = title;
    this.author = author;
    this.pages = pages;
    this.status = status;
  }
}

// ---------------------- Add a new book to list -------------------------------

bookList.addEventListener("submit", (event) => {
  event.preventDefault();

  const title = document.getElementById("new-book").value.trim();
  const author = document.getElementById("author").value.trim();
  const pages = document.getElementById("pages").value.trim();
  const status = document.querySelector(".book__read-button").textContent;

  if (!title) return;
  if (!author) return;
  if (!pages) return;

  const book = new Book(title, author, pages, status);
  library.push(book);
  
  const bookElement = document.createElement("li");
  const bookCollection = bookList.querySelector(".booklist__books");
  //associate html element with book
  bookElement._book = book;

//  library.forEach((book) => {
    bookElement.classList.add("book");
    bookElement.innerHTML = DOMPurify.sanitize(` <span class="book__info"
      ><span class="title_info">${title}</span> ⏤ <span class="author_info">${author}</span> ⏤ <span class="pages_info">${pages} Pages</span></span
    >
    <button class="book__read-button">Unread</button>
    <button type="button" class="book__delete-button">
   
    </button>`);
    bookCollection.appendChild(bookElement);
    clearInputs();
    document.getElementById("new-book").focus();
console.log(library);
//  });
});

function clearInputs() {
  document.querySelector("#new-book").value = "";
  document.querySelector("#author").value = "";
  document.querySelector("#pages").value = "";
}

//-------------------Toggle Read or Unread Button --------------------------

bookList.addEventListener("click", (e) => bookRead(e));

function bookRead(event) {
  if (event.target.classList.contains("book__read-button")) {
    console.log(event.target);
    event.target.classList.toggle("clicked");
    event.target.textContent =
      event.target.textContent == "Unread" ? "Read" : "Unread";
    //update object
    if (event.target.parentNode._book)
      event.target.parentNode._book.status = event.target.textContent;

console.log(library);
  }
}
<!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="https://fonts.googleapis.com/css?family=Roboto:300,400,700"
    />

    <link rel="stylesheet" href="styles.css" />
    <title>Book Library</title>
  </head>
  <body>
    <main>
      <div class="top">
        <img src="img/Open Book.png" alt="open book icon" />
        <h2>Book Library</h2>
      </div>

      <form action="#" class="booklist" autocomplete="off">
        <div class="booklist__new-book">
          <div class="new-book__input-group">
            <label for="new-book">Add a Book</label>
            <input
              type="text"
              id="new-book"
              name="new-book"
              placeholder="Book name" 
            />
            <input type="text" id="author" name="author" placeholder="Author" />
            <input
              type="number"
              id="pages"
              name="pages"
              placeholder="Number of Pages" 
            />
          </div>

          <button type="submit" id="submit">
           
            <span>Add Book</span>
          </button>
        </div>

        <!-- List of Books -->
        <ul class="booklist__books">
          <li class="book">
            <span class="book__info"
              ><span class="title_info">The Catcher in the Rye</span> ⏤ <span class="author_info">J. D. Salinger</span> ⏤ <span class="pages_info">277 Pages</span></span
            >
            <button class="book__read-button">Unread</button>
            <button type="button" class="book__delete-button">
              
            </button>
          </li>
          <li class="book">
            <span class="book__info"
            >Maid | A.Sommer | 277 Pages</span
          >
          <button class="book__read-button">Unread</button>
          <button type="button" class="book__delete-button">
            
          </li>
        </ul>
        <div class="booklist__empty-state">Your Book Library is empty, add some more books!📚</div>
      </form>
    </main>
  <!-- Adds DOMPurify library -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/1.0.7/purify.min.js"></script>

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

</html>

This is not very good way achieving this though, for example you could use Map() instead of array for library where key would be the html element and value the book object:

const readButtons = document.querySelectorAll(".book__read-button");
const bookList = document.querySelector(".booklist");

let library = new Map();

// ---------------------- Book Constructor -------------------------------
class Book {
  constructor(title, author, pages, status) {
    this.title = title;
    this.author = author;
    this.pages = pages;
    this.status = status;
  }
}

// ---------------------- Add a new book to list -------------------------------

bookList.addEventListener("submit", (event) => {
  event.preventDefault();

  const title = document.getElementById("new-book").value.trim();
  const author = document.getElementById("author").value.trim();
  const pages = document.getElementById("pages").value.trim();
  const status = document.querySelector(".book__read-button").textContent;

  if (!title) return;
  if (!author) return;
  if (!pages) return;

  const book = new Book(title, author, pages, status);
  
  const bookElement = document.createElement("li");
  const bookCollection = bookList.querySelector(".booklist__books");
  library.set(bookElement, book);

//  library.forEach((book) => {
    bookElement.classList.add("book");
    bookElement.innerHTML = DOMPurify.sanitize(` <span class="book__info"
      ><span class="title_info">${title}</span> ⏤ <span class="author_info">${author}</span> ⏤ <span class="pages_info">${pages} Pages</span></span
    >
    <button class="book__read-button">Unread</button>
    <button type="button" class="book__delete-button">
   
    </button>`);
    bookCollection.appendChild(bookElement);
    clearInputs();
    document.getElementById("new-book").focus();
//  });
});

function clearInputs() {
  document.querySelector("#new-book").value = "";
  document.querySelector("#author").value = "";
  document.querySelector("#pages").value = "";
}

//-------------------Toggle Read or Unread Button --------------------------

bookList.addEventListener("click", (e) => bookRead(e));

function bookRead(event) {
  if (event.target.classList.contains("book__read-button")) {
    console.log(event.target);
    event.target.classList.toggle("clicked");
    event.target.textContent =
      event.target.textContent == "Unread" ? "Read" : "Unread";
    //update object
    const book = library.get(event.target.parentNode);
    if (book)
      book.status = event.target.textContent;

console.log(...library);
_console.textContent = JSON.stringify([...library.values()], null, 2) + "\n";
  }
}
<!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="https://fonts.googleapis.com/css?family=Roboto:300,400,700"
    />

    <link rel="stylesheet" href="styles.css" />
    <title>Book Library</title>
  </head>
  <body>
    <main>
      <div class="top">
        <img src="img/Open Book.png" alt="open book icon" />
        <h2>Book Library</h2>
      </div>

      <form action="#" class="booklist" autocomplete="off">
        <div class="booklist__new-book">
          <div class="new-book__input-group">
            <label for="new-book">Add a Book</label>
            <input
              type="text"
              id="new-book"
              name="new-book"
              placeholder="Book name" 
            />
            <input type="text" id="author" name="author" placeholder="Author" />
            <input
              type="number"
              id="pages"
              name="pages"
              placeholder="Number of Pages" 
            />
          </div>

          <button type="submit" id="submit">
           
            <span>Add Book</span>
          </button>
        </div>

        <!-- List of Books -->
        <ul class="booklist__books">
          <li class="book">
            <span class="book__info"
              ><span class="title_info">The Catcher in the Rye</span> ⏤ <span class="author_info">J. D. Salinger</span> ⏤ <span class="pages_info">277 Pages</span></span
            >
            <button class="book__read-button">Unread</button>
            <button type="button" class="book__delete-button">
              
            </button>
          </li>
          <li class="book">
            <span class="book__info"
            >Maid | A.Sommer | 277 Pages</span
          >
          <button class="book__read-button">Unread</button>
          <button type="button" class="book__delete-button">
            
          </li>
        </ul>
        <div class="booklist__empty-state">Your Book Library is empty, add some more books!📚</div>
      </form>
    </main>
    <div id="_console"></div>
  <!-- Adds DOMPurify library -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/1.0.7/purify.min.js"></script>

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

</html>

Also, in your code each time you add a book, it unnecessary recreates html for all previously added books

Upvotes: 1

Related Questions