0

I am creating a library where you can store and remove books. I have a loop that goes through an array of books and displays them in HTML. However, when I try to remove them with the onlick function below, sometimes it works and sometimes, I'm assuming in a certain order - I get an error and the wrong item is removed.

For example, if I remove theLibrary[2] first, then I can remove the others without problems. But if I try to remove theLibrary[1] after removing theLibrary[0] succesfully, it removes theLibrary[2]. Then, if I try to remove theLibrary[1] again I get this error:

scripts.js:76 Uncaught TypeError: Cannot read property 'title' of undefined at HTMLButtonElement.toggleRemove.onclick (scripts.js:76)

Here is the code block where the problem occurs. The library is an array with book objects stored in them:

toggleRemove.onclick = function() {

                    // this is where problems occur
                    removedBook = document.getElementById(`${theLibrary[i].title}`);
                    console.log(removedBook);
                    
                    bookRemoved = theLibrary[i];
                    console.log(bookRemoved);
                    bookRemoved.removeSelf();

                    removedBook.remove();
                    console.table(theLibrary);

                    

                }

Here is the entire DOM element creation & display block to show where these elements are coming from:

function showLib() {
    for (let i = 0; i < theLibrary.length; i++) {

            item = document.createElement('div'); 
            bookTitle = document.createElement('h4'); 
            bookAuthor = document.createElement('h4'); 
            bookPages = document.createElement('h4'); 
            bookRead = document.createElement('h4'); 
            toggleRemove = document.createElement('button');
            
            item.classList.add('item');
            
            // add id's to items and buttons to associate with DOM
            toggleRemove.setAttribute('id', `${theLibrary[i].title}`);
            item.setAttribute('id', `${theLibrary[i].title}`);
            removeName = document.querySelector(`#${theLibrary[i].title}`);

            
            bookTitle.textContent = `'${theLibrary[i].title}'` 
            bookAuthor.textContent = `by ${theLibrary[i].author}`
            bookPages.textContent = `${theLibrary[i].pages} pages` 
    
                if (theLibrary[i].read === true) {
                    bookRead.textContent = 'Has been read';
                }
                else {
                    bookRead.textContent = 'Has not been read';
                }

            toggleRemove.textContent = 'Remove Book';
            
                item.appendChild(bookTitle); 
                item.appendChild(bookAuthor); 
                item.appendChild(bookPages);
                item.appendChild(bookRead); 
                item.appendChild(toggleRemove);

                libContainer.append(item); 

                toggleRemove.onclick = function() {

                    // this is where problems occur
                    removedBook = document.getElementById(`${theLibrary[i].title}`);
                    console.log(removedBook);
                    
                    bookRemoved = theLibrary[i];
                    console.log(bookRemoved);
                    bookRemoved.removeSelf();

                    removedBook.remove();
                    console.table(theLibrary);

                    

                }
    }
}

I would appreciate any tips you can give me to push me in the right direction. Thanks!

BlackICE
  • 8,816
  • 3
  • 53
  • 91
Connor C
  • 5
  • 3
  • 2
    Use [event delegation](//developer.mozilla.org/docs/Learn/JavaScript/Building_blocks/Events#Event_delegation) instead of assigning multiple event listeners — it’s more maintainable, and applies to dynamically added elements. E.g., use an [event argument](//developer.mozilla.org/docs/Web/API/EventTarget/addEventListener#The_event_listener_callback)’s [`target`](//developer.mozilla.org/docs/Web/API/Event/target). See [the tag info](/tags/event-delegation/info) and [What is DOM Event delegation?](/q/1687296/4642212). – Sebastian Simon Aug 02 '21 at 15:12
  • `toggleRemove.onclick = function() { removedBook document.getElementById (`${theLibrary[i].title}`)}` shoudn't be in the for loop. What you basically do is override it. – Mike Aug 02 '21 at 15:44
  • @HoangLe But I wouldn't be able to access the specified book if I didn't put it in the loop as well. I use library[i] to dynamically select the book, I'm not sure how to do it another way. – Connor C Aug 02 '21 at 16:09
  • Your issue appears to be the dom indexing is "static", in that it's rendered once when your loop is run, but the array behind the library gets updated when you remove a book, so if you have 3 books to start, index 0, 1, 2 and you remove the first book, you're now left with a library of index 0, 1, but your dom has indexes pointing to items 1, 2 in the array. – BlackICE Aug 02 '21 at 18:40

0 Answers0