1

i have a simple library app. i have an array that contains all my "book" objects and will also have functionality to add more objects to the array which will then be displayed as table rows. I need a delete function that targets the rows the the table but also newly created rows.

function Book(name, author, ReadOrNot) {
    this.name = name
    this.author = author
    this.ReadOrNot = ReadOrNot
}

const book1 = new Book("The Hobbit", "J.R.R Tolkien", "Read")
const book2 = new Book("A Game of Thrones", "George R.R. Martin", "Not read")
const book3 = new Book("Jane Eyre", "Charlotte Brontë", "Read")

let myLibrary = []

function addBookToLibrary(...arr) {
 myLibrary.push(...arr)
}

addBookToLibrary(book1)
addBookToLibrary(book2)
addBookToLibrary(book3)


function addBookToTable(){
    let tbody = document.querySelector('tbody')
    myLibrary.forEach(b =>{
      let tr = document.createElement('tr')
      let content = '<td>' + b.name + '</td><td>' + b.author + '</td>'
      if(b.ReadOrNot == 'Read'){
        content += '<td><button id="readbtn" class="btn rdbtn">Read</button></td>'  
       }
       else if(b.ReadOrNot == 'Not read'){
         content += '<td><button id="readbtn" class="btn rdbtn">Not read</button></td>'
       }
       content += '<td><button class="btn delbtn" onclick="toggleDelete()">Delete</button></td>'
      tr.innerHTML = content
      tbody.appendChild(tr)
     })
  }
  
  addBookToTable()
<table>
        <thead>
            <tr>
                <td>Name</td>
                <td>Author</td>
                <td>Status</td>
                <td>      </td>
            </tr>
        </thead>
       
        <tbody>
            
        </tbody>
    </table>

2
  • You want delete function only which will delete a targeted row? Commented Oct 6, 2022 at 18:16
  • Yes. every row will have a delete button that removes the targeted row Commented Oct 6, 2022 at 19:23

3 Answers 3

1

Following a simple approach and just defining your already declared toggleDelete() function.

  1. Remove a row

function Book(name, author, ReadOrNot) {
  this.name = name
  this.author = author
  this.ReadOrNot = ReadOrNot
}

const book1 = new Book("The Hobbit", "J.R.R Tolkien", "Read")
const book2 = new Book("A Game of Thrones", "George R.R. Martin", "Not read")
const book3 = new Book("Jane Eyre", "Charlotte Brontë", "Read")

let myLibrary = []

function addBookToLibrary(...arr) {
  myLibrary.push(...arr)
}

addBookToLibrary(book1)
addBookToLibrary(book2)
addBookToLibrary(book3)


function addBookToTable() {
  let tbody = document.querySelector('tbody')
  myLibrary.forEach(b => {
    let tr = document.createElement('tr')
    let content = '<td>' + b.name + '</td><td>' + b.author + '</td>'
    if (b.ReadOrNot == 'Read') {
      content += '<td><button id="readbtn" class="btn rdbtn">Read</button></td>'
    } else if (b.ReadOrNot == 'Not read') {
      content += '<td><button id="readbtn" class="btn rdbtn">Not read</button></td>'
    }
    content += '<td><button class="btn delbtn" onclick="toggleDelete(this)">Delete</button></td>'
    tr.innerHTML = content
    tbody.appendChild(tr)
  })
}
addBookToTable()

function toggleDelete(o) {
  var p = o.parentNode.parentNode;
  p.parentNode.removeChild(p);
}
.hide-row {
  visibility: hidden;
}
<table>
  <thead>
    <tr>
      <td>Name</td>
      <td>Author</td>
      <td>Status</td>
      <td> </td>
    </tr>
  </thead>
  <tbody>
  </tbody>
</table>

  1. Hide/Show a row

function Book(name, author, ReadOrNot) {
  this.name = name
  this.author = author
  this.ReadOrNot = ReadOrNot
}

const book1 = new Book("The Hobbit", "J.R.R Tolkien", "Read")
const book2 = new Book("A Game of Thrones", "George R.R. Martin", "Not read")
const book3 = new Book("Jane Eyre", "Charlotte Brontë", "Read")

let myLibrary = []

function addBookToLibrary(...arr) {
  myLibrary.push(...arr)
}

addBookToLibrary(book1)
addBookToLibrary(book2)
addBookToLibrary(book3)


function addBookToTable() {
  let tbody = document.querySelector('tbody')
  myLibrary.forEach(b => {
    let tr = document.createElement('tr')
    let content = '<td>' + b.name + '</td><td>' + b.author + '</td>'
    if (b.ReadOrNot == 'Read') {
      content += '<td><button id="readbtn" class="btn rdbtn">Read</button></td>'
    } else if (b.ReadOrNot == 'Not read') {
      content += '<td><button id="readbtn" class="btn rdbtn">Not read</button></td>'
    }
    content += '<td><button class="btn delbtn" onclick="toggleDelete(this)">Hide</button></td>'
    tr.innerHTML = content
    tbody.appendChild(tr)
  })
}
addBookToTable()

