Need help changing a value in an object within an array on the click of a button

Viewed 39

I'm building a book library and need help adjusting the "read" value for an object in the myLibrary array. When I click on the parent element's read status div, if the associated object's current read value is true it should change to false and vise versa. I added a function so when I click on the "read" div, it changes the read value for the object associated with it in the myLibrary array. The issue I'm running into is that it will only change the read value for the object in the array from true to false. If I click on the div and its associated object already has a read value of false nothing changes. The object's read value just stays false. The function I need help with is within the createCard() at the bottom where I create the "read" div. Please help! Thank you!

const library = document.querySelector('#library');

let myLibrary = [];


class Book {
  constructor(title, author, pages, read) {
    this.title = title;
    this.author = author;
    this.pages = pages;
    this.read = read;
  }
}

Book.prototype.addToLibrary = function () {
  myLibrary.push(this)
}

// myLibrary.push(new Book("The Hobbit", "J. R. R. Tolken", 471, read));
// myLibrary.push(new Book("Harry Potter", "J. K. Rowling", 381, read));
// myLibrary.push(new Book("Greenlights", "Matthew McConaughey", 252, read));

// submits the form
const addToLibraryBtn = document.querySelector('.modal-add-btn');

addToLibraryBtn.addEventListener('click', () => {
  const input = document.querySelectorAll('input')
  const title = input[0].value;
  const author = input[1].value;
  const pages = input[2].value;
  const read = document.getElementById('read').value === "Yes" ? true : false;

  const book = new Book(title, author, pages, read)
  book.addToLibrary()
  clearLibrary()
  createStoredCards()
  closeModal()
  clearForm()
})

// clears the display and re-adds cards in myLibrary array so duplicate cards are not created
const clearLibrary = () =>
  library.innerHTML = ""

// clears form inputs
const clearForm = () => {
  const form = document.querySelector('form')
  form.reset()
}

// Creates the look of the card and information that each card displays
function createCard(book) {

  const card = document.createElement('div');
  card.classList.add('card');

  // Adding the remove button and function
  const removeBtn = document.createElement('div');
  removeBtn.classList.add('remove-btn');
  removeBtn.innerText = 'Remove';
  card.appendChild(removeBtn);

  // Removes card from the array and the display
  removeBtn.addEventListener('click', () => {
    deleteBook(myLibrary.indexOf(book), card)
  })

  // Adding the title 
  let title = document.createElement('div');
  title.classList.add('card-title');
  title.innerHTML = `Title: <span>${book.title}</span>`;
  card.appendChild(title);

  // Adding the author
  let author = document.createElement('div');
  author.classList.add('card-author');
  author.innerHTML = `Author: <span>${book.author}</span>`;
  card.appendChild(author);

  // Adding the page count
  let pages = document.createElement('div');
  pages.classList.add('card-count');
  pages.innerHTML = `Page Count: <span>${book.pages}</span>`;
  card.appendChild(pages);

  // Adding the read status
  let read = document.createElement('div');
  read.classList.add('card-read');
  read.innerHTML = `Read Status: <span class="read-status">${book.read === true ? "Read" : "Not read"}</span>`;
  card.appendChild(read);
  read.addEventListener('click', () => {
    myLibrary[myLibrary.indexOf(book)].read = true ? false : true;

    clearLibrary()
    createStoredCards()
  })

  library.appendChild(card);
}

// creates a card for each book in the myLibrary array and displays the card in the users library
function createStoredCards() {
  myLibrary.forEach(book => {
    createCard(book);
  })
}

// function that removes book
function deleteBook(bookIndex, card) {
  myLibrary.splice(bookIndex, 1);
  card.remove();
}

// Open and close modal form

const addBookBtn = document.querySelector('.add-btn');
const modal = document.querySelector('.modal');
const closeBtn = document.querySelector('.close-modal');

addBookBtn.addEventListener('click', () => {
  modal.style.display = "flex";
})

const closeModal = () => modal.style.display = 'none'

window.addEventListener('click', (e) => {
  if (e.target == modal) {
    closeModal();
  }
})

closeBtn.addEventListener('click', () => {
  closeModal();
})
1 Answers

The problem is in your ternary conditional operator, here:

read.addEventListener('click', () => {
  myLibrary[myLibrary.indexOf(book)].read = true ? false : true;

  clearLibrary()
  createStoredCards()
})

When you write ...read = true ? false : true, this is what happens:

  1. This is an assignment statement (=), so it will evaluate all that is at the rigt of the assignment operator;
  2. Then you have your ternary conditional operator. It works like this:
  • It check if the expression before ? (called condition) evaluates to true or false.
  • If the condition evaluates to true (see truthy), the result of the ternary expression is whatever is before the :.
  • If the condition evaluates to false (see falsy), the result of the ternary expression is whatever is after the :.
  1. In your case, it is true ? false : true. The condition here is simply the constant true, which always evaluates to true. Hence, the result of the ternary expression will always be false, and that will be assigned to the .read property on every click.

To fix your code, you have to check inside the condition expression, if .read is truthy. Like this:

wasRead = myLibrary[myLibrary.indexOf(book)].read
myLibrary[myLibrary.indexOf(book)].read = wasRead ? false : true;

But actually, the operation you are doing is a very common one, know as "toggle". For toggling a boolean value, you just need to negate (!) is current value (if you do !true, you get false, and vice versa).

wasRead = myLibrary[myLibrary.indexOf(book)].read
myLibrary[myLibrary.indexOf(book)].read = !wasRead

Moreover, I don't see the point of this big expression to get the .read property of book by getting the index on the librady. You already have a reference to the book object! Why not just this?

book.read = !book.read
Related