Create HTML elements from nested array - javascript

I am attempting to create the mobile view of a restaurant menu. The menu itself is stored in the menu variable which holds data in the form of
let menu = [
[
'Food Section', //i.e Appetizers
['Entry', 'Food Description' , 'Price'],
['Entry', 'Food Description' , 'Price']
]
[
'Food Section', //i.e Soup
['Entry', 'Food Description' , 'Price'],
['Entry', 'Food Description' , 'Price']
],
etc...
I want the website itself to display buttons with the food sections ("Appetizers" button, "Soup" button) and upon clicking said button the appropriate food entries will drop down and become visible. For now I am attempting to just create the buttons and divs of the appropriate entries under each button. I do this by looping through menu and then looping through each menu element. Here is my code:
js:
let menu = [
[
'Appetizers',
['Fried Calamari', "", '$11.95'],
['Mussels', "Marinara, fra diavolo or bianco", '$12.95'],
['Calamari & Mussels', "Fra diavolo or marinara", '$12.95'],
['Hot Antipasto', "Two baked clams, two stuffed shells, two stuffed mushrooms, two fried shrimp & scallops in a seafood sauce", '$14.95'],
],
[
'Soups',
['Chicken Noodle','','$4.95'],
['Minestrone','','$4.95'],
['Lentil','','$5.95'],
['Pasta Fagioli','','$5.95'],
['Cheese Tortellini','','$6.95'],
]
//create html elements by looping through menu variable
for(i = 0; i < menu.length; i++){
for(j = 0; j < menu[i].length; j++){
if(j == 0){
foodSectionText = menu[i][j];
let btn = document.createElement("BUTTON");
btn.innerHTML = foodSectionText;
document.body.appendChild(btn); }
else{
menuEntry = menu[i][j];
console.log(menuEntry);
for(i = 0; i < menuEntry.length; i++){
div = document.createElement("DIV");
div.innerHTML = menuEntry[i];
document.body.appendChild(div);
}
}
}
}
The above code will create:
<button>Appetizers</button>
<div>Fried Calamari</div>
<div></div>
<div>$11.95</div>
But then throws Uncaught TypeError: Cannot read property 'length' of undefined referring to for(j = 0; j < menu[i].length; j++). Why is the second item ['Mussels', "Marinara, fra diavolo or bianco", '$12.95'] (and all subsequent items) not being properly rendered? Also if you have any suggestions as to how to clean up this process feel free to share, I feel I am going about implementing this a terrible way...

In the 3rd for loop, you're reusing the same loop counter i. Try using a different variable name (in my example I used k)
for(let i = 0; i < menu.length; i++){
for(let j = 0; j < menu[i].length; j++){
if(j == 0){
foodSectionText = menu[i][j];
let btn = document.createElement("BUTTON");
btn.innerHTML = foodSectionText;
document.body.appendChild(btn); }
else{
menuEntry = menu[i][j];
console.log(menuEntry);
for(let k = 0; k < menuEntry.length; k++){
div = document.createElement("DIV");
div.innerHTML = menuEntry[k];
document.body.appendChild(div);
}
}
}
}

Related

How can I define if a product is in a basket?

Tell me please, how can I do it for web-site on HTML CSS Javascript. If product is not in a shopping cart,
then show a text "Your cart is Empty." If the product is in the shopping cart, hide the text "Your cart is Empty.".
In Html there are several buttons with class .buttons on which the user clicks and adds products to the cart.
There are also added products in the shopping cart with class .basket__item. Buttons to delete items in cart with class .delete.
Lastly, the text with class .text_Empty_cart.
I was trying to do it through arrays and nothing happened. I tried through NodeList collections, but vainly.
function Cart_check() {
const btns_array = [...document.querySelectorAll(".buttons")];
const cart_Items_array = [...document.querySelectorAll(".basket__item")];
var text_Empty_cart = document.querySelector(".text_Empty_cart");
for (var i = 0; i < btns_array.length; i++) {
btns_array.addEventListener("click", () => {
for (var j = 0; j < cart_Items_array.length; i++) {
if (cart_Items_array[j] > 0) {
text_Empty_cart.style.display = "none";
} else {
text_Empty_cart.style.display = "block";
}
}
});
}
}
Cart_check();
Above one of my efforts. I'll be glad for any help!
First of all, maybe you should use j++.
for (var j = 0; j < cart_Items_array.length; i++) {
Second, it looks the script will reset the visibility. Maybe you should:
boolean hasItem = false;
for (var j = 0; j < cart_Items_array.length; j++) {
if (cart_Items_array[j] > 0) {
hasItem = true;
break;
}
}
if(hasItem)
text_Empty_cart.style.display = "none";
else
text_Empty_cart.style.display = "block";
You have not shared your HTML, so, for the moment we can only guess.
Below I out together a working snippet that will make the .empty__basket div disappear as soon as there are elements in the cart:
var i=0;
document.body.addEventListener("click",ev=>{
const el=ev.target;
if (!el.classList.contains("buttons")) return;
const btxt=el.textContent;
if(btxt=="add item"){
cart.insertAdjacentHTML("beforeend",
`<div class="basket__item">this is item ${++i} ... <button class="buttons">delete</button>`);
}
else if (btxt=="delete"){
el.closest("div").remove();
}
Cart_check();
});
const text_Empty_cart = document.querySelector(".text_Empty_cart"),
cart=document.querySelector("#cart");
function Cart_check() {
text_Empty_cart.style.display=document.querySelector(".basket__item")?"none":"";
}
Cart_check();
<button class="buttons">add item</button>
<div id="cart"></div>
<div class="text_Empty_cart">Your cart is currently empty.</div>
The Cart_check() function now becomes almost trivial: It simply checks for an existence of a .basket__item element and sets the visibility of the .text_Empty_cart element accordingly.

Make list of buttons clicked

Note: I know there may be ways to do this in other languages but I have only learned javascript.
I have an array of objects (food items in this case, each item has a name property). I have this code in a for loop that makes buttons for each item in the array (if the first item in the array has a name of cake then cake's button is called cake, if the item is called fries then the buttons name is fries). I want the user to be able to click the button for each item only once, and when that button is clicked, I want to display a list of each item clicked. The reason why I have var click = item[i].name is because I want each button to have the name of the item. This code makes a button for item in the array but it does not list the items clicked on. Here is my code:
HTML
<html>
<head>
</head>
<body>
<p id="likes">Likes: </p>
</body>
</html>
JAVASCRIPT
var items=[
{
name:"cake",
price:12
},
{
name:"fries",
price:10
},
{
name:"apple",
price:11
}
];
window.onload = function() {
for (var i = 0; i < items.length; i++) {
var btnItems = document.createElement("button");
btnItems.id = "btnItems";
btnItems.innerHTML = "Items";
var clicks = items[i].name;
btnItems.onclick = function () {
el.disabled = true;
clicks += items[i].name + i;
document.getElementById("clicks").innerHTML = "Items Clicked" + clicks;
}
}
Style your view as you wish but this should answer your problem
var items = [{
name: "cake",
price: 12
},
{
name: "fries",
price: 10
},
{
name: "apple",
price: 11
}
];
for (let i = 0; i < items.length; i++) {
const btn = document.createElement("button");
btn.id = "btnItems";
btn.textContent = items[i].name;
btn.onclick = function(el) {
// disable your button immediately upon click
el.target.disabled = true;
// create list element and assign value
const li = document.createElement('li');
li.textContent = items[i].name
// append list element to your <ul> list
document.getElementById('list-section').appendChild(li);
}
// append button to the DOM
document.body.appendChild(btn)
}
<ul id="list-section">
</ul>
HTML code:
I created a div to append the buttons in it.
<html>
<head>
</head>
<body>
<p id="likes">Likes: </p>
<p id="clicks"></p>
<div id="btn-container">
</div>
</body>
</html
>
Js code:
var items=[
{
name:"cake",
price:12
},
{
name:"fries",
price:10
},
{
name:"apple",
price:11
}
];
for (var i = 0; i < items.length; i++) {
var btnItems = document.createElement("button");
btnItems.id = "btnItems"+i;
var clicks = items[i].name;
btnItems.innerHTML = clicks;
document.getElementById("btn-container").appendChild(btnItems);
console.log(btnItems);
btnItems.addEventListener('click',function (el) {
alert('here');
el.disabled = true;
clicks += items[i].name + i;
document.getElementById("clicks").innerHTML = "Items Clicked" + clicks;
});
}
As you have not provided a reproducible example I cannot test this, however, you should be able to use something like this. Please take note of the comments and amend where necessary.
window.onload = function() {
for (var i = 0; i < items.length; i++) {
var btnItem = document.createElement("button");
const name = item[i].name;
// Set the button id
btnItem.id = `btnItem-${name}`;
// Set the button text to the item name
btnItem.innerHTML = name
btnItem.addEventListener('click', function (event) {
event.target.disabled = true;
// Do whatever you want here, e.g. add "name" to a list
}
}
}

Display pop up after 3 radio buttons are checked 'Yes'

I have a self-assessment quiz with 10 questions. After the user answers "Yes" 3 times, a modal is supposed to display with a referral link. I can't seem to get the code right, I've stored the radio buttons in an array and looped though the array, adding a counter variable every time the "Yes" button is clicked, but after 3 radios are checked "yes" the modal does not display:
const referralModal = document.getElementById('referralModal');
const radios = [q1, q2, q3, q4, q5, q6, q7, q8, q9, q10];
let count = 0;
for (var i = 0; i < radios.length; i++) {
radios[i].addEventListener('change', (e)=>{
count++;
});
if (count === 3) {
referralModal.style.display = 'block';
}
}
You should check this inside the event listener function
const referralModal = document.getElementById('referralModal');
const radios = [q1, q2, q3, q4, q5, q6, q7, q8, q9, q10];
let count = 0;
for (var i = 0; i < radios.length; i++) {
radios[i].addEventListener('change', (e) => {
if (count === 3) {
referralModal.style.display = 'block';
}
count++;
});
}

javascript get value of control in list item

I have an un-ordered list with items that are generated programatically in web2py...
I'm displaying them in HTML as displayed below... I want to have a textbox that allows a user to type in a string. this string should "toggle" the visibility of the <li> values if they match or not.
<input type="text" id="userTextSearch" onkeyup="listSearch(this.value)"></input>
<ul id="fileResultsID">
{{for item in mylist:}}
<li>
<input type="checkbox" name="FileListItem" id="value"> {{=item}}</label>
</li>
{{pass}}
</ul>
function listSearch(textValue)
{
var fileGroup = document.getElementById('fileResultsID');
var items = fileGroup.getElementsByTagName('li');
var chkBx;
for(var i = 0, n = items.length; i < n; i++)
{
chkBx = items[i].getElementsByTagName('input');
alert(chkBx.InnerHtml);
//if(!items[i].value.startswith(textValue))
//{
// items[i].toggle();
//}
}
}
So far when I type, nothing visible occurs...
Q: How can get certain <li> row items to disappear as the user types?
I will need them all to comeback if the text box is empty too btw
This is what worked for me... I also have a quick loop to renable all of the list items if the textbox is cleared out.
function listSearch(textValue){
var fileGroup = document.getElementById('fileResultsID');
var items = fileGroup.getElementsByTagName('li');
var chkBx;
//check to see if user deleted everything first
if(!textValue)
{
for(var i = 0, n = items.length; i < n; i++)
{
items[i].style.display = "block";
}
}
for(var i = 0, n = items.length; i < n; i++)
{
chkBx = items[i].getElementsByTagName('input');
var str = chkBx[0].id
if(!str.toLowerCase().startsWith(textValue.toLowerCase()))
{
items[i].style.display = "none";
}
}}

How to create a tabbed interface in Javascript

I'm trying to create a tabbed interface in Javascript which will allow a user to click on a button atop each interface in order to make the div under it become active while the other 'tabs'/divs recede to the background. I'm not quite sure I got that out right so attached is a screenshot of what I'm trying to make:
My code attaches one button -- beside the first div-- instead of all three and returns an error that says nodeChildren[j].getAttribute("data-tabname") is not a function although as far as I know, it seems it is.
I'll post my JavaScript code then add a link to fiddle where everything is.
function asTabs(node) {
var button = document.createElement("BUTTON");
var tempArray = [];
var nodeChildren = Array.prototype.slice.call(node.childNodes);
nodeChildren.filter(function(){
for (var i = 0; i < nodeChildren.length; i++) {
if (nodeChildren[i].nodeType === 1) {
tempArray += nodeChildren[i];
return tempArray;
}
}
});
nodeChildren.forEach(function (){
for (var j = 0; j < nodeChildren.length; j++) {
node.insertBefore(button, nodeChildren[j]);
var buttons = document.getElementsByTagName("button");
for (var k = 0; k < buttons.length; k++) {
buttons[k].innerHTML = nodeChildren[j].getAttribute("data-tabname").textContent;
}
}
});
var hide = nodeChildren.slice(1);
for (var l = 0; l < hide.length; l++) {
hide[l].className = "hide";
}
buttons[k].addEventListener("click", function (){
if (nodeChildren[j].className = "") {
nodeChildren[j].className = "hide";
}
else nodeChildren[j].className = "";
});
}
asTabs(document.querySelector("#wrapper"));
Then here's my fiddle containing comments explaining what is being tried to achieve on each line
https://jsfiddle.net/nmeri17/nmswdota/

Categories