Loop through localStorage and show specific value on click - javascript

I need to make a shopping cart for my library project the issue here is that on a click of a certain book I cannot add it in another localStorage.
This is my html <!--Knjige-->
<div class="container grid" id='knjige'></div>
This is my CSS:
.container{
margin: 50px; }
.grid{
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-gap: 20px;
align-items: start; }
.grid-card{
border: 1px solid #ccc;
box-shadow: 2px 2px 6px 0px rgba(0,0,0,0.3);
background: orange;
z-index: 9; }
.text:hover{
color: #fff;
cursor: pointer; }
.text{
padding: 0 20px 20px;
color: black;
font-weight: bold; }
And this is my JavaScript, please note that I'm not allowed to use jQuery
let knjige = [
{"Naziv":"4_50 From Paddington_ A Miss Marple Mystery",
"ID":"XA7JORPL",
"Autor":"Agatha Christie",
"Godina":"2007",
"Cena":546,
"Raspolozivo_stanje":50,
},
{"Naziv":"Lord Edgware Dies (1986, Berkley)",
"ID":"BPL6QUG5",
"Autor":"Agatha Christie",
"Godina":"1986",
"Cena":1041.06,
"Raspolozivo_stanje":15,
},
{"Naziv":"Murder at the Vicarage (2000, Signet)",
"ID":"T2CGKTQQ",
"Autor":"Agatha Christie",
"Godina":"2000",
"Cena":546,
"Raspolozivo_stanje":44,
},
{"Naziv":"Sparkling Cyanide (1989)",
"ID":"1QIFZZ4P",
"Autor":"Agatha Christie",
"Godina":"1989",
"Cena":1114.91,
"Raspolozivo_stanje":45,
},
{"Naziv":"The Mystery of the Blue Train",
"ID":"4C4XW7H2",
"Autor":"Agatha Christie",
"Godina":"1928",
"Cena":1041.06,
"Raspolozivo_stanje":"",
}
];
if(!localStorage.getItem('knjige')){
window.localStorage.setItem('knjige', JSON.stringify(knjige));
}
let knjigeLocalStorage = JSON.parse(window.localStorage.getItem('knjige'));
window.onload = function(show){
for(knjiga of knjigeLocalStorage){
show += `
<div class='grid-card'>
<div class='text'>
<h4>Naziv: ${knjiga.Naziv}</h4>
<p>Autor: ${knjiga.Autor}</p>
<p>ID: ${knjiga.ID}</p>
<p>Godina: ${knjiga.Godina}</p>
<p>Cena: ${knjiga.Cena}</p>
<p>Raspolozivo Stanje: ${knjiga.Raspolozivo_stanje}</p>
<button class='btn' id='dugme' onclick=''><i class="fas fa-shopping-cart"></i></button>
</div>
</div>
`;
};
document.getElementById('knjige').innerHTML = show;
};
So basically what I want is when I click on that button to show value of that specific book, hope I was clear..
Thanks!

