I am using Javascript to create an HTML form with some radio button questions and one checkbox question at the end. The reason I am using JavaScript is that the questions take data from a google cloud firestore database, and they need to be dynamic. when I get the data from the radio buttons, it shows it as a string, but when I get the data from the checkboxes, it leaves it blank. I want it to show a string with a list of boxes checked. Here is my code:
const OACanList = document.querySelector('#OAInput');
const setupOACans = (data) => {
let html = '';
if (data.length) {
data.forEach(doc => {
const OACan = doc.data();
const li = `
<style>
#OAInput [type="checkbox"]:not(:checked), [type="checkbox"]:checked {
position: static;
opacity: 1;
pointer-events: initial;
}
</style>
<input type="checkbox" name="OAElection" value="${OACan.name}" style="display:block opacity:1;">${OACan.name}
<br>
`;
html += li
});
OACanList.innerHTML = html;
} else {
OACanList.innerHTML = html;
};
};
index.js:
const voteForm = document.querySelector('#vote-form');
voteForm.addEventListener('submit', (e) => {
e.preventDefault();
db.collection('ballots').add({
OA: voteForm.OAElection.value
}).then(() => {
const modal = document.querySelector('#modal-vote');
M.Modal.getInstance(modal).close();
voteForm.reset();
}).then(() => {
const docRef = db.collection('users').doc(auth.currentUser.uid);
docRef.get().then(function(doc) {
doc.data().count++;
})
});
});
Related
I'm having trouble retrieving data from a data-tag attribute on a button that is created by createElement
chatbot.js
const selectServiciosMoviles = document.querySelector('#selectServiciosMoviles')
const addSelect = (select, id, datatag) => {
const selection = document.createElement('button')
selection.classList.add('chatbot__selection')
selection.id = id
selection.setAttribute("data-tag", datatag)
selection.innerHTML = select
messageArea.appendChild(selection)
scrollToBottom(messageArea)
}
selectServiciosMoviles.addEventListener('click', () => {
setTimeout(() => {
addSelect('Portabilidad', 'selectPortabilidad', '{"categoria":"chatbot", "nombre":"chatbot","ubicacion":"home_b2b", "accion":"seleccionar", "etiqueta":"subcategoria_portabilidad"}')
addSelect('Planes Moviles', 'selectMoviles', '{"categoria":"chatbot", "nombre":"chatbot","ubicacion":"home_b2b", "accion":"seleccionar", "etiqueta":"subcategoria_planes_moviles"}')
addSelect('Roaming', 'selectRoaming', '{"categoria":"chatbot", "nombre":"chatbot","ubicacion":"home_b2b", "accion":"seleccionar", "etiqueta":"subcategoria_roaming"}')
addSelect('Seguro Movil', 'selectSeguros', '{"categoria":"chatbot", "nombre":"chatbot","ubicacion":"home_b2b", "accion":"seleccionar", "etiqueta":"subcategoria_seguro_movil"}')
scrollToBottom()
}, 2000)
});
html
<button class="chatbot__selection" id="selectPortabilidad" data-tag="{"categoria":"chatbot", "nombre","chatbot", "ubicacion":"home_b2b", "accion":"seleccionar","etiqueta":"subcategoria_portabilidad"}">Portabilidad</button>
<button class="chatbot__selection" id="selectMoviles" data-tag="{"categoria":"chatbot", "nombre","chatbot", "ubicacion":"home_b2b", "accion":"seleccionar","etiqueta":"subcategoria_portabilidad"}">Planes Moviles</button>
<button class="chatbot__selection" id="selectRoaming" data-tag="{"categoria":"chatbot", "nombre","chatbot", "ubicacion":"home_b2b", "accion":"seleccionar","etiqueta":"subcategoria_portabilidad"}">Roaming</button>
<button class="chatbot__selection" id="selectSeguros" data-tag="{"categoria":"chatbot", "nombre","chatbot", "ubicacion":"home_b2b", "accion":"seleccionar","etiqueta":"subcategoria_portabilidad"}">Seguro Movil</button>
libreria.js
var tagItems = document.querySelectorAll('[data-tag]')
tagItems.forEach(function (e) {
e.addEventListener('click', function (e) {
if(e.target.dataset.tag != undefined){
var data = JSON.parse(e.target.dataset.tag)
console.log(data)
}
})
})
the problem when seeing the console nothing appears to me, the data-tag of the button does not rescue me. please i need help, thanks
I'm using an API to get information for a database sort of thing. I want the images to be displayed to the right of the text but the images aren't showing up at all. I tried multiple different keys and still nothing. Here is what it currently looks like:
The images are not showing up as you can see.
Here is the JS (its pulling the data from here https://api.tvmaze.com/shows/347/episodes):
// DATABASE const sunnyList = document.getElementById('sunnyList'); let sunnyInfo = [];
searchBar.addEventListener('keyup', (e) => { const searchTarget = e.target.value.toLowerCase(); const filteredSunny = sunnyInfo.filter(sunny => {
return sunny.name.toLowerCase().includes(searchTarget) || sunny.airdate.toLowerCase().includes(searchTarget) || sunny.airtime.includes(searchTarget) });
displayInfo(filteredSunny); });
const loadLayout = async () => {
try {
const res = await fetch('https://api.tvmaze.com/shows/347/episodes');
sunnyInfo = await res.json();
displayInfo(sunnyInfo);
} catch (err) {
console.error(err);
} };
const displayInfo = (sunny) => {
const htmlString = sunny
.map((sunny) => {
return `
<li class="character">
<div class="detail">
<h2>${sunny.name}</h2>
<p>Season ${sunny.season} Episode ${sunny.number}</p>
<p>${sunny.airdate}</p>
<p>${sunny.airtime}</p>
<p>${sunny.rating.average}</p>
</div>
<img src="${sunny.image}"></img>
</li>
`;
})
.join('');
sunnyList.innerHTML = htmlString; };
loadLayout();
I've tried sunny.image.medium and sunny.image.original but it still doesn't show up.
Any help is appreciated :)
The image is not a url string, but an object with the following shape:
{
medium: string,
original: string
}
where both strings contain the actual image URLs.
For your use case medium probably makes more sense, so you can do this:
<img src="${sunny.image?.medium}"></img>
Edit
Added optional chaining because some items do not have image property.
The problem your are facing is that not all objects have images.
Please try this code:
const displayInfo = (sunny) => {
const htmlString = sunny
.map((sunny) => {
const img = sunny.image ? sunny.image.medium : "https://picsum.photos/200/300"
return `
<li class="character">
<div class="detail">
<h2>${sunny.name}</h2>
<p>Season ${sunny.season} Episode ${sunny.number}</p>
<p>${sunny.airdate}</p>
<p>${sunny.airtime}</p>
<p>${sunny.rating.average}</p>
</div>
<img src=${img} />
</li>
`;
})
.join('');
sunnyList.innerHTML = htmlString; };
Why when you are searching for something else is deleting the previous contents ?For example first you search for egg and show the contents but then when you search for beef the program deletes the egg and shows only beef.Code :
const searchBtn = document.getElementById('search-btn');
const mealList = document.getElementById('meal');
const mealDetailsContent = document.querySelector('.meal-details-content');
const recipeCloseBtn = document.getElementById('recipe-close-btn');
// event listeners
searchBtn.addEventListener('click', getMealList);
mealList.addEventListener('click', getMealRecipe);
recipeCloseBtn.addEventListener('click', () => {
mealDetailsContent.parentElement.classList.remove('showRecipe');
});
// get meal list that matches with the ingredients
function getMealList(){
let searchInputTxt = document.getElementById('search-input').value.trim();
fetch(`https://www.themealdb.com/api/json/v1/1/filter.php?i=${searchInputTxt}`)
.then(response => response.json())
.then(data => {
let html = "";
if(data.meals){
data.meals.forEach(meal => {
html += `
<div class = "meal-item" data-id = "${meal.idMeal}">
<div class = "meal-img">
<img src = "${meal.strMealThumb}" alt = "food">
</div>
<div class = "meal-name">
<h3>${meal.strMeal}</h3>
Get Recipe
</div>
</div>
`;
});
mealList.classList.remove('notFound');
} else{
html = "Sorry, we didn't find any meal!";
mealList.classList.add('notFound');
}
mealList.innerHTML = html;
});
}
It's because you are replacing the contents in the mealList element every time.
A simple workaround would be to retrieve the the innerHTML values before you update it.
Something like
let html = mealList.innerHTML;
rather than starting off empty every time you call the function should do the trick.
I have a few buttons with different categories. When the user clicks on the button, the correct category should be displayed. In every category, there are a few products, each with their own "add to cart"-button.
So, the user clicks "beds" and then adds item #3 to the cart (which updates and so on).
I have managed to do this with classes IF the user can't choose a category. It also works without classes if I add the buttons dynamically in js. But again, without allowing the user to choose a category.
I also want the user to be able to search for an item, get the item/ items displayed, and add it to the cart.
Get Products
class Products {
async getProducts() {
try {
const result = await fetch("/data/products.json");
const data = await result.json();
let products = data.items;
products = products.map((item) => {
const { category, title, price } = item;
const { id } = item.sys;
const image = item.image.url;
return { category, title, price, id, image };
});
return products;
} catch (error) {
console.log(error);
}
}
}
Display Products
class UI {
async displayProducts(products, searchText) {
let matches = products.filter(item => {
const regex = new RegExp(`^${searchText}`,'gi');
return item.category.match(regex);
})
let result = "";
matches.forEach((product) => {
result += `
<!-- single product -->
<article class="product">
<div class="img-container">
<img
src=${product.image}
alt="product"
class="product-img"
/>
<button class="bag-btn" data-id=${product.id}>
<i class="fas fa-shopping-cart">add to cart</i>
</button>
</div>
<h3>${product.title}</h3>
<h4>$${product.price}</h4>
</article>
<!-- end single product -->
`;
});
productDOM.innerHTML = result;
}
getBagButtons() {
const buttons = [...document.querySelectorAll(".bag-btn")];
In HTML I used onclick="displayProducts('bed')"
This will not work tho, since displayProducts is in a class.
I have also tried to add an id to each button and add an eventlistener in DOMContentLoaded, but that wrecks the rest of my DOMContentLoaded stuff
DOMContentLoaded
document.addEventListener("DOMContentLoaded", () => {
const ui = new UI();
const products = new Products();
// setup app
ui.setupAPP();
products
.getProducts()
.then((products) => {
ui.displayProducts(products);
Storage.saveProducts(products);
})
.then(() => {
ui.getBagButtons();
ui.cartLogic();
});
});
These are just a few of the things I've tried, but for each try, one issue is fixed but one or more issues are added, so I could really use some help here. Thanks!
These are the changes we made:
All category buttons gets this event listener
onclick="searchNdisplay(new UI, new Products, 'category text');"
This initializes the ui and products and they get displayed, so we changed it to use the searchNdisplay function
document.addEventListener("DOMContentLoaded", () => {
const ui = new UI();
const products = new Products();
// setup app
ui.setupAPP();
searchNdisplay(ui, products, "");
Storage.saveProducts(products);
});
This function repopulates the page with products that met the search criteria.
function searchNdisplay(ui, products, search)
{
products
.getProducts()
.then((products) => {
if (search == "")
{
ui.displayProducts(products);
}
else
{
ui.displayProducts(products, search);
}
})
.then(() => {
ui.getBagButtons();
ui.cartLogic();
});
}
i am creating a multiple dynamic tooltips using tippyjs library on a page that fetches content using fetch api.
how do i access the data attribute on each of the selector while the initialisation of the tooltip.
here is what i have
Code
<span class="order-tooltip" data-orderid="123456">Order ID 123456</span>
<span class="order-tooltip" data-orderid="454515">Order ID 454515</span>
<span class="order-tooltip" data-orderid="487848">Order ID 487848</span>
<span class="order-tooltip" data-orderid="154214">Order ID 154214</span>
<div id="tooltipTemplate" style="display: none;">
Loading data...
</div>
<script>
const template = document.querySelector('#tooltipTemplate')
const initialText = template.textContent
const tip = tippy('.order-tooltip', {
animation: 'shift-toward',
arrow: true,
html: '#tooltipTemplate',
onShow() {
// `this` inside callbacks refers to the popper element
const content = this.querySelector('.tippy-content')
if (tip.loading || content.innerHTML !== initialText) return
tip.loading = true
console.log($('.order-tooltip').data('orderid')) // This is not working
var orderid = $(this).data('orderid');
var url = "/fetch_position_tooltip?" + $.param({orderid: orderid})
fetch(url).then(resp => resp.json()).then (responseJSON =>{
content.innerHTML = responseJSON
tip.loading = false
}).catch(e => {
console.log(e)
content.innerHTML = 'Loading failed'
tip.loading = false
})
},
onHidden() {
const content = this.querySelector('.tippy-content')
content.innerHTML = initialText
},
// prevent tooltip from displaying over button
popperOptions: {
modifiers: {
preventOverflow: {
enabled: false
},
hide: {
enabled: false
}
}
}
})
</script>
i need to access the data attribute for each of the span element when instantiating the toolitip .
How could i do this?
Contacted the maintainer of the library
Any one looking for this can use.
this._reference