I started learning OOP in JavaScript at school and I have to do my homework in OOP. It is a shopping list, one fills in a product and price and that is put into an array, the array its contents are put in a table in HTML. The list also has got delete buttons for every product, I have thought about using this
in JavaScript, as I am working in OOP, but I am sceptic because of the scope.
The idea is that one clicks "verwijder" on the webpage (EDIT: in the corresponding row) and the table row is gone. I have thought about using this
but also about dynamically updating the table after removing the selected row from the array.
Who can advise me about what to do and how to do that correctly? I have uploaded my JavaScript here: http://jsfiddle.net/hNAZ9/
Mainly, it is about this piece of code:
function ShoppingList(){
this.items = [];
this.setItem = function(product, price){
var item = new Item(product, price);
this.items.push(item);
};
this.render = function(){
var placeHolder = document.getElementById("shoppingList");
placeHolder.innerHTML = "";
for(var i = 0; i <this.items.length; i++){
var tr = document.createElement("tr");
tr.id = i;
var tdProduct = document.createElement("td");
tdProduct.innerHTML = this.items[i].product;
tr.appendChild(tdProduct);
var tdPrice = document.createElement("td");
tdPrice.innerHTML = this.items[i].price;
tr.appendChild(tdPrice);
var tdDel = document.createElement("td");
tdDel.innerHTML = "Verwijder";
tdDel.addEventListener("click", delItem, false);
tr.appendChild(tdDel);
placeHolder.appendChild(tr);
}
};
}
function delItem(e){
e.preventDefault();
// What do I have to do here?
}
1 Answer 1
The trick is linking a row to its item object and vice-versa, so both are removed/added in lockstep.
There are a lot of ways of going about that, but given your original code, the following should be a pretty good way to go.
I'd suggest using a closure when defining the event handler to make things simpler. Here's a simple demo and here's the code
function ShoppingList() {
var that = this, // keep a scope reference
table = document.getElementById("shoppingList"); // find this once (only works if the page has been loaded already)
this.items = [];
// this adds an item to the array and a row to the table
this.addItem = function (product, price) {
var item = new Item(product, price);
this.items.push(item);
table.appendChild(buildRow(item));
};
// this removes the given item from the array and the table
this.removeItem = function (item) {
for(var i = 0 ; i < this.items.length ; i++) {
if(this.items[i] === item) {
this.items.splice(i, 1);
break; // skip the rest of the loop, since we've found what we need
}
}
table.removeChild(item.row); // remove the row
}
// this isn't actually needed as rows get added by addItem,
// but it'll work just fine regardless
this.render = function(){
table.innerHTML = "";
for(var i = 0; i < this.items.length; i++){
table.appendChild(buildRow(this.items[i]));
}
};
// an internal helper. This can be moved to the Item prototype
// since it's not actually dependent on anything in ShoppingList
function buildRow(item) {
// an internal, internal helper
function buildCell(text) {
var td = document.createElement("td");
td.innerHTML = text;
return td;
}
// store the table row object on the item itself
item.row = document.createElement("tr");
item.row.appendChild(buildCell(item.product));
item.row.appendChild(buildCell(item.price));
var deleteCell = buildCell("Verwijder");
item.row.appendChild(deleteCell);
// set the event listener here, where we can access `item` and `tr`
deleteCell.addEventListener("click", function () {
that.removeItem(item); // remove the item. Here we need the `that` var
}, false);
return item.row;
}
}
getElementById
call inside.render
is not needed. You can make that DOM query once and then have a reference to that element. Also, the function you're looking for for removing elements from the array is.splice
\$\endgroup\$getElementById
inside of.render
and I will also look into the function.splice
and its usage. Thank you a lot for your very helpful comment! \$\endgroup\$