Not able to use a map function on an array of dictionaries - javascript

Hope someone can help me out.
I am trying to dynamically create some cards on my webpage out of a dictionary.
I tried to create the function but the code inside the first <div>
cards.map((character)=>(
is not recognizing the array of dictionaries.
Any ideas on how to fix it?
function MemoryCards() {
const images = [
"./img/Abadango.jpeg",
"./img/abradolf.jpeg",
"./img/Adjudicator.jpeg",
"./img/AgencyDirector.jpeg",
"./img/Alan.jpeg",
"./img/Albert.jpeg",
"./img/Alexander.jpeg",
"./img/AlienMorty.jpeg",
"./img/AlienRick.jpeg",
"./img/Annie.jpeg",
"./img/AntsJonson.jpeg",
"./img/Beth.jpeg",
"./img/Jerry.jpeg",
"./img/morty.jpeg",
"./img/ricky.jpeg",
"./img/summer.jpeg"
]
const cards = [];
let len = images.length;
for (let i = 0; i < len; i++) {
let end = images[i].indexOf('.', 3);
let name = images[i].substring(6, end);
let card = { 'name': name, 'img': images[i], 'id': i };
cards.push(card);
}
return (
<div>
cards.map((character)=>(
<div class="card">
<div className="card_header">
<img src={cards.img}></img>
</div>
<div className="card_body">
<h3>{cards.name}</h3>
</div>
</div>
))
</div>
)
}
export default MemoryCards;

Inside your loop you have {cards.img} and {cards.name} but what you want is {character.img} and {character.name}
Also you are missing curly brackets {} before initializing cards loop
Note, you have a typo, instead of className you have just class here: <div class="card">
function MemoryCards() {
const images = [
"./img/Abadango.jpeg",
"./img/abradolf.jpeg",
"./img/Adjudicator.jpeg",
"./img/AgencyDirector.jpeg",
"./img/Alan.jpeg",
"./img/Albert.jpeg",
"./img/Alexander.jpeg",
"./img/AlienMorty.jpeg",
"./img/AlienRick.jpeg",
"./img/Annie.jpeg",
"./img/AntsJonson.jpeg",
"./img/Beth.jpeg",
"./img/Jerry.jpeg",
"./img/morty.jpeg",
"./img/ricky.jpeg",
"./img/summer.jpeg"
];
const cards = [];
let len = images.length;
for (let i = 0; i < len; i++) {
let end = images[i].indexOf(".", 3);
let name = images[i].substring(6, end);
let card = { name: name, img: images[i], id: i };
cards.push(card);
}
return (
<div>
{cards.map((character, idx) => (
<div key={idx} className="card">
<div className="card_header">
<img src={character.img} alt="" />
</div>
<div className="card_body">
<h3>{character.name}</h3>
</div>
</div>
))}
</div>
);
}
export default MemoryCards;

You need to wrap your variables in curly braces {} for it to work inside JSX:
return (
<div>
{cards.map((card)=>(
<div key={card.name} class="card">
<div className="card_header">
<img src={card.img}></img>
</div>
<div className="card_body">
<h3>{card.name}</h3>
</div>
</div>
))}
</div>
)
In the example above, you can see that the entire map block should be inside the curly braces, also don't forget to add an ID to the element inside the map and to use the actual variable defined inside the map function

Related

List localStorage data

I have a question to save data with localStorage, it would be a shopping cart, it's getting now I need to list the data taken on the other page, I can list it through console.log, but I can't call the data, they can help ?
Page Product where, get the items
function handleCount(){
setItemCount(itemCount + parseInt(document.getElementById("quantity").value));
}
function saveCart(template){
let cartObject = parseCart() // {itemsCount: 1, itemsData: [{'name': pencil, 'quantity': 3, 'price': 2}]};
cartObject.itemsData.push(template)
let diversas_cart = {
'itemsCount': cartObject.itemsData.length,
'itemsData': cartObject.itemsData
};
localStorage.setItem('#diversas/cart', JSON.stringify(diversas_cart))
return 0;
};
function parseCart(){
let cartObject = JSON.parse(localStorage.getItem('#diversas/cart'));
console.log(cartObject)
if(cartObject !== null)
return cartObject;
return {itemsCount: 0, itemsData: []}
};
function addCart(productName, itemCount, price){
let template = {'name': productName, 'quantity': itemCount, 'price': price};
//cartItems.push(template);
saveCart(template);
}
let selectQuantity = []
for (let i = 1; i <= product?.quantity; i++) {
selectQuantity.push(<option value={i}>{i}</option>)
}
<Link to="/shopCart"><button type="button" className="btn btn-green btn-md btn-block" id="addProduct"
onClick={()=>{handleCount()
addCart(`${product?.productName}`, parseInt(document.getElementById("quantity").value), `${product?.price}`);
}}
>Buy{" "}</button></Link>
Page shopCart
let cart = JSON.parse(localStorage.getItem('#diversas/cart'));
var item0Name = cart[0].name;
{cart[0].map(item =>(
<div className="col-sm-12 col-md-3 col-lg-3 col-xl-2 col-main m-5">
<main>
<section>
<div className="card mb-3 mt-3 cardShop" key={item.id}>
<img class="card-img-top" src="" alt="" />
<div class="card-body"></div>
</div>
<h6>{item.name}</h6>
</section>
</main>
</div>
))}
enter image description here
You already have the parseCart() method in your code which returns the parsed cart data as an array. You can get the array by simply calling:
var cart = parseCart();
then you can use the following statements to get the data for each item:
var item0Name = cart[0].name;
var item1Name = cart[1].name;
var item0Quantity = cart[0].quantity;
var item1Quantity = cart[1].quantity;
Edit:
All you need is to use this statement:
var cart = JSON.parse(localStorage.getItem('#diversas/cart'));
var item0Name = cart[0].name;

How do I sort items by array?

I understand that the wording of the question is incorrect (if someone can write it correctly, please). The task is this, I have 30 elements on the page and I need to sort them with the resulting array. That is, I get an array - let order = [2, 5, 3, 6, 12 ...] and sorting should take place in accordance with this order, that is, the first element is the 2nd element from HTML, the second element is the 5th element from HTML (according to the given array). The initial order is equal to the number in data-custom-sort.
There will be many such an array. And I don't understand how to do it universally. Can someone have any ideas?
I have not formulated very well, so if you have questions - ask.
The HTML is something like this:
<a id="sort-best" class="choose-cat">best</a>
<div>
<article data-custom-sort="1">
...
</article>
<article data-custom-sort="2">
...
</article>
<article data-custom-sort="3">
...
</article>
//and etc
</div>
These are product cards in the catalog. I need to sort them
document.querySelector('#sort-best').onclick = sortBest;
function sortBest() {
let nav = document.querySelector('#game-items-cart');
for (let i = 0; i < nav.children.length; i++) {
for (let j = i; j < nav.children.length; j++) {
if (+nav.children[i].getAttribute('data-sort') > +nav.children[j].getAttribute('data-sort')) {
replaceNode = nav.replaceChild(nav.children[j], nav.children[i]);
insertAfter(replaceNode, nav.children[i]);
}
}
}
}
function insertAfter(elem, refElem) {
return refElem.parentNode.insertBefore(elem, refElem.nextSibling);
}
I used this code to sort through the data attributes. That is, the number in the data attribute = the ordinal after sorting.
Like this?
let order = [2, 1, 3];
const container = document.getElementById("container");
document.getElementById("sort-best").addEventListener("click", e => {
e.preventDefault()
order.forEach(idx => container.appendChild(container.querySelector("[data-custom-sort='" + idx + "']")))
})
<a id="sort-best" class="choose-cat">best</a>
<div id="container">
<article data-custom-sort="1">
One
</article>
<article data-custom-sort="2">
Two
</article>
<article data-custom-sort="3">
Three
</article>
</div>
More generic:
const sortArticles = (cont, order) => {
const container = document.getElementById(cont);
order.forEach(idx => container.appendChild(container.querySelector("[data-custom-sort='" + idx + "']")))
};
document.getElementById("sort").addEventListener("click", e => {
const tgt = e.target;
if (tgt.classList.contains("choose-cat")) {
e.preventDefault()
sortArticles("container", tgt.dataset.order.split(","))
}
})
<div id="sort">
<a id="sort-best" class="choose-cat" data-order="3,1,2">best</a> |
<a id="sort-default" class="choose-cat" data-order="1,2,3">default</a>
</div>
<div id="container">
<article data-custom-sort="1">
One
</article>
<article data-custom-sort="2">
Two
</article>
<article data-custom-sort="3">
Three
</article>
</div>
Here is another way of doing this
// Sort reference array
const sortRef = [2, 5, 3, 1, 4];
// Get, sort, update function
const sortFn = () => {
// Apply new order by sorting and replacing sortContainer content
const newArray = [];
for(let i = 0; i < sortRef.length; i++) newArray.push(document.querySelector("[data-custom-sort='" + sortRef[i] + "']").outerHTML);
// Update html
document.getElementById("sortContainer").innerHTML = newArray.join('');
}
// Add click event
document.getElementById("clickMe").addEventListener('click', event => {
sortFn();
});
article {
border: 1px solid #ff0000;
padding: 3px;
width: 100px;
}
<div id="sortContainer">
<article data-custom-sort="1">
1
</article>
<article data-custom-sort="2">
2
</article>
<article data-custom-sort="3">
3
</article>
<article data-custom-sort="4">
4
</article>
<article data-custom-sort="5">
5
</article>
</div>
<p></p>
<button id="clickMe">Sort html data</button>

How to add different images in three divs using the same class

I have this code:
<div class="main_flex">
<div class="flex_items">
</div>
<div class="flex_items">
</div>
<div class="flex_items">
</div>
</div>
javascript:
function shoe_images () {
for (var i = 0; i < shoes.length; i++){
var getFlexItems = document.querySelector('.flex_items');
var createImgTag = document.createElement('img');
createImgTag.src = shoes[i].imageUrl;
getFlexItems.appendChild(createImgTag);
}
};
And i have an array of object with different images. I want to add different images to the
class="flex_items"
How do i do that? I used a for loop, but all the images shows in the first class="flex_items".
The problem is in the querySelector() method. This method return only the first element. It is the reason for this.
See: https://www.w3schools.com/jsref/met_document_queryselector.asp
You need to use querySelectorAll()
See: https://www.w3schools.com/jsref/met_document_queryselectorall.asp
Rewrited your code:
function shoe_images () {
var getFlexItems = document.querySelectorAll('.flex_items');
for (var i = 0; i < shoes.length; i++){
var createImgTag = document.createElement('img');
createImgTag.src = shoes[i].imageUrl;
getFlexItems[i].appendChild(createImgTag);
}
you can do this by css or by js
this for CSS
.flex_items:nth-of-type(2) {
background: #ff0000;
}
.flex_items:nth-of-type(1) {
background: #324445;
}
to used js
var elements = document.getElementsByClassName('flex_items');
it will return arry contain 3 elment [0,1,2]
elements[0].innerHTML ='<img src="path">';
elements[1].innerHTML ='<img src="path">';
You can select the flex_items then append the element image like this:
const images = [{
src: "https://picsum.photos/id/284/200/300"
}, {
src: "https://picsum.photos/id/284/200/300"
}, {
src: "https://picsum.photos/id/284/200/300"
}]
document.querySelectorAll(".flex_items").forEach((el, index) => {
const image = document.createElement("img");
image.setAttribute("src", images[index].src);
el.appendChild(image);
})
<div class="main_flex">
<div class="flex_items">
</div>
<div class="flex_items">
</div>
<div class="flex_items">
</div>
</div>

Why can I only fire this function once?

I have this function:
const sliderTextChange = document.getElementsByClassName('slider') // text change
const changeSliderText = change => {
const sliderLeft = document.getElementsByClassName('switch-left')
const sliderRight = document.getElementsByClassName('switch-right')
for (let i = 0; i < change.length; i++) {
change[i].addEventListener('click', () => {
sliderRight[i].style.display = 'flex';
sliderLeft[i].style.display = 'none';
});
}
}
changeSliderText(sliderTextChange);
This is one of the many sliders on the website:
<div class="flex-column">
<h3>Text Colour</h3>
<div class="slider">
<div class="slider-back"></div>
<div class="slider-circle"></div>
</div>
<h3 class="switch-left">White</h3>
<h3 class="switch-right">Black</h3>
</div>
This function is quite a lot like many other functions in my code but they're only firing once. AKA I fire the event listener and but then I can't fire it again.
What's the issue here?
I have tried to simplify your code and keep the scope to be modular and reusable view.
function bindEvent() {
const sliderList = document.querySelectorAll('.slider');
[...sliderList].forEach((slider) => slider.addEventListener('click', () => {
const left = slider.parentElement.querySelector('.switch-left');
const right = slider.parentElement.querySelector('.switch-right');
const leftDisplay = left.style.display || 'flex';
const rightDisplay = right.style.display || 'none';
left.style.display = rightDisplay;
right.style.display = leftDisplay;
}, false));
}
window.onload = bindEvent;
<div>
<button class="slider"> - SLIDER 1 - </button>
<div class="switch-left">L</div><div class="switch-right">R</div>
</div>
<div>
<button class="slider"> - SLIDER 2 - </button>
<div class="switch-left">L</div><div class="switch-right">R</div>
</div>
<div>
<button class="slider"> - SLIDER 3 - </button>
<div class="switch-left">L</div><div class="switch-right">R</div>
</div>
<div>
<button class="slider"> - SLIDER 4 - </button>
<div class="switch-left">L</div><div class="switch-right">R</div>
</div>
Parameters you have chosen for your function are not really intuitive and make your example more complex.
We use querySelector, it's nicer to read but if you prefer speed, just go for getElementsByClassName, it also works on any DOM element.

react.js every nth item add opening tag or closing tag

I'm having trouble with this logic since react/jsx does not allow for non closing tags to be added to an array/child component. For example with bootstrap css I want to add a row for every 4 columns.
So the logic is as follows:
Add a opening row ex: <div className="row">, then loop inside this row and every loop append a column ex: <div className="column>{this.data}</div> when the loop reaches 4 check with if(i % 4 == 0) and add a closing </div> tag while adding new row tag <div className="row">;
The code below would work in another language but in react this is not doable since we push a closing tag and a opening tag (which is invalid jsx):
generateColumns(columns) {
let newColumns = [];
columns.forEach(function(column, idx) {
newColumns.push( <div className="column"> some data </div> );
if (idx % 4 == 0) {
// Here we end the row and start a new row, works in any other language.
newColumns.push( </div> <div className="row"> );
}
});
// This array now has the proper tags for opening a row every 4th item and closing it.
return newColumns;
},
render() {
return (
<div className="row">
{this.generateColumns(this.props.columns)}
</div>
)
}
The expected output would be:
<div class="row">
<div class="column">
Some data
</div>
<div class="column">
Some more data
</div>
<div class="column">
Other data
</div>
<div class="column">
Something else
</div>
</div>
<div class="row">
<div class="column">
Some data
</div>
<div class="column">
Some more data
</div>
<div class="column">
Other data
</div>
<div class="column">
Something else
</div>
</div>
//the above would be repeated and new rows would appear every 4 columns.
render() {
const rows = array_chunk(this.props.columns, 4)
return (
{
rows.map((row) => (
<div className="row">
{
row.map((col) => (
<div className="col">{ col }</div>
))
}
</div>
))
}
)
}
An example array_chunk (I recommend that you use lodash)
module.exports = function chunks(arr, size) {
if (!Array.isArray(arr)) {
throw new TypeError('Input should be Array');
}
if (typeof size !== 'number') {
throw new TypeError('Size should be a Number');
}
var result = [];
for (var i = 0; i < arr.length; i += size) {
result.push(arr.slice(i, size + i));
}
return result;
};
I actually just used arrays and react handled fine the rendering.
render() {
let rows = [],
cols = []
let index = 0
const totalCols = 20;
for (index; index < totalCols; index++) {
cols.push(<div class="col" key={index}/>)
if ((index + 1) % 4 == 0) {
rows.push(
<div class="row" key={index}>
{cols}
</div>
)
cols = []
}
}
return (
<div class="container">
{rows}
</div>
)
}

Categories

Resources