I have an array of items that I'm mapping over and would like to style them as flex wrap items so they end up in a row. However, I've tried multiple ways to go about this but the items remain listed in one column.
This is the result I'm going for: https://www.nike.com/w/mens-training-gym-shoes-58jtoznik1zy7ok
<div>
<h3>All Shoes ({allShoes.length})</h3>
{allShoes.map(item => {
return (
<section key={item.id} style={{display: 'flex'}}>
<div>
<img src={item.image} alt={item.name}/>
<p>{item.name}</p>
<p>{item.subTitle}</p>
<p>{item.price}</p>
</div>
</section>)
})}
</div>
You are creating several section elements, each containing just one div.
To get the divs displayed in a row, create one section and put multiple divs inside it. Something like this:
<div>
<h3>All Shoes</h3>
<section style="display: flex">
{allShoes.map(item => {
return (
<div key={item.id}>
<img src={item.image} alt={item.name}/>
<p>{item.name}</p>
<p>{item.subTitle}</p>
<p>{item.price}</p>
</div>)
})}
</section>
</div>
Here's what that looks like as rendered HTML:
section {
background-color: #a0a0a0;
}
section:before {
content: "section";
padding: 1rem;
color: #606060;
}
section div {
margin: 4px;
border: 1px solid gray;
background-color: white;
}
section div p {
padding-left: 0.5rem;
margin: 0;
}
<div>
<h3>All Shoes</h3>
<!-- a single section with flex -->
<section style="display: flex;">
<!-- containing multiple divs -->
<div>
<img src="https://via.placeholder.com/140" />
<p>item.name</p>
<p>item.subTitle</p>
<p>item.price</p>
</div>
<div>
<img src="https://via.placeholder.com/140" />
<p>item.name</p>
<p>item.subTitle</p>
<p>item.price</p>
</div>
<div>
<img src="https://via.placeholder.com/140" />
<p>item.name</p>
<p>item.subTitle</p>
<p>item.price</p>
</div>
</section>
</div>
Related
Sorry I don't code much and have adapted this code, so help would be greatly appreciated.
I'm trying to emulate a shopping page where you can 'like' a product and shows number of 'likes' for each product.
What is happening:
When I click on different instances of the 'like' button they get saved as one instance on firebase and all the 'like' counters show the same number of 'likes'
What I want:
Every time I click a different instance of the 'like' button I want it saved as a different instance on firebase so the counts are different for each 'like' button.
var dCounters = document.querySelectorAll('.CountLike');
[].forEach.call(dCounters, function(dCounter) {
var el = dCounter.querySelector('button');
var cId = dCounter.id;
var dDatabase = firebase.database().ref('Like Number Counter').child(cId);
// get firebase data
dDatabase.on('value', function(snap) {
var data = snap.val() || 0;
dCounter.querySelector('span').innerHTML = data;
});
// set firebase data
el.addEventListener('click', function() {
dDatabase.transaction(function(dCount) {
return (dCount || 0) + 1;
});
});
});
.CountLike div {
display: inline-flex;
}
.item-like {
font-size: 18px;
display: inline-block;
margin-top: 10px;
}
.counterStat {
margin-right: 15px;
margin-top: 5px;
}
.heart {
width: 32px;
height: 32px;
}
.btn {
background: none;
border: none;
cursor: pointer;
}
<div>
<div class="store-action">
<div class="CountLike" id="Like Count">
<div class="likes">
<span class="counterStat">0</span>
<button class="btn"><img src="https://www.svgrepo.com/show/164008/heart.svg" class="heart" alt="the heart-like button"></button>
</div>
</div>
</div>
</div>
<div>
<div class="store-action">
<div class="CountLike" id="Like Count">
<div class="likes">
<span class="counterStat">0</span>
<button class="btn"><img src="https://www.svgrepo.com/show/164008/heart.svg" class="heart" alt="the heart-like button"></button>
</div>
</div>
</div>
</div>
Below snippet should do it for now. Both of your elements have the same id value set which is set as id="Like Count"
So right now you just end up writing and reading from the same field for every cell you have.
As it is also stated on this link you should always make sure the id values you assign are unique.
<div>
<div class="store-action">
<div class="CountLike" id="xyz">
<div class="likes">
<span class="counterStat">0</span>
<button class="btn"><img src="https://www.svgrepo.com/show/164008/heart.svg" class="heart" alt="the heart-like button"></button>
</div>
</div>
</div>
</div>
<div>
<div class="store-action">
<div class="CountLike" id="xyzt">
<div class="likes">
<span class="counterStat">0</span>
<button class="btn"><img src="https://www.svgrepo.com/show/164008/heart.svg" class="heart" alt="the heart-like button"></button>
</div>
</div>
</div>
</div>
I am trying to display Cards next to one another (4 cards per row). Here is my my html for a Card:
<div class="HelloWorldCard">
<div class="cardwithlink">
<div class="row">
<div class="Hellocard cardwithlink style="height: 170px;">
<a href="//www.https://www.google.com/" title="Google home page" target="">
<div class="content">
<div class="HelloTopSection" style="height: 110px;">
<div class="HelloCardTitle">{{ title }}</div>
<div class="HelloCardExcerpt">{{ description }}</div>
</div>
</div>
</a>
</div>
</div>
</div>
</div>
<Script>
export default{
name: "HelloWordCard",
props:{
title: String,
description: String
},
};
I have about 100 cards that I want to display on my page. I can't just copy and past this html 100 times since that would be a waste of time. Is it possible to print out this block of html in a loop 100 times ?
The real issue I am having is that the cards are displaying 1 card on each row. I am trying to get them to display 4 on each row.
Your row should not be inside your card component.
It should be in a parent component holding the card, where you can apply #Srijan Katuwal's CSS. For example:
<template>
<div id="app">
<div class="row">
<HelloWorldCard
v-for="index in 100"
:key="index"
title="Test"
description="Test description"
/>
</div>
</div>
</template>
<script>
import HelloWorldCard from "./components/HelloWorldCard";
export default {
name: "App",
components: {
HelloWorldCard,
},
};
</script>
<style>
.row {
display: grid;
grid-template-columns: repeat(4, auto);
gap: 30px;
}
</style>
Your component now is:
<template>
<div class="Hellocard cardwithlink" style="height: 170px">
<a href="//www.https://www.google.com/" title="Google home page" target="">
<div class="content">
<div class="HelloTopSection" style="height: 110px">
<div class="HelloCardTitle">{{ title }}</div>
<div class="HelloCardExcerpt">{{ description }}</div>
</div>
</div>
</a>
</div>
</template>
<script>
export default {
name: "HelloWordCard",
props: {
title: String,
description: String,
},
};
</script>
You can see it in action here: https://codesandbox.io/s/hungry-hodgkin-2sklq?file=/src/App.vue:0-476
You can use v-for directive to show a div block for n number of times.
Vue offical documentation has similar example v-for
Also, to display 4 cards in a single row, you can use CSS grid or flex. A grid implementation can be done as below
.row {
display: grid;
grid-template-columns: repeat(4, auto);
gap: 30px;
}
You need to write following CSS to display cards next to each other
* {
box-sizing: border-box;
}
.row {
display: block;
width: 100%;
}
.card {
display: block;
float: left;
width: 25%;
padding: 10px;
border: 1px solid grey;
}
<div class="row">
<div class="card">Card Data</div>
<div class="card">Card Data</div>
<div class="card">Card Data</div>
<div class="card">Card Data</div>
<div class="card">Card Data</div>
<div class="card">Card Data</div>
</div>
I'm trying to get the end result to look like, (following this example):
<style>
* {
box-sizing: border-box;
}
.column {
float: left;
width: 50%;
padding: 10px;
height: 300px;
}
.row:after {
content: "";
display: table;
clear: both;
}
</style>
<div class="row">
<div class="column">
<Component />
</div>
<div class="column">
<Component />
</div>
</div>
The problem is that I can't quite figure out how to do this in React. The original map function currently looks like:
<div className="main">
{
arrayOfComponents.map((({ name }), index) => (
<Component
key={`${index}-${name}`}
label={name}
/>
))
}
</div>
I've tried doing something like,
<div className="main">
{
arrayOfComponents.map((({ name }), index) => (
<div className={index % 2 === 0 ? 'row' : ''}>
<div className="column">
<Component
key={`${index}-${name}`}
label={name}
/>
</div>
</div>
))
}
</div>
But that didn't seem to work, and if it did, it seems messy. How can I go about this?
arrayOfComponents looks something like
const arrayOfComponents = [
{ name: 'abc', key: 'value1'},
{ name: 'def', key: 'value2' },
. . .
]
You just need to map over the array and return the Component wrapped in a div with className of column like this :
<div className="main">
<div className="row">
{
arrayOfComponents.map(({name},index) => (
<div className="column">
<Component
key={`${index}-${name}`}
label={name}
/>
</div>
))
}
</div>
</div>
* {
box-sizing: border-box;
}
/* Create two equal columns that floats next to each other */
.column {
float: left;
width: 50%;
padding: 10px;
}
/* Clear floats after the columns */
.row:after {
content: "";
display: table;
clear: both;
}
.bg{
background:orange;
border: 2px solid red;
margin: 0 auto 100px;
}
<div class="row bg">
<div class="column">
<h2>Column 1</h2>
<p>Some text..</p>
</div>
<div class="column">
<h2>Column 2</h2>
<p>Some text..</p>
</div>
</div>
<div class="bg">
<div class="column">
<h2>Column 1</h2>
<p>Some text..</p>
</div>
<div class="column">
<h2>Column 2</h2>
<p>Some text..</p>
</div>
</div>
Hope this helps !
If you specifically need additional row elements, You can use conditional rendering like this. This would create a new row after 2 columns.
<div className="main">
{
arrayOfComponents.map(({ name }, index) => index%2!=0?null:(
<div className="row">
<div className="column">
<Component
key={`${index}-${name}`}
label={name}
/>
</div>
{arrayOfComponents[index+1] && (
<div className="column">
<Component
key={`${index+1}-${arrayOfComponents[index+1].name}`}
label={arrayOfComponents[index+1].name}
/>
</div>
)}
</div>
))
}
</div>
You can use reduce for splitting your data:
const rows = arrayOfComponents.reduce((acc, rec, index) => {
if (index % 2 === 0) {
return [...acc, [rec]]
}
acc[acc.length - 1] = [...acc[acc.length - 1], rec]
return acc
}, [])
const Component = (props) => {
return <div>
<h2>{props.item.name}</h2>
<p>{props.item.key}</p>
</div>
}
const TodoApp = () => {
return rows.map((row, index)=>{
return <div key={index}>{
row.map((col) => <div className="column" key={col.name}><Component item={col}/></div>)
}</div>
})
}
See full example in playground: https://jsfiddle.net/denisstukalov/ut8x9Lkq/21/#&togetherjs=Q7jLIOHHOP
I am currently working on a admin panel that must display a list of videos / text links on cards.
The environment that I'm working on does not use bootstrap, so I could not simply use their cards. Which meant that I had to recreate the card components.
I have made it so the cards display normally as if it is a regular card as follow:
The code for this is:
<div className="">
<Link className="styledLink" to={`adminhelpcard/${this.state.id}`}>
<div className="card">
<h5 className="card-header">{this.state.title}</h5>
<div>
<img
className="Sprite"
onLoad={() => this.setState({ imageLoading: false })}
onError={() => this.setState({ tooManyRequests: true })}
src={this.state.thumbnail}
style={
this.state.tooManyRequests
? { display: "none" }
: this.state.imageLoading
? { display: "null" }
: { display: "null" }
}
/>
</div>
<div>
{this.state.tooManyRequests ? (
<h6 className="mx-auto">
<span className="badge badge-danger mt-2"></span>
</h6>
) : null}
<div className="card-body mx-auto">
<h6 className="card-title">
{this.state.title
.toLowerCase()
.split(" ")
.map((letter) => letter.charAt(0).toUpperCase() + letter.substring(1))
.join(" ")}
</h6>
</div>
</div>
</div>
</Link>
</div>
I am trying to re-create the horizontal card (https://getbootstrap.com/docs/4.3/components/card/#horizontal)
for specifically the links containing videos. But it comes out like so
The code for the recreated attempt is as follows:
<div className="horizontalCard">
<div className="innerCard">
<div className="leftImage">
<img
className="Sprite"
onLoad={() => this.setState({ imageLoading: false })}
onError={() => this.setState({ tooManyRequests: true })}
src={this.state.thumbnail}
style={
this.state.tooManyRequests
? { display: "none" }
: this.state.imageLoading
? { display: "null" }
: { display: "null" }
}
/>
</div>
<div className="rightText">
<div className="card-body">
<h5 className="card-title">{this.state.title}</h5>
<p className="card-text">...</p>
<p className="card-text">...</p>
</div>
</div>
</div>
</div>
So my main question, is how can I go about recreating this / adjusting the image size so that it stays within the dimensions of the leftImage div.
With height: auto you can fit an image with respect to the aspect ration.
img.Sprite {
display: block; /*optional*/
width: 100%; /*optional*/
max-width: 100%;
height: auto;
border: 0;
}
The parent of the img must have a width (in %, px, em, rem, or whatever)
I've added three pictures. Look at them please.
What is the best solution to create something like this? I would create after each row a big container and this container is collapsed. After clicking on one of the 3 overlying containers I would fill the container with the text and show it. But what happens when the display can't show 3 divs in a row, because I will use flex boxes? Is there a better solution with much less jquery?
Maybe something like this is a good place to start:
https://jsfiddle.net/547ec3bx/
HTML
<div class="wrapper">
<div class="row">
<div class="element">
</div>
<div class="element">
</div>
<div class="element">
</div>
</div>
<div class="row">
<div class="element">
</div>
<div class="element">
</div>
<div class="element">
</div>
</div>
<div class="row">
<div class="element">
</div>
<div class="element">
</div>
<div class="element">
</div>
</div>
</div>
Javascript
document.querySelectorAll('.row').forEach((element, index) => {
element.style.order = index * 2;
});
document.querySelectorAll('.element').forEach(element => {
element.addEventListener('click', event => {
var newRow = document.createElement('div');
newRow.classList.add('row');
newRow.style.order = +event.currentTarget.parentNode.style.order + 1;
var newElement = document.createElement('div');
newElement.classList.add('element');
newRow.appendChild(newElement);
event.currentTarget.parentNode.parentNode.appendChild(newRow);
});
});
CSS
.element {
min-width: 100px;
height: 50px;
flex: 1;
border: 1px solid black;
flex-wrap: nowrap;
}
.row {
width: 350px;
display: flex;
flex-direction: row;
}
.wrapper {
display: flex;
flex-direction: column;
}
you can use javascript to solve this problem , like this ....
html code:
<div id="a">
<h3>wellcome</h3>
</div>
<div id="b">
<h3>hello...</h3>
</div>
javascript code in external file
function goB()
{
document.getElementById("a").style.display="none";
document.getElementById("b").style.display="block";
}
function
{
document.getElementById("b").style.display="none";
document.getElementById("a").style.display="block";
}
Add a div and set its display to Hidden.
Get onclick event for a particular div and set the display property to block
window.addEventListener("load", function(){
document.getElementById("click").onclick = function(){
document.getElementById("div-1").style.display = "block";
};
});
.row
{
width:100%;
}
.one-third
{
width:33.33333%;
float:left;
padding:30px 0;
}
.full-width
{
display:none;
width:100%;
text-align:center;
}
<div class=wrap>
<div class="row">
<div id="click" class="one-third">
Column 1-Click Me
</div>
<div class="one-third">
Column 2
</div>
<div class="one-third">
Column 3
</div>
</div>
<div class="full-width" id="div-1">Full width Div</div>
<div class="row">
<div class="one-third">
Column 1
</div>
<div class="one-third">
Column 2
</div>
<div class="one-third">
Column 3
</div>
</div>