So I have this function here:
const printCardList = (arr) => {
const uo_list = document.getElementById("verify_list");
arr.forEach((card) => {
let list_item = document.createElement("LI");
let str = card.name + " " + card.mana_cost + " " + card.set_name;
list_item.appendChild(document.createTextNode(str));
uo_list.appendChild(list_item);
});
};
and its suppose to insert list items into and unorder list from an array of card objects.
return(
<div className="list-confirm">
<h3> Please confirm card list </h3>
<ul id="verify_list"></ul>
<br />
<button onClick={getCardList}>Confirm</button>
</div>
);
If I do a console.log on arr I can verify that it is an array of cards, but if I console.log card from inside the for each it does not even trigger. It's like the for each does not run. Does anyone have an idea why this is happening?
I'm not sure what you are trying to do, the first part of your code is plain javascript that manipulates the DOM, while the second part is react js object.
You normally don't want to mix these two, either you code your javascript as part of the html, like the first part, or - if you want to create an array of cards in react you can do something like:
let cardList = arr.map(card => {
listItem = <li>{card.name + " " + card.mana_cost + " " + card.set_name }</li>
return listItem;
})
return(
<div className="list-confirm">
<h3> Please confirm card list </h3>
<ul id="verify_list">{cardList}</ul>
<br />
<button onClick={getCardList}>Confirm</button>
</div>
);
what I did is assigned the list itself to a variable named 'cardList', JSX object are just javascript objects, so you can assign them to a variable or return then from a function.
to place the card list inside the page (or component), you can just use the {} notation, which will embed the cardList object as part of the returned JSX object.
Thanks for all the advice. In hindsight, I should have stuck to what I was learning and not try to freestyle. React is about using states. So rather than having a function that will generate HTML from an array of data and I had to do use "the state". Then code the render to loop through the list of cards when the button is pressed.
const [state, setState] = useState([]);
const card_list= ()=> {...}
const changeState = ()=> {setState(card_list)}
return(
<div className="list-confirm">
<h3> Please confirm card list </h3>
<ul>
{state.map((card) => (
<li>{card.name}</li>
))}
</ul>
<br />
<button onClick={changeSate}>Confirm</button>
</div>
);
You should change the onClick. More precisely call the method after getting items from getCardList() method.
This is an example:
const printCardList = (arr) => {
const uo_list = document.getElementById("verify_list");
arr.forEach((card) => {
let list_item = document.createElement("li");
let str = card.name + " " + card.mana_cost + " " + card.set_name;
list_item.appendChild(document.createTextNode(str));
uo_list.appendChild(list_item);
});
};
// this is a test method. Not the real one
const getCardList = () => {
return [ { name: "Card", mana_cost: 0, set_name: "Set: Card" } ];
};
<div className="list-confirm">
<h3> Please confirm card list </h3>
<ul id="verify_list"></ul>
<br />
<button onClick="printCardList(getCardList())">Confirm</button>
</div>
Related
I have this piece of code that reads data from an excel sheet, turns them into objects and then display their details in a neat product card
let allHoodies = [
['Hoodie', 'Purple', 'Cotton', '$39.99', 'image/items/hoodies/hoodie(1).jpg'],
['Hoodie', 'Blue', 'Cotton', '$39.99', 'image/items/hoodies/hoodie(2).jpg'],
['Hoodie', 'Green', 'Cotton', '$39.99', 'image/items/hoodies/hoodie(3).jpg']
]
allHoodies.forEach((element, index) => {
let obj = {}
obj.id = index
obj.type = element[0]
obj.color = element[1]
obj.material = element[2]
obj.price = element[3]
obj.imagesrc = element[4]
allHoodies[index] = obj
})
//Evaluating each hoodie and displaying its information in HTML
allHoodies.forEach(function(hoodie) {
let card = `
<div class="card">
<img class="product-image" src="${hoodie.imagesrc}">
<h1 class="product-type">${hoodie.type}</h1>
<p>Color: ${hoodie.color}</p>
<p>${hoodie.material} Read more </p>
<p class="price">${hoodie.price}</p>
<p><button>Buy</button></p>
</div>
`;
// Add the card to the page
document.getElementById('product-container').innerHTML += card;
});
What I'm trying to do is, upon clicking "Buy", it adds multiple items to the local storage although I'm struggling to do it and add multiple ones, it keeps on adding only 1 of them and overwriting the previous one (I'm assuming due to the fact that they have the same key)
Here's what I've tried (which works, but its not my goal):
function addToCart(id){
let hoodie = hoodies[id];
localStorage.setItem('item', JSON.stringify(hoodie));
}
and then I simply add the addToCart() function to the button, would someone guide me and help me figure out how I could actually add multiple ones to the local storage and not just keep overwriting?
Expected result:
Runnable JSFiddle snippet
You can use localStorage#getItem to get the current list, and JSON#parse to convert it to an array of objects. Then, use Array#push to add the current item, and finally, use localStorage#set and JSON#stringify to save the updated list:
function addToCart(id) {
try {
const hoodie = allHoodies[id];
if(hoodie) {
const items = JSON.parse(localStorage.getItem('items') || "[]");
items.push(hoodie);
localStorage.setItem('items', JSON.stringify(items));
}
} catch(e) {
console.log('error adding item');
}
}
Function to show the saved list:
function displayProductsinCart() {
const products = JSON.parse(localStorage.getItem("item") || "[]");
document.getElementById("item-container").innerHTML = products.reduce((cards, product) =>
cards + `<div class="card">
<img class="item-image" src="${product.image}">
<h1 class="product-type">${product.type}</h1>
<p>Color: ${product.color}</p>
<p>${product.description}</p>
<p class="price">${product.price} </p>
<p><button>Buy</button></p>
</div>
`, '');
}
I am a beginner in JavaScript and I can't figure out the following problem: I am trying to create a simple JavaScript Movie List. I have 10 lists on the Movie List. I tried to show all of the lists with for loop, but it doesn't work.
Here's the code:
function renderModal() {
for (let i = 0; i < listMovies.length; i++) {
let movieData = listMovies[i];
document.getElementById("poster").src = movieData.img;
document.getElementById("title").innerHTML = movieData.name;
document.getElementById("genre").innerHTML = movieData.genre;
document.getElementById("rating-num").innerHTML = "Rating: "+ movieData.rating + "/10";
document.getElementById("movie-desc").innerHTML = movieData.desc;
document.getElementById("imdb-page").href = movieData.link;
return movieData;
}
}
What do I have to do?
Help me to fix it!.
You can use template tag for list and render it into target element.I am showing an example.
Movie list
<div id="movieList"></div>
template for list
<template id="movieListTemplate">
<div class="movie">
<img src="" class="poster" alt="">
<div class="title"></div>
<div class="genre"></div>
<div class="rating-num"></div>
<div class="movie-desc"></div>
<div class="imdb-page"></div>
</div>
</template>
Javascript code:
if (listMovies.length > 0) {
const movileListTemplate = document.getElementById('movieListTemplate')
const movieRenederElement = document.getElementById('movieList')
for(const movie of listMovies) {
const movieEl = document.importNode(movileListTemplate.content, true)
movieEl.querySelector('.poster').src = movie.img
movieEl.querySelector('.title').textContent = movie.name
//use all queryselector like above
}
}
Your return movieData; will stop the loop dead. Not that running it more than once will change anything since you change the same elements over and over. IDs must be unique.
Here is a useful way to render an array
document.getElementById("container").innerHTML = listMovies.map(movieData => `<img src="${movieData.img}" />
<h3>${movieData.name}</h3>
<p>${movieData.genre}</p>
<p>Rating: ${movieData.rating}/10</p>
<p>${movieData.desc}
IMDB
</p>`).join("<hr/>");
With return movieData, the for loop will ends in advance.You should put it outside the for loop.
I have set up a conditional element on click on a button I've made within react. but default prop runs onload without clicking the button how can I fix this issue?
the button looks like this:
<p onClick={Butter + Milk + Bread + Soup + Cheese > 0 ? props.next_ClickHandler : alert('Please Input some food!')}>Buy Now!</p>
I would like it so that if the values add to greater than 0 the props are passed but if not an alert is played why it this not working as intended?
Edit full code:
import React, { useState, useEffect, useContext } from "react";
import Data from '../shoppingData/Ingredients';
import { quantitiesContext } from '../shoppingData/Quantities';
const ShoppingPageOne = (props) => {
//element displays
const [pageone_show, setPageone_show] = useState("pageOne");
//stores quantities of items as JSON objects
const [Quantities, setQuantities] = useContext(quantitiesContext);
const quantities = useContext(quantitiesContext);
const Bread = quantities[0].Bread.quantities;
const Milk = quantities[0].Milk.quantities;
const Cheese = quantities[0].Cheese.quantities;
const Soup = quantities[0].Soup.quantities;
const Butter = quantities[0].Butter.quantities;
useEffect(() => {
//sets info text using Json
if (props.showOne) {
setPageone_show("pageOne");
} else {
setPageone_show("pageOne hide");
}
}, [props.showOne]);
return (
<div className={"Shopping_Content " + pageone_show}>
<div className="Shopping_input_aligner">
<div className='Shopping_input_container'>
{Data.map((Ingredients) => {
//updates Quanties Hook
const handleChange = (event) => {
setQuantities({
...Quantities,
[Ingredients.Name]: {
...(Quantities[Ingredients.Name] ?? {}),
quantities: event.target.value
}
});
};
return (<div className={"Shopping_input " + Ingredients.Name} key={Ingredients.Name}>
<p>{Ingredients.Name} £{Ingredients.Price}</p>
<input onChange={handleChange.bind(this)} min="0" placeholder="Input food quantity" type="number"></input>
</div>)
})}
</div>
<div className='Discount_list'>
<h3>Discounts:</h3>
<li>Buy one cheese get one free!</li>
<li>Buy a Soup get a half price bread!</li>
<li>A third off butter!</li>
</div>
</div>
<div className="Shopping_Buttons">
<p onClick={() => {Butter + Milk + Bread + Soup + Cheese > 0 ? props.next_ClickHandler : alert('Please Input some food!')}} >Buy Now!</p>
</div>
</div>
);
};
export default ShoppingPageOne;
You can have a cleaner code with something like this if you're using React Hooks
const [ingredientsGreaterThanZero, setIngredientsGreaterThanZero] = useState(false);
useEffect(() => {
if (butter + milk + bread + soup + cheese > 0) {
setIngredientsGreaterThanZero(true)
} else {
setIngredientsGreaterThanZero(false)
}
}, [butter, milk, bread, soup, cheese]);
...
{ingredientsGreaterThanZero ?
<p onClick={props.next_ClickHandler}>Buy Now!</p> :
<p onClick={() => alert('Please Input some food!')}>Buy Now!</p>
}
<p onClick={() => { Butter + Milk + Bread + Soup + Cheese > 0 ? props.next_ClickHandler : alert('Please Input some food!')}}>Buy Now!</p>
Can you try using this?
Reason
If you attach any event in element with onClick() or any other event handler,
You shouldn't add any function invocation like in your example alert().
Because, of parentheses () the function runs when component mounted in dom.
Example:
<p onClick={alert('runs on load')}>wrong way</p>
Solution
You have to add an empty function and and writes your codes in it. If your codes contain function invocation ( with parentheses () ).
Example:
<p onClick={() => alert ('only runs on click')}>right way</p>
Happy Coding :)
Hello I am new to React and building a quote generator. I want to pull out one quote at a time from my array and show it on the screen, however I can only seem to output each quote to the console.
I have:
1.Created an on click handler and function so that when the user clicks my quote array is targeted.
2. In this function I have created a variable to hold my random array index
3. I have console.logged the array index to see if every time the user clicks it the quote appears.
Component and function and click handler, as you can see the Quote Component should return the quote from the array in my opinion but nothing happens:
class Card extends Component {
state = {
quotes: ['"A dream doesn\'t become reality through magic; it takes sweat, determination and hard work."','"You GOT this!"','"To be or not to be that is the question"'];
changeQuoteHandler = (event) => {
const quotes = [...this.state.quotes];
const arrayIndex = quotes[Math.floor(Math.random() * quotes.length)]
console.log(arrayIndex);
this.setState({
quotes: quotes
})
};
render(){
return (
<div className="Card">
<div>
<h2>Random Quote Generator</h2>
<Quote className="QuoteStyle" quote={this.state.quotes.arrayIndex}/>
</div>
<div className="Flex">
<div>
<NewQuoteButton onClick={this.changeQuoteHandler}/>
</div>
</div>
</div>
)
}
};
export default Card;
Quote Componenet :
import React from 'react';
const Quote = (props) => {
return(
<p>{props.quote}</p>
)
};
export default Quot
I would like to print one quote at a time to the screen on click.
You are so close. You can store the arrayIndex that you generate in the state and use it to display the quote. The code would look like something below
class Card extends Component {
state = {
quotes: ['"A dream doesn\'t become reality through magic; it takes sweat, determination and hard work."','"You GOT this!"','"To be or not to be that is the question"'],
selectedIndex: 0,
}
changeQuoteHandler = (event) => {
const quotes = [...this.state.quotes];
const arrayIndex = Math.floor((Math.random() * 10) % quotes.length);
this.setState({
quotes: quotes,
selectedIndex: arrayIndex,
});
};
render(){
return (
<div className="Card">
<div>
<h2>Random Quote Generator</h2>
<Quote className="QuoteStyle" quote={this.state.quotes[this.state.selectedIndex]}/>
</div>
<div className="Flex">
<div>
<NewQuoteButton onClick={this.changeQuoteHandler}/>
</div>
</div>
</div>
)
}
};
export default Card;
I have a props object, with a user comment array, and the userId array inside. Originally i only had the user comment array, and so i used the map function to style each comment individually. Now that i have two arrays inside my props object, is there a way to use the map function to style both the users comment and his id at the same time? Here is my attempt at it but it doesnt work:
import React from 'react'
import faker from 'faker'
const UserComment = (props)=> {
var commentData = props.map(props=> {
return(<StyleComment comment = {props.comment} key = {props.comment} author = {props.userIds} />)})
return(null)//commentData)
}
const StyleComment = (props) => {
// get time of comment
return(
<div className = 'comment'>
<a href="/" className= "avatar">
<img alt ="avatar" src= {faker.image.avatar()}/>
</a>
<div className = 'name'>
<a href ="/" className = "author">
{props.author}
</a>
<span className="metadata"> Today at 1.00pm </span>
<div className= 'content'>
<div className = 'text'>{props.comment}</div>
</div>
</div>
</div>
)
}
Here is the parent where the props are defined:
<UserComment comment = {this.state.usersComment} userIds = {this.props.userIds}/>
and here is a console.log of an example output for the props object:
You need to pass complete object to UserComment component,
<UserComment comment={this.state.usersComment} />
Then you can iterate like this,
const UserComment = (props)=> {
console.log(props.comment);
return props.comment.comment.map((comment,index) => {
return <StyleComment key={comment} comment={comment} author={props.comment.userIds[index]}/>
});
}
Demo
Note: Current array iteration and mapping is based on index, but you must have some relation between comment and userIds array to correctly map the data.