I have a button "-" that when on click, it creates an "X" button on the corner of my "books" to delete them. Is there a way to make it so that when I click the "-" button again it toggles between hiding and displaying the "X" button in the corner of the "books"?
No JQuery please, still have not learned how to use it
here is my HTML:
<div class="container">
<div class="book-display">
<div class="title">Title:</div>
<div class="author">Author:</div>
<div class="pages">Pages:</div>
<div class="read">Have Read:</div>
</div>
<div class="shelf"></div>
<div class="buttons">
<button class="button" id="delete">➖</button>
<button class="button" id="add">➕</button>
</div>
and here is my Javascript:
//Add Books to Shelf Display
function addBookToShelf() {
for (let i = 0; i < myLibrary.length; i++) {
const books = document.createElement('div');
books.classList.add('books');
books.setAttribute('id', myLibrary[i].title)
if (myLibrary[i].read === "Not Read") {
books.style.background = "rgba(71, 22, 10, 0.664)"
};
if (myLibrary[i].read === "Partially Read") {
books.style.background = "rgba(199, 199, 58, 0.575)"
}
const booksText = document.createElement('div');
booksText.classList.add('book-text')
booksText.addEventListener('click', () => {
bookTitleEl.innerHTML = "Title: " + myLibrary[i].title;
bookAuthorEl.innerHTML = "Author: " + myLibrary[i].author;
bookPagesEl.innerHTML = "Pages: " + myLibrary[i].pages;
bookReadEl.innerHTML = "Have Read: " + myLibrary[i].read;
});
booksText.innerHTML = myLibrary[i].title;
shelfEl.appendChild(books);
books.appendChild(booksText);
document.getElementById(myLibrary[i].title).setAttribute('value', 1);
//Add delete button to books function
function deleteXButton() {
const deleteXEl = document.createElement('button');
deleteXEl.classList.add('deleteX');
books.appendChild(deleteXEl);
deleteXEl.innerHTML = "X"
document.getElementsByClassName('deleteX');
if (document.getElementsByClassName('deleteX').length > myLibrary.length) {
deleteXEl.remove();
}
if (deleteXEl.style.display === "block") {
deleteXEl.style.display = "none";
} else {
deleteXEl.style.display = "block";
}
//Delete Book from Shelf & Object from Libray Array
deleteXEl.addEventListener('click', () => {
const bookIndex = myLibrary.indexOf(myLibrary[i])
books.remove(delete myLibrary[bookIndex]);
noBookFound();
});
}
//DELETE BUTTON EVENT LISTENER
deleteButtonEl.addEventListener('click', () => {
deleteXButton();
});
}
};
Any and all help would be greatly appreciate it!
The classList API has a toggle method that we can use to toggle styles. If you include a class that removes elements from the DOM (as with display: none
), this becomes an easy way to hide/show your elements in response to a user action. You can see how this works in the toggleDeleteButtons
function in the snippet.
I made a bunch of other suggested modifications to your code, which you are free to take or leave on an à la carte basis. Btw, the link above goes to MDN, which is a great site to search for any unfamiliar web-dev term (e.g, you'd just google "MDN findIndex" to learn about the findIndex
method of Arrays.)
// Identifies some DOM elements globally
const
deleteBooksButton = document.getElementById("delete"),
addBookButton = document.getElementById("add"),
shelfEl = document.getElementsByClassName("shelf")[0],
deleteButtons = document.getElementsByClassName("delete-button");
// Declares the library globally, and populates it with sample books
let library;
library = getSampleLibrary(library);
addBooksToShelf(library);
// Calls toggleDeleteButtons when deleteBooksButton is clicked
deleteBooksButton.addEventListener("click", toggleDeleteButtons);
// Calls deleteBook when anything inside shelf is clicked
shelfEl.addEventListener("click", deleteBook);
// Defines function to show/hide all delete buttons
function toggleDeleteButtons(){
for(let button of deleteButtons){
button.classList.toggle("hidden");
}
}
// Defines function to delete a book (Click events bubble up to `shelf`)
function deleteBook(event){
// Makes sure the click event was on a delete-button before proceeding
const clickedThing = event.target;
if(!clickedThing.classList.contains("delete-button")){ return; }
// Searches upward in DOM tree for bookEl, then downward for title
const
bookEl = clickedThing.closest(".book"),
title = bookEl.querySelector(".title").textContent;
// Removes bookEl from the DOM tree
bookEl.remove();
// Looks in library array for book object with matching title property
const libraryIndex = library.findIndex(book => book.title == title);
// Removes book object from library if there was a match
if(libraryIndex > -1){
library.splice(libraryIndex, 1);
}
}
// Defines function to populate shelf's DOM tree with book-related elements
function addBooksToShelf(library) {
// Loops through elements of library array (referring to each as `book`)
for (let book of library) {
// Uses "destructuring" to get local variables bound to props of book
const { title, author, pages, read } = book;
// Creates bookEl and its descendants
// bookEl will have 3 children: deleteDiv, teaserEl, and detailsEl
// deleteDiv will have 1 child: deleteButton
// detailsEl will have 4 div children (title, author, pages, and read)
// (The 4 divs inside detailsEl will each have 1 span child)
const
bookEl = document.createElement("div"), // Will have class: "book"
deleteDiv = document.createElement("div"), // ... "delete-div"
teaserEl = document.createElement("div"), // ... "teaser"
detailsEl = document.createElement("div"), // ... "text"
titleDiv = document.createElement("div"),
authorDiv = document.createElement("div"),
pagesDiv = document.createElement("div"),
readDiv = document.createElement("div"),
titleSpan = document.createElement("span"), // ... "title"
authorSpan = document.createElement("span"), // ... "author"
pagesSpan = document.createElement("span"), // ... "pages"
readSpan = document.createElement("span"); // ... "read"
// Creates and configures deleteButton, and appends it to deleteDiv
deleteButton = document.createElement("button");
deleteButton.classList.add("delete-button");
deleteButton.classList.add("hidden");
deleteButton.textContent = "X";
deleteDiv.appendChild(deleteButton);
// Configures deleteDiv, and appends it to bookEl
deleteDiv.classList.add("delete-div");
bookEl.appendChild(deleteDiv);
// Configures teaserEl, and appends it to bookEl
teaserEl.innerHTML = title;
teaserEl.classList.add("teaser"); // teaser class
bookEl.appendChild(teaserEl);
// Configures the spans
titleSpan.classList.add("title");
authorSpan.classList.add("author");
pagesSpan.classList.add("pages");
readSpan.classList.add("read");
titleSpan.textContent = title;
authorSpan.textContent = author;
pagesSpan.textContent = pages;
readSpan.textContent = read;
// Populates divs (w/ label text and spans), and adds them to detailsEl
titleDiv.innerHTML = "Title: " + titleSpan.outerHTML;
authorDiv.innerHTML = "Author: " + authorSpan.outerHTML
pagesDiv.innerHTML = "Pages: " + pagesSpan.outerHTML
readDiv.innerHTML = "Have Read: " + readSpan.outerHTML
detailsEl.appendChild(titleDiv);
detailsEl.appendChild(authorDiv);
detailsEl.appendChild(pagesDiv);
detailsEl.appendChild(readDiv);
// Configures detailsEl, and appends it to bookEl
detailsEl.classList.add('text'); // text class
detailsEl.classList.add("hidden"); // detailsEl & children are hidden
bookEl.appendChild(detailsEl);
// Configures bookEl (w/ styles, listener, etc), and adds it to shelf
const
readBG = "rgba(22, 71, 10, 0.420)",
notReadBG = "rgba(71, 22, 10, 0.664)",
partReadBG = "rgba(199, 199, 58, 0.575)";
if (read === "Partially Read") { bookEl.style.background = partReadBG; }
else if (read === "Not Read") { bookEl.style.background = notReadBG; }
else { bookEl.style.background = readBG; }
bookEl.id = title; // (Careful: Book titles are not unique identifiers!)
bookEl.classList.add("book");
bookEl.setAttribute("data-value", 1); // (Custom attributes use "data-")
bookEl.addEventListener('click', toggleText); // Listener on book
shelfEl.appendChild(bookEl);
}
};
// Defines function to show text and hide teaser (or vice versa)
function toggleText(event){
// Searches upward in DOM tree (from clicked element) to get closest book
const bookEl = event.target.closest(".book");
// Searches downward in DOM tree to find teaser & text, and update classes
bookEl.querySelector(".teaser").classList.toggle("hidden");
bookEl.querySelector(".text").classList.toggle("hidden");
}
// Defines function to return a sample library
function getSampleLibrary(library){
const sampleLibrary = [
{
title: "Harry Potter and the Methods of Rationality",
author: "Yudkowsky, Eliezer",
pages: 750,
read: "Read"
},
{
title: "Go, Dog. Go!",
author: "Eastman, P.D.",
pages: 16,
read: "Partially Read"
}
];
library = sampleLibrary;
return library;
}
.shelf{ width: 350px; }
.book{ margin-top: 0.5em; padding: 0.5em; }
.delete-div{ text-align: right; } /* divs exist only to align buttons */
.delete-button{ border: 1px solid grey; border-radius: 0.3em; }
.hidden{ display: none; }
<div class="container">
<div class="buttons">
<button id="delete">Delete Books ➖</button>
<button class="button" id="add">Add Book ➕</button>
</div>
<div class="shelf"></div>
</div>