I am looping through an array of objects (rendering data coming from an API) via Vanilla JavaScript (DOM). And I want to pass more than one value (Product ID, Product Name .. etc) to a function triggered in the event of a click button. saveProduct(${proInfo}) as it shown below (proInfo is an object).
The problem is I have been able to pass ONLY ONE value to this function. I tried to pass the variable as an object but it didn't work and got the error (index):1 Uncaught SyntaxError: Unexpected end of input
var shopNcounter = 0;
const baseURL = "***";
const idsArray = [];
const divRow = document.querySelector(".row");
const buttonContainer = document.querySelector("#button-container")
//create column div
function createDiv() {
const div = document.createElement("div");
div.classList.add("col-xl-3");
div.classList.add("col-md-6");
div.classList.add("col-sm-12");
return div;
}
async function getData(id) {
shopNcounter ++;
console.log(shopNcounter);
if(shopNcounter > 5) {
getProInfo(id);
return;
} else if (shopNcounter > 4) {
getProducts(id);
return;
}
idsArray.push(id);
console.log(id);
console.log(idsArray);
if(idsArray.length > 10) {
idsArray.splice(0,6);
}
const api = `**shop=${shopNcounter}&id=${id}`;
try {
const response = await fetch(api);
const data = await response.json();
divRow.innerHTML = "";
if (shopNcounter > 1) {
buttonContainer.innerHTML = `
<button class="btn btn-lg btn-warning px-5" onclick="moveBack(${idsArray[idsArray.length-2]})">رجوع</button>
`
} else {
buttonContainer.innerHTML = "";
}
//mapping through data
data.map(item => {
const div = createDiv();
divRow.appendChild(div);
div.innerHTML+=`
<div class="card text-center h-100 mx-auto border-white shadow" style="width: 16rem;">
<img src="${baseURL + item.image}" class="card-img-top mx-auto" alt="...">
<div class="card-body">
<a onclick=handleClick(${item.id}) class="btn btn-outline-dark px-5 mt-4" id="goToItemButton">${item.name}</a>
</div>
</div>
`;
});
} catch(error) {console.log(error);}
}
getData(0);
async function getProducts(id) {
//shop > 4 = 5
console.log("Get Product is being executing");
const apiProducts = `**product?id=${id}`;
try {
const response = await fetch(apiProducts);
const data = await response.json();
console.log(data);
divRow.innerHTML = "";
//mapping through data
data.map((item, index) => {
var proInfo = {
pid: item.PID,
pname: item.PName
}
const div = createDiv();
divRow.appendChild(div);
div.innerHTML+=`
<div class="card text-center h-100 mx-auto border-white shadow" style="width: 16rem;">
<img src="${baseURL + item.image}" class="card-img-top mx-auto" alt="...">
<div class="card-body">
<h5>${item.PName}</h5>
<p class="product-price">Price: ${item.PSelPrice}</p>
<a onclick=saveProduct(${item.PID}) class="btn btn-danger px-5 mt-4"> Add to Card </a>
</div>
</div>
`;
});
} catch(error) {
console.log(error);
}
}
function moveBack(id) {
shopNcounter = shopNcounter -2;
getData(id);
}
function handleClick(id) {
let clickedButton = document.querySelector("#goToItemButton");
clickedButton.onclick = "";
getData(id);
}
function saveProduct(g) {
console.log(g);
}
your code should not result in the error you see
However you can make your life easier using delegation
do this
document.getElementById("container").innerHTML = data.map((item,i) => `<div class="card text-center h-100 mx-auto border-white shadow" style="width: 16rem;">
<img src="${baseURL + item.image}" class="card-img-top mx-auto" alt="...">
<div class="card-body">
<h5>${item.PName}</h5>
<p class="product-price">Price: ${item.PSelPrice}</p>
<a data-id="${i}" class="add btn btn-danger px-5 mt-4"> Add to Card </a>
</div>
</div>`).join("");
Have this
document.getElementById("container").addEventListener("click",function(e) {
const tgt = e.target.closest("a");
if (tgt && tgt.className.contains("add")) {
const item = data[tgt.dataset.id]
// here you can add the item
saveProduct({pid: item.PID,pname: item.PName })
}
})
Related
i want to use multiple XMLHttpRequest,
However i used this code that 1st XMLHttpRequest was successfully run but the second one is not running, its simply executing the else block from code Some error occured
so help me to get this issue resolve
HTML File
<div class="container my-3">
<div class="row">
<div class="col-6">
<h3>Top News <span class="badge bg-dark">by OnDemand News</span></h3>
<hr>
<div class="accordion" id="newsAccordion"></div>
</div>
<div class="col-6">
<h3>Top News <span class="badge bg-dark">by OnDemand News</span></h3>
<hr>
<div class="accordion" id="newsAccordion1"></div>
</div>
</div>
</div>
JavaScript File
// Initialize the news api parameters
let source = 'bbc-news';
let apiKey = '---';
// Grab the news container
let newsAccordion = document.getElementById('newsAccordion');
// create an Ajax get request
const xhr = new XMLHttpRequest();
xhr.open('GET', `https://newsapi.org/v2/top-headlines?sources=${source}&apiKey=${apiKey}`, true);
// What to do when response is ready
xhr.onload = function () {
if (this.status === 200) {
let json = JSON.parse(this.responseText);
let articles = json.articles;
// console.log(articles);
let newsHtml = "";
articles.forEach(function(element, index) {
// console.log(element, index);
let news = `<div class="card">
<div class="card-header" id="heading${index}">
<h2 class="mb-0">
<button class="btn btn-link collapsed btn-block text-left" type="button" data-toggle="collapse" data-target="#collapse${index}" aria-expanded="true" aria-controls="collapse${index}">
<b>${element["title"]}</b>
</button>
</h2>
</div>
<div id="collapse${index}" class="collapse" aria-labelledby="heading${index}" data-parent="#newsAccordion">
<div class="card-body">
${element["content"]}. Read more about this News
</div>
</div>
</div>`
newsHtml += news;
});
newsAccordion.innerHTML = newsHtml;
}
else {
console.log("Some error occured")
}
}
xhr.send();
// Initialize the news api parameters
let source1 = 'times-of-india';
let apiKey1 = '---';
// Grab the news container
let newsAccordion1 = document.getElementById('newsAccordion1');
// create an Ajax get request
const xhr1 = new XMLHttpRequest();
xhr1.open('GET', `https://newsapi.org/v2/top-headlines?sources=${source1}&apiKey=${apiKey1}`, true);
// What to do when response is ready
xhr1.onload = function () {
if (this.status === 300) {
let json = JSON.parse(this.responseText);
let articles = json.articles;
// console.log(articles);
let newsHtml1 = "";
articles.forEach(function(element, index) {
console.log(element, index);
let news1 = `<div class="card">
<div class="card-header" id="heading${index}">
<h2 class="mb-0">
<button class="btn btn-link collapsed btn-block text-left" type="button" data-toggle="collapse" data-target="#collapse${index}" aria-expanded="true" aria-controls="collapse${index}">
<b>${element["title"]}</b>
</button>
</h2>
</div>
<div id="collapse${index}" class="collapse" aria-labelledby="heading${index}" data-parent="#newsAccordion">
<div class="card-body">
${element["content"]}. Read more about this News
</div>
</div>
</div>`
newsHtml1 += news1;
});
newsAccordion1.innerHTML = newsHtml1;
}
else {
console.log("Some error occured")
}
}
xhr1.send();
I have made a TODO app and added a counter to keep a count of the items in the list. If the counter hits zero, I've set it to re-show a message 'You currently have no tasks. Use the input field above to start adding.'
if(count === 0){
noTasksText.classList.remove('d-none');
}
In the console I print out the div and it doesn't have d-none in the class list any more which is what I want, however, in the actual DOM it does.
Here is a full example - https://codepen.io/tomdurkin/pen/LYdpXKJ?editors=1111
I really can't seem to work this out. I can't seem to interact with that div when the counter becomes zero, however I can get console logs etc to show when expected.
Any help would be appreciated!
const mainInput = document.querySelector('#main-input');
const todoContainer = document.querySelector('#todo-container');
const errorText = document.querySelector('#js-error');
const noTasksText = document.querySelector('.js-no-tasks')
let tasks = [];
let count = 0;
// focus input on load
window.onload = () => {
mainInput.focus();
const storedTasks = JSON.parse(localStorage.getItem('tasks'));
if (storedTasks != null && storedTasks.length > 0) {
// set count to number of pre-existing items
count = storedTasks.length
// hide the 'no tasks' text
noTasksText.classList.add('d-none');
// overwrite tasks array with stored tasks
tasks = storedTasks;
tasks.forEach(task => {
// Build the markup
const markup = `
<div class="js-single-task single-task border-bottom pt-2 pb-2">
<div class="row">
<div class="col d-flex align-items-center js-single-task-name">
<h5 class="mb-0" data-title="${task}">${task}</h5>
</div>
<div class="col d-flex justify-content-end">
<button class="js-remove-task d-block btn btn-danger">Remove Item</button>
</div>
</div>
</div>`;
// Append it to the container
todoContainer.innerHTML += markup;
});
} else {
if (noTasksText.classList.contains('d-none')) {
noTasksText.classList.remove('d-none');
}
}
};
// event listener for 'enter on input'
mainInput.addEventListener("keydown", e => {
// if error is showing, hide it!
if (!errorText.classList.contains('d-none')) {
errorText.classList.add('d-none');
}
if (e.key === "Enter") {
// Get the value of the input
let inputValue = mainInput.value;
if (inputValue) {
// Build the markup
const markup = `
<div class="js-single-task border-bottom pt-2 pb-2">
<div class="row">
<div class="col d-flex align-items-center js-single-task-name">
<h5 class="mb-0" data-title="${inputValue}">${inputValue}</h5>
</div>
<div class="col d-flex justify-content-end">
<button class="js-remove-task d-block btn btn-danger">Remove Item</button>
</div>
</div>
</div>`;
// hide 'no tasks' text
noTasksText.classList.add('d-none');
// Append it to the container
todoContainer.innerHTML += markup;
// Push value to 'tasks' array
tasks.push(inputValue);
// Put in localStorage
textTasks = JSON.stringify(tasks);
localStorage.setItem("tasks", textTasks);
// Reset the value of the input field
mainInput.value = '';
// add 1 to the count
count++
} else {
// Some very basic validation
errorText.classList.remove('d-none');
}
}
});
// remove task
todoContainer.addEventListener('click', (e) => {
// Find the button in the row that needs removing (bubbling)
const buttonIsDelete = e.target.classList.contains('js-remove-task');
if (buttonIsDelete) {
// Remove the HTML from the screen
e.target.closest('.js-single-task').remove();
// Grab the name of the single task
let taskName = e.target.closest('.js-single-task').querySelector('.js-single-task-name h5').getAttribute('data-title');
// filter out the selected word
tasks = tasks.filter(item => item != taskName);
textTasks = JSON.stringify(tasks);
localStorage.setItem("tasks", textTasks);
// update counter
count--
// check if counter is zero and re-show 'no tasks' text if true
if (count === 0) {
noTasksText.classList.remove('d-none');
console.log(noTasksText);
}
}
});
body {
background: #e1e1e1;
}
<div class="container">
<div class="row d-flex justify-content-center mt-5">
<div class="col-10 col-lg-6">
<div class="card p-3">
<h2>To dos</h2>
<p>
Use this app to keep a list of things you need to do
</p>
<input class="form-control" id="main-input" type="text" placeholder="Type your todo and hit enter..." class="w-100" />
<small id="js-error" class="text-danger d-none">
Please type a value and press enter
</small>
<hr />
<h4 class="mb-5">Your 'To dos'</h4>
<div id="todo-container">
<!-- todos append in here -->
<div class="js-no-tasks">
<small class="d-block w-100 text-center mb-3">
<i>
You currently have no tasks. Use the input field above to start adding
</i>
</small>
</div>
</div>
</div>
<!-- /card -->
</div>
</div>
</div>
Upon setting innerHTML by using += innerHTML the node noTasksText is lost, because browser processes the whole new set innerHTML and creates new objects. You can either retrieve noTasksText again after that, or append nodes using todoContainer.appendChild. I forked your pen and solved it with the latter solution.
https://codepen.io/aghosey/pen/wvmGwWd
You can do the following, it will work (here innerHTML is changing the DOM, so I added an extra function to recalculate elements after DOM is changed due to innerHTML):
var mainInput = document.querySelector("#main-input");
var todoContainer = document.querySelector("#todo-container");
var errorText = document.querySelector("#js-error");
var noTasksText = document.querySelector(".js-no-tasks");
let tasks = [];
let count = 0;
function getAllElements() {
mainInput = document.querySelector("#main-input");
todoContainer = document.querySelector("#todo-container");
errorText = document.querySelector("#js-error");
noTasksText = document.querySelector(".js-no-tasks");
}
// focus input on load
window.onload = () => {
mainInput.focus();
var storedTasks = JSON.parse(localStorage.getItem("tasks"));
if (storedTasks != null && storedTasks.length > 0) {
// set count to number of pre-existing items
count = storedTasks.length;
// hide the 'no tasks' text
noTasksText.classList.add("d-none");
// overwrite tasks array with stored tasks
tasks = storedTasks;
tasks.forEach((task) => {
// Build the markup
const markup = `
<div class="js-single-task single-task border-bottom pt-2 pb-2">
<div class="row">
<div class="col d-flex align-items-center js-single-task-name">
<h5 class="mb-0" data-title="${task}">${task}</h5>
</div>
<div class="col d-flex justify-content-end">
<button class="js-remove-task d-block btn btn-danger">Remove Item</button>
</div>
</div>
</div>`;
// Append it to the container
todoContainer.innerHTML += markup;
getAllElements();
});
} else {
if (noTasksText.classList.contains("d-none")) {
noTasksText.classList.remove("d-none");
}
}
};
// event listener for 'enter on input'
mainInput.addEventListener("keydown", (e) => {
// if error is showing, hide it!
if (!errorText.classList.contains("d-none")) {
errorText.classList.add("d-none");
}
if (e.key === "Enter") {
// Get the value of the input
let inputValue = mainInput.value;
if (inputValue) {
// Build the markup
const markup = `
<div class="js-single-task border-bottom pt-2 pb-2">
<div class="row">
<div class="col d-flex align-items-center js-single-task-name">
<h5 class="mb-0" data-title="${inputValue}">${inputValue}</h5>
</div>
<div class="col d-flex justify-content-end">
<button class="js-remove-task d-block btn btn-danger">Remove Item</button>
</div>
</div>
</div>`;
// hide 'no tasks' text
noTasksText.classList.add("d-none");
// Append it to the container
todoContainer.innerHTML += markup;
getAllElements();
// Push value to 'tasks' array
tasks.push(inputValue);
// Put in localStorage
textTasks = JSON.stringify(tasks);
localStorage.setItem("tasks", textTasks);
// Reset the value of the input field
mainInput.value = "";
// add 1 to the count
count++;
} else {
// Some very basic validation
errorText.classList.remove("d-none");
}
}
});
// remove task
todoContainer.addEventListener("click", (e) => {
// Find the button in the row that needs removing (bubbling)
const buttonIsDelete = e.target.classList.contains("js-remove-task");
if (buttonIsDelete) {
// Remove the HTML from the screen
e.target.closest(".js-single-task").remove();
// Grab the name of the single task
let taskName = e.target
.closest(".js-single-task")
.querySelector(".js-single-task-name h5")
.getAttribute("data-title");
// filter out the selected word
tasks = tasks.filter((item) => item != taskName);
textTasks = JSON.stringify(tasks);
localStorage.setItem("tasks", textTasks);
// update counter
count--;
// check if counter is zero and re-show 'no tasks' text if true
if (count === 0) {
noTasksText.classList.remove("d-none");
console.log(noTasksText);
}
}
});
body {
background: #e1e1e1;
}
<div class="container">
<div class="row d-flex justify-content-center mt-5">
<div class="col-10 col-lg-6">
<div class="card p-3">
<h2>To dos</h2>
<p>
Use this app to keep a list of things you need to do
</p>
<input class="form-control" id="main-input" type="text" placeholder="Type your todo and hit enter..." class="w-100" />
<small id="js-error" class="text-danger d-none">
Please type a value and press enter
</small>
<hr />
<h4 class="mb-5">Your 'To dos'</h4>
<div id="todo-container">
<!-- todos append in here -->
<div class="js-no-tasks">
<small class="d-block w-100 text-center mb-3">
<i>
You currently have no tasks. Use the input field above to start adding
</i>
</small>
</div>
</div>
</div>
<!-- /card -->
</div>
</div>
</div>
I need to add a Delete button on my cards, and this is the error I get.
Try moving the deleteButton() function outside of the getComments() function.
function getComments() {
fetch(commentsUrl, { method: "GET" })
.then((res) => res.json())
.then((data) => {
data.forEach(function (post) {
const randomId = Math.random().toString().substr(2, 8);
const comment = document.createElement("div");
comment.innerHTML = `
<div class="card" id="${randomId}">
<div class="card text-center bg-info" style="width: 18rem;">
<div class="card-body ">
<h5 class="card-user ">${post.user}</h5>
<h6 class="card-id mb-2 text-muted">Id: ${post.id}</h6>
<p class="card-content">"${post.content}" </p>
<p class="card-date">${post.date}<p>
<button type="button" class="btn btn-primary btn-sm">Edit</button>
<button type="button" class="btn btn-danger btn-sm" id="deleteButton" onclick="deleteButton('${randomId}')">Delete</button>
</div>
</div>
</div>`;
document.getElementById("content").append(comment);
});
});
}
function deleteButton(id) {
var del = document.getElementById(id);
del.remove();
}
window.onload = getComments();
Functions in Javascript create a scope so functions defined within functions can only be called within that function.
You are creating a HTML element, which will try to call deleteButton() from the global scope and doesn't have access to the function declaration within getComments().
EDIT: fixed some more code
This is how it was asked to be done..
I find it above my knowledge, but in case anybody is curios, I thought I could share it.
const commentsUrl = "http://localhost:8080/comments";
let comments = [];
function getComments() {
fetch(commentsUrl, { method: "GET" })
.then((res) => res.json())
.then((data) => {
comments = data;
renderComments(comments);
});
}
const renderComments = (comments) => {
const commentsContainer = document.getElementById("content");
commentsContainer.innerHTML = "";
comments.forEach(function (post) {
const comment = document.createElement("div");
comment.innerHTML = `
<div id=${post.id} class="card">
<div class="card text-center bg-info" style="width: 18rem;">
<div class="card-body ">
<h5 class="card-user ">${post.user}</h5>
<h6 class="card-id mb-2 text-muted">Id: ${post.id}</h6>
<p class="card-content">"${post.content}" </p>
<p class="card-date">${post.date}<p>
<button type="button" class="btn btn-primary btn-sm">Edit</button>
<button type="button" class="btn btn-danger btn-sm" id="deleteBtn" onclick='remove(${post.id})'>Delete</button>
</div>
</div>
</div>`;
commentsContainer.append(comment);
});
};
function remove(id) {
fetch(`${commentsUrl}/${id}`, { method: "DELETE" }).then((comment) => {
const index = comments.findIndex(
(currentComment) => currentComment.id === comment.id
);
comments.splice(index - 1, 1);
renderComments(comments);
});
}
getComments();
I am using a Bootstrap Carousel, but the slides of the carousel are generated through DOM by looping through an array called "Capris".
There is a button that displays on each slide that is also specific to each index.
What I am trying to do is when a User clicks on one of the buttons, it redirects them to a different HTML file and prints to DOM that same index, just on the other HTML page.
I managed to do everything except having that index print to DOM on the second HTML file. Here is a snippet of my code for the carousel and the button's event listener:
const buyCapriBttn = () => {
for (let i = 0; i < capris.length; i++) {
document.querySelector(`#${capris[i].name}`).addEventListener('click', function () {generateProduct(capris[i])});
}
}
const capriCarousel = () => {
let domString = '';
for (let i = 0; i < capris.length; i++) {
if (i === 0) {
domString += `
<div class="carousel-item active">
<img class="d-block w-100" src="${capris[i].imageUrl}" alt="Capri 1">
<div class="d-flex justify-content-center">
<a id="${capris[i].name}" class="btn btn-primary capri-btn" href="/capris.html" role="button">Buy ${capris[i].name}</a>
</div>
<p class="capri-description">${capris[i].description}</p>
</div>
`;
} else if (i >= 1) {
domString += `
<div class="carousel-item">
<img class="d-block w-100" src="${capris[i].imageUrl}" alt="Capri 1">
<div class="d-flex justify-content-center">
<a id="${capris[i].name}" class="btn btn-primary capri-btn" href="/capris.html" role="button">Buy ${capris[i].name}</a>
</div>
<p class="capri-description">${capris[i].description}</p>
</div>
`;
} else;
}
printToDom("#carousel-items", domString);
buyCapriBttn();
}
When the button is clicked, it runs the generateProduct function for that index. Here is a snippet of that function that is run:
const generateProduct = (selectedPants) => {
domString = '';
console.log(selectedPants);
for (let i = 0; i < capris.length; i++) {
if (capris[i] === selectedPants) {
domString += `
<div id="caprisDom">
<img id="buycaprispic" src="${capris[i].imageUrl}">
<div id="nameandrating">
<h5 id="buycaprisname">${capris[i].name}</h5><h2>☆☆☆☆☆</h2>
</div>
<div class="caprisinfobox">
<p id="caprisinfo">${capris[i].description}</p>
<div class="sizeandprice">
<div id="sizeselector">
<label id="sizelabel">Size:</label>
<select name="sizelist" id="size">
</select>
</div>
<h3 id="price">$${capris[i].price}</h3>
</div>
<button id="cartbutton">Add to Cart</button>
</div>
</div>
`;
}
}
printToDom('#caprismain', domString);
}
I have a printToDom function that prints to those ids if you need that as well.
NOTE: In this exercise, I am trying to not use JQuery
Any thoughts and help are much appreciated!
Is all you need the index position of the item? I'd probably add it dynamically in the a declaration. Something like <a id="${capris[i].name}" class="btn btn-primary capri-btn" href="/capris.html?index=${i}" role="button">Buy ${capris[i].name}</a>
So it should look like this:
const capriCarousel = () => {
let domString = '';
for (let i = 0; i < capris.length; i++) {
if (i === 0) {
domString += `
<div class="carousel-item active">
<img class="d-block w-100" src="${capris[i].imageUrl}" alt="Capri 1">
<div class="d-flex justify-content-center">
<a id="${capris[i].name}" class="btn btn-primary capri-btn" href="/capris.html?index=${i}" role="button">Buy ${capris[i].name}</a>
</div>
<p class="capri-description">${capris[i].description}</p>
</div>
`;
} else if (i >= 1) {
domString += `
<div class="carousel-item">
<img class="d-block w-100" src="${capris[i].imageUrl}" alt="Capri 1">
<div class="d-flex justify-content-center">
<a id="${capris[i].name}" class="btn btn-primary capri-btn" href="/capris.html?index=${i}" role="button">Buy ${capris[i].name}</a>
</div>
<p class="capri-description">${capris[i].description}</p>
</div>
`;
} else;
}
printToDom("#carousel-items", domString);
buyCapriBttn();
}
Then, in the other page, in your js, you'd grab the query select using URLSearchParams like so:
const urlParams = new URLSearchParams(window.location.search);
const myParam = urlParams.get('index');
I need to create a card element for each row of the database. The problem in my function is that print only the first element. What i forgot? (the query works)
aggiornaEventi();
function aggiornaEventi() {
fetch("../user_area/query/select_allevents.php").then(onResponse).then(onJson);
}
function onResponse(response) {
return response.json();
}
function onJson(json) {
console.log(json);
if (json.length !== 0) {
const eventi = document.getElementById("eventi"); //inserire l'id
for (const evento of json) {
const card = document.getElementById("eventi").innerHTML = `
<div class="card" style="width: 18rem;">
<div class="card-body">
<h5 class="card-title">${evento.titolo}</h5>
<p class="card-text">${evento.descrizione} | ${evento.data}</p>
Vai
</div>
</div>
`;;
eventi.appendChild(card);
}
}
}
It looks like you are not creating a new element for each card, instead reusing the same one over an over.
Try:
// ...
const card = Document.createElement();
card.innerHTML = `
<div class="card" style="width: 18rem;">
<div class="card-body">
<h5 class="card-title">${evento.titolo}</h5>
<p class="card-text">${evento.descrizione} | ${evento.data}</p>
Vai
</div>
</div>
`;
eventi.appendChild(card);
// ...
You override the innerHTML of the card on 'evento' element. You should either use
const card = document.getElementById("eventi").innerHTML += `...`
or create a new element on every run with Document.createElement();
I fixed with this, thanks to all
function onJson(json) {
console.log(json);
if (json.length !== 0) {
const eventi = document.getElementById("eventi"); //inserire l'id
for (const evento of json) {
const card = document.createElement("eventi");
card.innerHTML = `
<div class="card" style="width: 18rem;">
<div class="card-body">
<h5 class="card-title">${evento.titolo}</h5>
<p class="card-text">${evento.descrizione} | ${evento.data}</p>
Vai
</div>
</div>
`;
eventi.appendChild(card);
}
}
}