You have a mis-typed value here: for(knjiga of knjigeLocalStorage){
innerHTML is going to give you all sorts of
problems with your onclick events and rendering html
I prefer to use addEventListener and adding elements via the DOM. It's a bit old school.
document.addEventListener("DOMContentLoaded", (event) => {
const div = document.getElementById('knjige');
knjigeLocalStorage.forEach((k) => {
const d = document.createElement("div");
d.classList.add("grid-card");
const text = document.createElement("div");
text.classList.add("text");
const h4 = document.createElement("h4");
h4.innerHTML = `Naziv ${k.Naziv}`;
const button = document.createElement("button");
const i = document.createElement("i");
i.classList.add("fas", "fa-shopping-cart");
button.appendChild(i);
button.addEventListener("click", () => {
alert(`Naziv ${k.Naziv}`);
});
text.append(h4);
text.append(button);
d.appendChild(text);
div.appendChild(d);
});
});
Try this fiddle:
https://jsfiddle.net/2cor9v1w/
document.addEventListener("DOMContentLoaded") Doesn't work for me with JSFiddle, but you may need it for your actual code to replace window.onload.

Related

How do I make it so only one element is shown at once?

When the box is clicked on the insides for each of the boxes are shown, I only want one to show up at a time.
function select() {
const outside = document.querySelectorAll('.box')
const insides = document.querySelectorAll('.insides')
insides.forEach(insides => {
outside.forEach(box => {
box.addEventListener('mouseenter', (e) => {
box.setAttribute("id", "selected")
box.addEventListener('click', (e) => {
box.classList.add('hover')
if (document.getElementById('selected')) {
insides.classList.add('insidesHover')
}
})
})
box.addEventListener('mouseleave', (e) => {
box.classList.remove('hover')
box.setAttribute('id', 'testBox')
insides.classList.remove('insidesHover')
})
})
})
}
function newOption() {
var optionRow = document.createElement("div");
optionRow.setAttribute("class", "answers");
optionRow.setAttribute("id", "optionRow");
var option = document.createElement("input");
option.setAttribute("type", "radio");
option.setAttribute("name", "options");
option.setAttribute("id", "options");
var optionBox = document.createElement("div");
optionBox.setAttribute("class", "answerContainer")
optionBox.setAttribute("id", "optionBox")
var text = document.createElement("input");
text.setAttribute("type", "text");
text.setAttribute("name", "option");
text.setAttribute("id", "option");
text.setAttribute("placeholder", "Enter Option");
optionBox.append(optionRow);
optionRow.append(option);
optionRow.append(text);
document.getElementById("selected").append(optionRow);
array()
}
.testContainer {
width: 50%;
margin-left: 25%;
margin-top: 1%;
padding: 1%;
background-color: #333;
height: auto;
color: white;
}
.box {
background-color: white;
color: black;
padding: 25px;
border: 5px blue solid;
}
.hover {
border: #780119 5px solid;
}
.insides {
display: none;
}
.insidesHover {
display: flex;
}
.buttons {
display: none;
}
.buttonsHover {
display: flex;
height: 25px;
width: 25px;
border: 1px solid black;
border-radius: 100%;
}
<div class="testContainer">
<div class="box">
<div class="insides" id="testBox">
<input type="text" class="insidesHover">
<button onclick="newOption()" class="buttonsHover"> </button>
</div>
</div>
</div>
<div class="testContainer">
<div class="box">
<div class="insides" id="testBox">
<input type="text" class="insidesHover">
<button onclick="newOption()" class="buttonsHover"> </button>
</div>
</div>
</div>
<div class="testContainer">
<div class="box">
<div class="insides" id="testBox">
<input type="text" class="insidesHover">
<button onclick="newOption()" class="buttonsHover"> </button>
</div>
</div>
</div>
So the problem I am having is that I want to use a querySelectorAll() for the class of .box, which on click changes the outline to show it is being selected. Which is something that is fully functional and works. However, I also want it to show the inside pieces on click as well but only for one box at a time, which on the event listener of leave will disappear again. Once the inside of adding new options goes away, I need the options that were put in to stay. I have tried putting everything in one div class where the opacity is set to 0, but it makes it so the new options don't stay visible. I have also tried rearranging the variables so that the insides are affected first, which had no effect on the actual functionality. I believe the true issue lies in the fact that when the id, selected, is active it triggers all boxes to be active instead of individual ones. I am not entirely sure how to go about rectifying this issue and would like some advice on moving forward. If you have any questions or if something needs clarification please let me know! Thank you for your time and wish you all a good day!

Is there an alternative to foreach in Js?

I have several identical divs and each of them contains a button that is hidden. I want to make button visible when you hover on the parent div. I wrote this code:
const cardElements = document.querySelectorAll('.middle_section__president_section');
const learnButtons = document.querySelectorAll('.president_section__button');
cardElements.forEach((cardElement) => {
cardElement.addEventListener('mouseover', () => {
learnButtons.forEach((learnButton) => {
learnButton.style.height = "50px";
learnButton.style.opacity = "1";
learnButton.style.border = "3px solid rgb(129, 129, 129)";
});
});
cardElement.addEventListener('mouseout', () => {
learnButtons.forEach((learnButton) => {
learnButton.style.height = "0px";
learnButton.style.opacity = "0";
learnButton.style.border = "0px solid rgb(129, 129, 129)";
});
});
})
carElements is parent, learnButtons - child.
but with this code when i hover on one div buttons appears in every similiar div. How can i make button appear only on hovered div?
Use the Event object
cardElement.addEventListener('mouseover', () => {
learnButtons.forEach((learnButton) => {
convert this to
cardElement.addEventListener('mouseover', (e) => {
var learnButton = e.target;
There's no need to use JS for this. As Mister Jojo/traktor pointed out in their comments you can use the CSS :hover pseudo-class instead.
The key CSS line is .box:hover button { visibility: visible;} which means "when you hover over the parent container make its button visible".
.box { width: 50%; display: flex; flex-direction: column; border: 1px solid lightgray; margin: 0.25em; padding: 0.25em;}
button { visibility: hidden; margin: 0.25em 0; border-radius: 5px; background-color: lightgreen; }
.box:hover button { visibility: visible;}
.box:hover, button:hover { cursor: pointer; }
<section class="box">
Some text
<button>Click for a surprise!</button>
</section>
<section class="box">
Some text
<button>Click for a surprise!</button>
</section>
<section class="box">
Some text
<button>Click for a surprise!</button>
</section>
It is bad practice to iterate over all elements and give each an event, as you can add 1 event handler to the parent and when the event happens you can check the affected element by the event parameter in the handler call back
parent.addEVentListener('mouseover', (e) => {
if(e.target.classList.contains('middle_section__president_section')) {
// Do
}
});

How to correctly add CSS to input element through JavaScript

I have an input field with the class 'device_1' which has a css style applied to it. The function 'createNewInputField()'created new input field with the class 'device_2'. Every new field creation creates a new class name. I want to apply the same CSS style applied to 'device_1' to the newly created fields ('device_2', ... , 'device_X'). I have a function 'addStyle()' that is supposed to do exactly this but it does not actually apply the style.
var idNumber= 1;
var deviceID = "device_"+idNumber;
var kWattID = "kW_"+idNumber;
var hoursID = "hours_"+idNumber;
var totalID = "total_"+idNumber;
function createNewInputFields() {
idNumber = idNumber+1;
deviceID = "device_"+idNumber;
const containerDevice = document.getElementById('deviceCol');
const inputHtmlDevice = "<br><input type='text' id='"+deviceID+"' required>";
containerDevice.insertAdjacentHTML('beforeend', inputHtmlDevice);
containerDevice.style(addStyle(containerDevice, idNumber));
return idNumber;
}
function addStyle(container, number){
var styles = `
#device_`+number+`{
text-align: center;
border-radius: 10px;
border:solid #2b2b2b;
border-width: 2px;
}
`
return styles
}
#device_1{
text-align: center;
border-radius: 10px;
border:solid #2b2b2b;
border-width: 2px;
}
<div class="calculationSection">
<h1 class="energytitle">Energy calculations</h1>
<div class="row_2">
<div class="deviceCol" id="deviceCol">
<p><b>Device</b></p>
<input type="text" id="device_1" required>
</div>
<div class="addButton">
<button class="btn" onclick="createNewInputFields()"> Add device </button>
</div>
</div>
The error says it loud and clear containerDevice.style is not a function. To add styles, you need to add them one at a time as properties, like
containerDevice.style.backgroundColor = '#000'
but it's far more efficient and better practice to create actual styles in your css for this and just add or remove them
css:
.elementcss {
text-align: center;
border-radius: 10px;
border:solid #2b2b2b;
border-width: 2px;
}
javscript:
document.querySelector('.element').classList.add('elementcss')
document.querySelector('.element').classList.remove('elementcss')

Is there a way to change a function by clicking on different divs?

I just started school, and this is my first question ever asked on Stackoverflow, so I apologize up front regarding both formatting and wording of this question.
I want to change the border color of my div to a style I have already declared when I click on it. To show that this has been selected.
I have three divs with id="red/green/pink".
Now, is there a way to change this function to grab information from the div I clicked, so I dont have to write 3 (almost) identical functions?
.chosenBorder{
border: 3px solid gold;
}
<div id="red" class="mainDivs" onclick="newColor('red')">Red?</div>
<div id="green" class="mainDivs" onclick="newColor('green')">Green?</div>
<div id="pink" class="mainDivs" onclick="newColor('pink')">Pink?</div>
<div class="mainDivs" onclick="whatNow(changeBig)">Choose!</div>
<script>
let changeBig = "";
let chosenDiv = document.getElementById("body");
function newColor(thisColor) {
changeBig = thisColor;
// something that make this part dynamic.classList.toggle("chosenBorder");
}
function whatNow(changeBig) {
document.body.style.backgroundColor = changeBig;
}
</script>
Since you already have an id contains the name of color; get the advantage of it: and keep track of the selected color in your variable changeBig.
let changeBig = "";
function newColor(div) {
// initial all divs to black
initialDivs();
div.style.borderColor = div.id;
changeBig = div.id;
}
function initialDivs() {
[...document.querySelectorAll('.mainDivs')].forEach(div => {
div.style.borderColor = 'black'
});
}
function whatNow() {
document.body.style.backgroundColor = changeBig;
}
.mainDivs {
padding: 10px;
margin: 10px;
border: 3px solid;
outline: 3px solid;
width: fit-content;
cursor: pointer;
}
<div id="red" class="mainDivs" onclick="newColor(this)">Red?</div>
<div id="green" class="mainDivs" onclick="newColor(this)">Green?</div>
<div id="pink" class="mainDivs" onclick="newColor(this)">Pink?</div>
<div class="mainDivs" onclick="whatNow()">Choose!</div>
There are a few (modern) modifications you can make to simplify things.
Remove the inline JS.
Use CSS to store the style information.
Use data attributes to store the colour rather than the id.
Wrap the div elements (I've called them boxes here) in a containing element. This way you can use a technique called event delegation. By attaching one listener to the container you can have that listen to events from its child elements as they "bubble up" the DOM. When an event is caught it calls a function that 1) checks that the event is from a box element 2) retrieves the color from the element's dataset, and adds it to its classList along with an active class.
// Cache the elements
const boxes = document.querySelectorAll('.box');
const container = document.querySelector('.boxes');
const button = document.querySelector('button');
// Add a listener to the container which calls
// `handleClick` when it catches an event fired from one of
// its child elements, and a listener to the button to change
// the background
container.addEventListener('click', handleClick);
button.addEventListener('click', handleBackground);
function handleClick(e) {
// Check to see if the child element that fired
// the event has a box class
if (e.target.matches('.box')) {
// Remove the color and active classes from
// all the boxes
boxes.forEach(box => box.className = 'box');
// Destructure the color from its dataset, and
// add that to the class list of the clicked box
// along with an active class
const { color } = e.target.dataset;
e.target.classList.add(color, 'active');
}
}
function handleBackground() {
// Get the active box, get its color, and then assign
// that color to the body background
const active = document.querySelector('.box.active');
const { color } = active.dataset;
document.body.style.backgroundColor = color;
}
.boxes { display: flex; flex-direction: row; background-color: white; padding: 0.4em;}
.box { display: flex; justify-content: center; align-items: center; width: 50px; height: 50px; border: 2px solid #dfdfdf; margin-right: 0.25em; }
button { margin-top: 1em; }
button:hover { cursor: pointer; }
.box:hover { cursor: pointer; }
.red { border: 2px solid red; }
.green { border: 2px solid green; }
.pink { border: 2px solid pink; }
<div class="boxes">
<div class="box" data-color="red">Red</div>
<div class="box" data-color="green">Green</div>
<div class="box" data-color="pink">Pink</div>
</div>
<button>Change background</button>

How to link HTML Element with Python function in Jupyter notebook?

I've written JavaScript code that shows a custom right click menu.
I'd like to know how to trigger Python functions upon my menu items being clicked. These menu items are the divs nested under the div with the class of menu, which consequently is the only element in the body section of my HTML.
The environment I'm using is Jupyter Notebook.
notebook.
import jinja2
from bokeh.embed import components
template = jinja2.Template("""
<!doctype html>
<html>
<head>
<script>
src="http://cdn.pydata.org/bokeh/dev/bokeh-0.13.0.min.js"
var menuDisplayed = false;
var menuBox = null;
window.addEventListener("contextmenu", function() {
var left = arguments[0].clientX;
var top = arguments[0].clientY;
menuBox = window.document.querySelector(".menu");
menuBox.style.left = left + "px";
menuBox.style.top = top + "px";
menuBox.style.display = "block";
arguments[0].preventDefault();
menuDisplayed = true;
}, false);
window.addEventListener("click", function() {
if(menuDisplayed == true){
menuBox.style.display = "none";
}
}, true);
</script>
<style>
.menu
{
width: 150px;
box-shadow: 3px 3px 5px #888888;
border-style: solid;
border-width: 1px;
border-color: grey;
border-radius: 2px;
padding-left: 5px;
padding-right: 5px;
padding-top: 3px;
padding-bottom: 3px;
position: fixed;
display: none;
}
.menu-item
{
height: 20px;
}
.menu-item:hover
{
background-color: #6CB5FF;
cursor: pointer;
}
</style>
</head>
<body>
<div class="menu">
<div class="menu-item">Add Node</div>
<div class="menu-item">Delete Node</div>
<div class="menu-item">Update Node</div>
</div>
</body>
</html>
""")
I think you will get clear understanding and clarity on this with below example easily:
// %%javascript
window.executePython = function(python) {
return new Promise((resolve, reject) => {
var callbacks = {
iopub: {
output: (data) => resolve(data.content.text.trim())
}
};
Jupyter.notebook.kernel.execute(`print(${python})`, callbacks);
});
}
// Use it in any Jupyter JS/HTML cell like this
%%javascript
window.executePython("1 + 1")
.then(result => console.log(result)); // Logs 2
// You can access any defined object/method in the notebook
// I suggest writing a function that returns your data as JSON and just calling the function.

Categories

Resources