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" >Read</button></td>'
}
else if(b.ReadOrNot == 'Not read'){
content = '<td><button id="readbtn" >Not read</button></td>'
}
content = '<td><button 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>
CodePudding user response:
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
anddelete
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 itsstatus
value.1b) To delete a book you will need to
find the index
of the book, and thensplice
that book from the books array.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>
CodePudding user response:
Try use pop method:
function deleteLastBookToLibrary() {
myLibrary.pop()
}
CodePudding user response:
Following a simple approach and just defining your already declared toggleDelete()
function.
- 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" >Read</button></td>'
} else if (b.ReadOrNot == 'Not read') {
content = '<td><button id="readbtn" >Not read</button></td>'
}
content = '<td><button 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>
- 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" >Read</button></td>'
} else if (b.ReadOrNot == 'Not read') {
content = '<td><button id="readbtn" >Not read</button></td>'
}
content = '<td><button 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>