Here's another approach it seems easy to understand but don't hesitate if you have any question.
This solution avoid to always use innerHTML!
I don't understand if you want to duplicate nodes or just create a document as specified and add a listener to it.
in the clickHandler()
method you can easily do what you want...
Duplicate an Object, add the destination to a cart...
If you want to see the logs, click on "Full page" for the snippet.
EDIT :
I was curious if I really gain functionalities with the method I used in the first snippet, so I searched a while to see if I was able to deal with the document.createElement()
method.
I finally get a result.
For sure there's a lot of code and not so easy to read I suppose but I post what I've tried if someone is interested in the second snippet.
There you may create a real cart, select the number of tickets you want, calculate the prize for each destination and get all the information in the div bellow with the total prize of your cart.
The data's may be submitted by a form (not implemented) an so on...
So the second snippet is a study of case, just to know if some things can be done.
If you want to see the result, click on "Full page" for the second snippet too.
END OF EDIT
Best regards.
let countries = ["Sweden", "Norway", "Denmark"];
function addElements(){
for(var i=0; i<countries.length; i++){
constructElement(i)
}
}
function constructElement(i){
var newDiv = document.createElement("div");
var newH1 = document.createElement("h1");
var newTitle = document.createTextNode(countries[i]);
var innerDiv = document.createElement("div");
innerDiv.classList.add("inDiv");
var paragraph = document.createElement("p");
var btn = document.createElement("button");
btn.setAttribute("value", i);
btn.classList.add("inButton");
var newText = document.createTextNode("Country n°" + (i+1) + " :");
var buttonText = document.createTextNode(countries[i]);
newDiv.appendChild(newH1);
newH1.appendChild(newTitle);
newDiv.appendChild(innerDiv)
innerDiv.appendChild(paragraph);
paragraph.appendChild(newText);
innerDiv.appendChild(btn);
btn.appendChild(buttonText)
document.body.appendChild(newDiv);
btn.addEventListener("click", clickEvent);
}
addElements();
function clickEvent(event){
console.log("button clicked value = " + this.value + ", country = " + this.textContent);
// then you may add conditions related to the button value...
if(this.value == 0){
console.log("Do you live in " + countries[this.value] + "?");
}else if(this.value == 1){
console.log("Are you happy in " + countries[this.value] + "?");
}else if(this.value == 2){
console.log("Are you really leaving " + countries[this.value] + "?");
}
}
html, body{
font-family: sans-serif;
}
h1{
font-size: 1.2em;
}
p{
margin:0;
}
.inDiv{
padding:10px;
color:#009900;
border:1px solid #000000;
width:300px;
font-weight:bold;
}
.inButton{
padding:5px;
color:#990000;
width:100px;
}
Here is the second snippet
// HERE IS A LOT OF CODE :D
let countries = ["Sweden", "Norway", "Denmark"];
let cart = [];
let tableIndex = 0;
let destinationsDiv=document.getElementById("destinationsDiv");
let cartDiv=document.getElementById("cartDiv");
let cartTotal=document.getElementById("cartTotal");
let cartTotalPrice=document.getElementById("cartTotalPrice");
let fields = [document.getElementById("field1"),
document.getElementById("field2"),
document.getElementById("field3")
]
let details = [[],[],[]];
let counter = [
{country:"Sweden", quantity:0, id:0, price:100},
{country:"Norway", quantity:0, id:1, price:220},
{country:"Denmark", quantity:0, id:2, price:150}
];
let currency = "$"
let paragraphEmpty;
let totalPrice = 0;
// the counter Array may accept a lot of arguments like quantity, totalPrice...
// and You can update the elements of counter anywhere in the function
// The createElement is safer than use innerHTML method and avoid injections possibilities
// I think that the use of createElement is better in terms of performance.
// In a short file like yours it' not significant for sure.
function addElements(){
for(var i=0; i<countries.length; i++){
constructElement(i);
}
updateCartStatus();
displayEmptyCart();
}
function updateCart(j){
counter[j].quantity += 1;
var inf = document.getElementById(counter[j].country+"_info");
inf.textContent = "tickets = " + counter[j].quantity + " total price = " + (counter[j].quantity * counter[j].price) + " " + currency;
updateCartStatus();
}
function updateCartStatus(){
// TO CHANGE DISPLAY OF CART ITEMS SEPARETELY
/*
FORMAT THE DETAILS FOR THE CART
*/
totalPrice = 0;
var str="";
cartTotalPrice.textContent=""
for(var j=0; j<counter.length; j++){
if(counter[j].quantity>0){
str+=(counter[j].country + ", " +
"1 ticket = " + counter[j].price + ", " +
"quantity = " + counter[j].quantity + ", " +
"sub-total = " + (counter[j].quantity * counter[j].price) + " " + currency
);
fields[j].textContent = str;
}else{
fields[j].textContent = "";
}
totalPrice += (parseInt(counter[j].quantity)*parseInt(counter[j].price));
str="";
}
//console.log("totalPrice = " + parseInt(totalPrice));
cartTotalPrice.textContent = ("TotalPrice = " + parseInt(totalPrice) + " " + currency);
displayFilledCart();
}
function constructElement(i){
let newDiv = document.createElement("div");
var newH1 = document.createElement("h1");
var newTitle = document.createTextNode(countries[i]);
var innerDiv = document.createElement("div");
innerDiv.classList.add("inDiv");
var paragraph = document.createElement("p");
var btn = document.createElement("button");
btn.setAttribute("value", i);
btn.classList.add("inButton");
var newText = document.createTextNode("price : " + counter[i].price);
var buttonText = document.createTextNode("add to cart.");
newDiv.appendChild(newH1);
newH1.appendChild(newTitle);
newDiv.appendChild(innerDiv)
innerDiv.appendChild(paragraph);
paragraph.appendChild(newText);
innerDiv.appendChild(btn);
btn.appendChild(buttonText);
destinationsDiv.appendChild(newDiv);
btn.addEventListener("click", addTicket);
}
function addToCart(i){
var id = counter[i].country;
var test = document.getElementById(`${id}`);
if (test != null) {
updateCart(i);
return;
}
// CREATE A NEW ELEMENT IF IT'S NOT ALREADY IN CART
var newDiv = document.createElement("div");
newDiv.setAttribute("data-id", i);
newDiv.setAttribute("id", counter[i].country);
var newH1 = document.createElement("h1");
var newTitle = document.createTextNode(countries[i]);
var innerDiv = document.createElement("div");
var paragraph = document.createElement("p");
var details = document.createElement("div");
details.setAttribute("id", counter[i].country+"_info");
counter[i].quantity+=1;
var ticketsText = document.createTextNode("tickets = " + counter[i].quantity + " total price = " + (counter[i].quantity * counter[i].price) + " " + currency);
details.classList.add("details");
details.appendChild(ticketsText);
var btn = document.createElement("button");
btn.setAttribute("value", tableIndex);
btn.classList.add("inButton");
var newText = document.createTextNode("Booked : price = " + counter[i].price + currency + " / person");
var buttonText = document.createTextNode("remove 1 ticket");
newDiv.appendChild(newH1);
newH1.appendChild(newTitle);
newDiv.appendChild(innerDiv);
innerDiv.appendChild(paragraph);
innerDiv.classList.add("inDiv");
paragraph.appendChild(newText);
innerDiv.appendChild(details);
innerDiv.appendChild(btn);
btn.appendChild(buttonText);
cart.push({ div: newDiv, country: countries[i], tableIndex: tableIndex});
cartDiv.appendChild(newDiv);
btn.addEventListener("click", removeTicket);
tableIndex+=1;
updateCartStatus();
}
function displayEmptyCart(){
paragraphEmpty = document.createElement("p");
paragraphEmpty.classList.add("emptyCart");
var newText = document.createTextNode("Your cart is empty");
paragraphEmpty.appendChild(newText);
cartDiv.appendChild(paragraphEmpty);
}
function displayFilledCart(){
if(paragraphEmpty != null){
cartDiv.removeChild(paragraphEmpty);
paragraphEmpty=null;
}
}
addElements();
function addTicket(event){
if(this.value == 0){
addToCart(0);
}else if(this.value == 1){
addToCart(1);
}else if(this.value == 2){
addToCart(2);
}
}
function removeTicket(event) {
let divToRemove = this.parentNode.parentNode;
let index = cart.findIndex((item) => item.div === divToRemove);
let countryCode = parseInt(divToRemove.getAttribute("data-id"));
if (index !== -1) {
if (counter[countryCode].quantity > 1) {
counter[countryCode].quantity -= 1;
let details = divToRemove.querySelector(".details");
details.textContent = "tickets = " + counter[countryCode].quantity + " total price = " + (counter[countryCode].quantity * counter[countryCode].price) + currency;
} else {
counter[countryCode].quantity = 0;
cartDiv.removeChild(divToRemove);
// Update tableIndex when removing a ticket
cart.splice(index, 1);
for (let i = index; i < cart.length; i++) {
cart[i].tableIndex -= 1;
}
}
updateCartStatus();
}
//console.log(cart.length);
if (cart.length === 0) {
displayEmptyCart();
}
}
html, body{
font-family: sans-serif;
}
h1{
font-size: 1.2em;
}
p{
margin:0;
}
#destinationsDiv{
border:1px solid #000000;
padding:10px;
background-color: rgba( 255,66,00,0.1);
}
#cartDiv{
border:1px solid #000000;
margin-top:20px;
padding:10px;
background-color: rgba( 200,250,200,0.2);
}
#cartTotal{
border:1px solid #000000;
margin-top:20px;
padding:10px;
font-weight: bold;
font-style: italic;
background-color: rgba( 255,255,200,0.3);
}
#cartTotalPrice{
margin:10px;
padding:10px;
color:#009900;
font-weight: bold;
font-size: 1.1em;
border:1px solid #000000;
width:200px;
}
.details{
color:#000000;
}
.inDiv{
padding:10px;
color:#009900;
border:1px solid #000000;
width:300px;
font-weight:bold;
}
.inButton{
padding:5px;
color:#990000;
width:200px;
}
.emptyCart{
font-size:1.1em;
font-style: italic;
}
<div id="destinationsDiv">
<h1>Our destinations :</h1>
</div>
<div id="cartDiv">
<h1>Your cart :</h1>
</div>
<div id="cartTotal">
<p id="field1"></p>
<p id="field2"></p>
<p id="field3"></p>
<p id="cartTotalPrice"></p>
</div>