function toggleDelete(o) {
  var p = o.parentNode.parentNode;
  p.childNodes.forEach(elements => {
    elements.classList.toggle('hide-row');
  })
  p.childNodes[3].style = 'visibility : visible !important';
  if (p.childNodes[3].childNodes[0].parentNode.classList[0] == "hide-row") {
    p.childNodes[3].childNodes[0].innerHTML = 'Show';
  } else {
    p.childNodes[3].childNodes[0].innerHTML = 'Hide';
  }
}
.hide-row {
  visibility: hidden;
}
<table>
  <thead>
    <tr>
      <td>Name</td>
      <td>Author</td>
      <td>Status</td>
      <td> </td>
    </tr>
  </thead>
  <tbody>
  </tbody>
</table>

Sign up to request clarification or add additional context in comments.

Comments

1
  1. You want to be able to identify each book by an id which you'll have to insert somewhere into your book object at some point. When you create your update and delete functions you'll be able to use that id to update the books array.

    1a) To update the status of a book you can find the book in the books array, and then simply update its status value.

    1b) To delete a book you will need to find the index of the book, and then splice that book from the books array.

  2. When the books array is updated you will also need to re-render the HTML. And you can do that with the function you already have (although I've changed it in this example to use template strings. In the HTML you'll need to add a couple of data attributes: the first to indicate the type (update/delete), and the second to indicate the book/row id.

Now, to make this all a bit easier it might make sense to create a new class called Library to which you can add books, handles all the book operations, and also creates the new HTML when a book is updated/deleted.

Note: I've used a class here instead of a function constructor to make the code a little easier to understand. Whether you keep working with constructors the principles as to how update/delete the books will remain the same.

// New class!
class Library {
  
  // It accepts a root element - the tbody element
  // It creates a books array, and then adds an event listener
  // to the root element (ensuring we bind `this` properly)
  constructor(el) {
    this.books = [];
    this.el = el;
    this.el.addEventListener('click', this.handleClick.bind(this));
  }

  // When the root element catches an event from one of its
  // child elements we check to see if it's a button
  // and then checks its type: either `update` or `delete`, and
  // calls a library method with the book it accordingly.
  handleClick(e) {
    if (e.target.matches('button')) {
      const { dataset: { id, type } } = e.target;
      if (type === 'update') {
        this.updateBook(id);
      }
      if (type === 'delete') {
        this.deleteBook(id);
      }
      this.updateHtml();
    }
  }

  // When you add a book we automatically assign
  // an id to it (the current length of the books array + 1)
  // We update the table
  addBook(book) {
    this.books.push({
      ...book,
      id: this.books.length + 1
    });
    this.updateHtml();
  }
  
  // If the update button was clicked we `find` it in the
  // books array, and set its status to either true/false
  updateBook(id) {
    const found = this.books.find(book => {
      return +book.id === +id;
    });
    if (found) found.status = !found.status;
  }

  // If the delete button was clicked we find the index
  // of the book in the books array, and then `splice` it out
  deleteBook(id) {
    const index = this.books.findIndex(book => {
      return book.id === +id;
    });
    if (index >= 0) this.books.splice(index, 1);
  }

  // Creates a new set of HTML from the books array, and
  // replaces the innerHTML of the root element with it
  // For each row we add the data attributes for the type, and
  // the id. Each of which will be used in the library's `handleClick`
  // method
  updateHtml() {
    this.html = this.books.map(book => {
      return `
        <tr>
          <td>${book.name}</td>
          <td>${book.author}</td>
          <td>
            <button data-type="update" data-id="${book.id}">
              ${book.status ? 'Read' : 'Not read'}
            </button>
          </td>
          <td>
            <button data-type="delete" data-id="${book.id}">
              Delete
            </button>
          </td>
        </tr>
      `;
    }).join('');

    this.el.innerHTML = this.html;

  }

}

// Creates a book object
class Book {
  constructor(name, author) {
    this.name = name;
    this.author = author;
    this.status = false;
  }
}


// Cache the root element (the table body)
const tbody = document.querySelector('tbody');

// Create a new library from the Library class passing
// in the root element
const library = new Library(tbody);

// Use the library `addBook` method to add new books
library.addBook(new Book('The Hobbit', 'J.R.R Tolkien'));
library.addBook(new Book('A Game of Thrones', 'George R.R. Martin'));
library.addBook(new Book('Jane Eyre', 'Charlotte Brontë'));
table { width: 100%; border-collapse: collapse; border: 1px solid #dfdfdf; }
td { width: 24%; padding: 0.2em; border: 1px solid #efefef;}
<table>
  <thead>
    <tr>
      <td>Name</td>
      <td>Author</td>
      <td>Status</td>
      <td></td>
    </tr>
  </thead>
  <tbody>
  </tbody>
</table>

Comments

0

Try use pop method:

 function deleteLastBookToLibrary() {
     myLibrary.pop()
 }

1 Comment

the pop method removes the last element/object in an array right? these objects, which are displayed as rows when entered into the array, all have a delete button. the button should remove the row.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.