Sorry for my English.I have an array of items, that are being rendered on my web-page. Each item has a delete button, but how can I anchor a click on a button to the item, that it(button) belongs to? I mean: how can I delete exactly that item, which button I clicked? Do I need to add IDs to my items, if so, how can I do that? Preferably without server or React, just JS Looking forward for your help!
From my CodePen
HTML
<section class="main">
<div class="container">
<h1 class="mb-3">Details storage</h2>
<form class="mb-3" action="" id="add-detail">
<div class="mb-3">
<input required class='form-control' type="number" placeholder="Detail Code" id="input-key">
</div>
<div class="mb-3">
<input required class='form-control' type="text" placeholder="Category" id="input-category">
</div>
<div class="mb-3">
<input required class='form-control' type="number" placeholder="Amount" id="input-amount">
</div>
<div class="mb-3">
<input required class='form-control' type="number" placeholder="Price per piece" id="input-price">
</div>
<button class='btn btn-primary'>Add</button>
</form>
<table class="table table-striped detailsTable">
<thead>
<th data-column="key">Detail Code</th>
<th data-column="category">Category</th>
<th data-column="amount">Amount</th>
<th data-column="price">Price per piece</th>
<th data-column="totalPrice">Total amount</th>
<th></th>
</thead>
<tbody id="details-list">
</tbody>
</table>
</div>
</section>
JS
class Detail {
constructor(key, category, amount, price) {
this.key=key
this.category=category
this.amount=amount
this.price=price
}
get totalPrice() {
return (this.amount * this.price);
}
}
const details=[
new Detail(0,'Nails',300,4),
new Detail(1,'Screws',400,6),
new Detail(2,'Bolts',600,5),
new Detail(3,'Self-tapping screw',700,3),
new Detail(4,'Nails', 400, 2)
]
const $detailsList = document.getElementById('details-list'),
$detailsListTHALL = document.querySelectorAll('.detailsTable th')
let column = 'key',
columnDir = true
function newDetailTR(detail){
const $detailTR= document.createElement('tr'),
$keyTD= document.createElement('td'),
$categoryTD= document.createElement('td'),
$amountTD= document.createElement('td'),
$priceTD= document.createElement('td'),
$totalPriceTD=document.createElement('td'),
$deleteTD=document.createElement('button')
$keyTD.textContent=detail.key
$categoryTD.textContent=detail.category
$amountTD.textContent=detail.amount
$priceTD.textContent=detail.price
$totalPriceTD.textContent = detail.totalPrice
$deleteTD.textContent="Delete"
$detailTR.append($keyTD)
$detailTR.append($categoryTD)
$detailTR.append($amountTD)
$detailTR.append($priceTD)
$detailTR.append($totalPriceTD)
$detailTR.append($deleteTD)
return $detailTR;
}
function getSortDetails(prop, dir) {
const detailsCopy=[...details]
return detailsCopy.sort(function(detailA, detailB){
if((!dir==false? detailA[prop] <detailB[prop] : detailA[prop] > detailB[prop])) return -1;
})
}
function render(){
let detailsCopy=[...details];
detailsCopy=getSortDetails(column, columnDir);
$detailsList.innerHTML = '';
for(const detail of detailsCopy){
$detailsList.append(newDetailTR(detail))
}
}
$detailsListTHALL.forEach(elment => {
elment.addEventListener('click', function() {
column = this.dataset.column;
columnDir = !columnDir;
render()
})
})
document.getElementById('add-detail').addEventListener('submit', function(event){
event.preventDefault()
details.push(new Detail(
Number(document.getElementById('input-key').value),
document.getElementById('input-category').value,
Number(document.getElementById('input-amount').value),
Number(document.getElementById('input-price').value)
))
render()
alert('Item has been added!')
event.preventDefault();
event.target.reset();
})
render()
When you create your TR element, assign a click to it; basically like this (by using a reusable function elNew
to create new DOM elements):
const $detailTR = elNew('tr')
const $deleteButton = elNew('button', {
textContent: "Delete",
onclick() {
removeDetail(detail); // Remove from array
$detailTR.remove(); // Remove from HTML
}
});
also, don't forget to:
Example:
// DOM utility functions:
const el = (sel, par = document) => par.querySelector(sel);
const els = (sel, par = document) => par.querySelectorAll(sel);
const elNew = (tag, prop) => Object.assign(document.createElement(tag), prop);
class Detail {
constructor(key, category, amount, price) {
this.key = key;
this.category = category;
this.amount = amount;
this.price = price;
}
get totalPrice() {
return (this.amount * this.price);
}
}
const details = [
new Detail(0, 'Nails', 300, 4),
new Detail(1, 'Screws', 400, 6),
new Detail(2, 'Bolts', 600, 5),
new Detail(3, 'Self-tapping screw', 700, 3),
new Detail(4, 'Wheels', 400, 2),
];
const $detailsList = el('#details-list');
const $detailsListTHALL = els('.detailsTable th');
let column = 'key';
let columnDir = true;
function removeDetail(detail) {
const index = details.indexOf(detail);
if (index > -1) details.splice(index, 1);
}
function newDetailTR(detail) {
const $detailTR = elNew('tr'),
$keyTD = elNew('td', { textContent: detail.key }),
$categoryTD = elNew('td', { textContent: detail.category }),
$amountTD = elNew('td', { textContent: detail.amount }),
$priceTD = elNew('td', { textContent: detail.price }),
$totalPriceTD = elNew('td', { textContent: detail.totalPrice }),
$deleteTD = elNew('td'),
$deleteButton = elNew('button', {
textContent: "Delete",
onclick() {
removeDetail(detail); // Remove from array
$detailTR.remove(); // Remove from HTML
}
});
$deleteTD.append($deleteButton);
$detailTR.append($keyTD, $categoryTD, $amountTD, $priceTD, $totalPriceTD, $deleteTD);
return $detailTR;
}
function getSortDetails(prop, dir) {
return details.sort(function(a, b) {
if((!dir==false? a[prop] < b[prop] : a[prop] > b[prop])) return -1;
});
}
function render() {
const detailsCopy = getSortDetails(column, columnDir);
$detailsList.innerHTML = "";
details.forEach(detail => $detailsList.append(newDetailTR(detail)));
}
el('#add-detail').addEventListener('submit', function(event){
event.preventDefault();
details.push(new Detail(
el('#input-key').valueAsNumber,
el('#input-category').value,
el('#input-amount').valueAsNumber,
el('#input-price').valueAsNumber
));
render();
event.target.reset();
})
render();
<section class="main">
<div class="container">
<h1 class="mb-3">Details storage</h2>
<form class="mb-3" action="" id="add-detail">
<div class="mb-3">
<input required class='form-control' type="number" placeholder="Detail Code" id="input-key">
</div>
<div class="mb-3">
<input required class='form-control' type="text" placeholder="Category" id="input-category">
</div>
<div class="mb-3">
<input required class='form-control' type="number" placeholder="Amount" id="input-amount">
</div>
<div class="mb-3">
<input required class='form-control' type="number" placeholder="Price per piece" id="input-price">
</div>
<button class='btn btn-primary'>Add</button>
</form>
<table class="table table-striped detailsTable">
<thead>
<th data-column="key">Detail Code</th>
<th data-column="category">Category</th>
<th data-column="amount">Amount</th>
<th data-column="price">Price per piece</th>
<th data-column="totalPrice">Total amount</th>
<th></th>
</thead>
<tbody id="details-list"></tbody>
</table>
</div>
</section>