this is my code so far
class PortfolioList extends Component{
render(){
const {column , styevariation } = this.props;
const list = PortfolioListContent.slice(0 , this.props.item);
return(
<React.Fragment>
{list.map((value , index) => (
<div className={`${column}`} key={index}>
<div className={`portfolio ${styevariation}`}>
<div className="thumbnail-inner" >
<div className={`thumbnail ${value.image}`}></div>
<div className={`bg-blr-image ${value.image}`}></div>
</div>
<div className="content" >
<div className="inner">
<p>{value.category}</p>
<h4>{value.title}</h4>
<div className="btn-container">
<div className="portfolio-button">
<a className="rn-btn" href="/portfolio-details"><FaGithub /> Git </a>
</div>
<div className="portfolio-button">
<a className="rn-btn" href="/portfolio-details"><FaExternalLinkAlt /> Live </a>
</div>
</div>
</div>
</div>
</div>
</div>
))}
</React.Fragment>
)
}
}
I want to conditionally render the div "content" and the child elements of content div when mouse is hovering over "thumbnail-inner" div. But hide content when mouse is not hovering over thumbnail-inner div.
How can i achieve this?
I didn't test this, but the idea is to add a variable in the state of the component which holds the current hovered item.
When a mouseEnter event enters to your thumbnail-inner, you update that variable with the current component index. And you set it to -1 when a mouseLeave events happens in your thumbnail-inner.
Then you simply render the content conditionally by checking if the this.state.selectedIndex === index.
class PortfolioList extends Component {
state = {
selectedItem: -1,
}
render(){
const {column , styevariation } = this.props;
const list = PortfolioListContent.slice(0 , this.props.item);
return(
<React.Fragment>
{list.map((value , index) => (
<div className={`${column}`} key={index}>
<div className={`portfolio ${styevariation}`}>
<div
className="thumbnail-inner"
onMouseEnter={ () => { this.setState({selectedItem: index}) } }
onMouseLeave={ () => { this.setState({selectedItem: -1}) } }>
<div className={`thumbnail ${value.image}`}></div>
<div className={`bg-blr-image ${value.image}`}></div>
</div>
{
this.state.selectedItem === index &&
<div className="content" >
<div className="inner">
<p>{value.category}</p>
<h4>{value.title}</h4>
<div className="btn-container">
<div className="portfolio-button">
<a className="rn-btn" href="/portfolio-details"><FaGithub /> Git </a>
</div>
<div className="portfolio-button">
<a className="rn-btn" href="/portfolio-details"><FaExternalLinkAlt /> Live </a>
</div>
</div>
</div>
</div>
}
</div>
</div>
))}
</React.Fragment>
)
}
First, you need to add state for condition of hover (ex: "onHover"), the state is for conditional rendering the <div className="content">.
Second you need create function for hover and leaveHover(onMouseEnter & onMouseLeave) we call it handleMouseEnter for onMouseEnter, and we call it handleMouseLeave for onMouseLeave.
class PortfolioList extends Component {
state = {
onHover: false,
}
handleMouseEnter() {
this.setState({onHover: true})
}
handleMouseLeave() {
this.setState({onHover: false})
}
render(){
const {column , styevariation } = this.props;
const list = PortfolioListContent.slice(0 , this.props.item);
return(
<React.Fragment>
{list.map((value , index) => (
<div className={`${column}`} key={index}>
<div className={`portfolio ${styevariation}`}>
<div
className="thumbnail-inner"
onMouseEnter={this.handleMouseEnter}
onMouseLeave={this.handleMouseLeave}>
<div className={`thumbnail ${value.image}`}></div>
<div className={`bg-blr-image ${value.image}`}></div>
</div>
{
this.state.onHover &&
<div className="content" >
<div className="inner">
<p>{value.category}</p>
<h4>{value.title}</h4>
<div className="btn-container">
<div className="portfolio-button">
<a className="rn-btn" href="/portfolio-details"><FaGithub /> Git </a>
</div>
<div className="portfolio-button">
<a className="rn-btn" href="/portfolio-details"><FaExternalLinkAlt /> Live </a>
</div>
</div>
</div>
</div>
}
</div>
</div>
))}
</React.Fragment>
)
}
Related
I made a button (entered as {this.props.children}), and I can align it in the center of the card footer, but for some reason, it will not align right (it just aligns on the left side).
class Product extends Component {
state = {
product: this.props.product
}
render() {
return (
<div className='col-lg-6'>
<div className='card m-2'>
<div className='card-body'>
<div className='text-muted'># {this.state.product.id}</div>
<h5 className='pt-2 border-top'>{this.state.product.productName}</h5>
<div>${this.state.product.price}</div>
</div>
{/*card body ends here*/}
<div className='card-footer text-center'>{this.props.children}</div>
</div>
</div>
);
}
}
Here is the button code:
render() {
return (
<div>
<div className="container-fluid">
<h4>Shopping Cart</h4>
<div className="row">
{this.state.products.map((prod) => {
return (
<Product
key={prod.id}
product={prod}
>
<button className="btn btn-primary">Buy Now</button>
</Product>
);
})}
</div>
</div>
</div>
);
}
Thanks in advance for any help offered!
I'm creating a movies app with React and Redux, in each movie card I have some information about the movie like the title, image, and a button(buy a ticket). The idea is when I click on the button of each card I want to get the same image and title of the card and display it on the same page on another card that going to pop up so the user can choose the quantity and continue.
How can I get the data from the movie card onclick and transform it to another card as a pop-up?
what do you think
Single movie card Component
const SingleMovieCard = ({ id, title, poster_path, overview, toggleHandler }) => {
const [selected, isSelected] = useState(null);
return (
<article key={id} className="card">
<div key={id} onMouseEnter={() => isSelected(id)} onMouseLeave={() => isSelected(null)}>
<img src={`${ImgPath}` + poster_path} alt={title} className="image" />
{selected === id && <video src="./Trailers/SpaceJam.mp4" autoPlay={true} loop muted />}
</div>
<div className="body-card">
<h1>{title}</h1>
<p>{`${overview.substring(0, 200)}...`}</p>
</div>
<div className="services">
<FiShare2 className="icon" />
<FiHeart className="icon" />
<div className="btn-icon-container">
<BiShoppingBag className="btn-icon" />
<button onClick={() => toggleHandler()}>Buy Ticket</button>
</div>
</div>
</article>
)
}
export default SingleMovieCard;
Pop-up movie card
const PopUpMovie = ({showClass, toggleHandler}) => {
const moviesList = useSelector((state)=> state.allMovies.movies);
return (
<div className={`pop-up-container ${showClass}`}>
<nav className="pop-up">
<GrClose className="pop-up-close" onClick={()=> toggleHandler()}/>
<div className="product-details">
<div className="img-container">
<img src="./Pictures/FreeGuy.jpg" alt="FreeGuy" />
</div>
<div className="product info">
<h1 className="title">Free Guy movie</h1>
<div className="quantity">
<h4>Quantity</h4>
<span>4</span>
</div>
<h5 className="prix">11$</h5>
<button className="btn-checkout">Continue to checkout</button>
</div>
</div>
</nav>}
</div>
)
}
export default PopUpMovie;
you can use Modal from react-bootstrap
Example:
import { Modal } from "react-bootstrap";
const PopUpMovie = ({ showClass, toggleHandler }) => {
const modalContent = (
<div className={`pop-up-container ${showClass}`}>
<nav className="pop-up">
<GrClose className="pop-up-close" onClick={() => toggleHandler()} />
<div className="product-details">
<div className="img-container">
<img src="./Pictures/FreeGuy.jpg" alt="FreeGuy" />
</div>
<div className="product info">
<h1 className="title">Free Guy movie</h1>
<div className="quantity">
<h4>Quantity</h4>
<span>4</span>
</div>
<h5 className="prix">11$</h5>
<button className="btn-checkout">Continue to checkout</button>
</div>
</div>
</nav>
</div>
)
const moviesList = useSelector((state) => state.allMovies.movies);
return (
<Modal
id="order-modal-close"
backdrop="static"
show={showClass}
size={"md"}
dialogClassName="modal-90w"
onHide={toggleHandler}
>
<Modal.Header closeButton>
<Modal.Title>Movie</Modal.Title>
</Modal.Header>
<Modal.Body >{modalContent}</Modal.Body>
{modalFooter}
</Modal>
)
}
I've been using Bootstrap 4 for displaying data to the user.
Now I've had idea to display data in columns and rows. Frontend is ReactJS and it's fetching data from backend response. Right now I've managed to display data in the cards, but they are all over the place.
This is how my dashboard looks:
So as can you see, it's all over the place, where I need to each one be in the same line. (they are not sticking with each other)
Is there a way to fix this with only Bootstrap or is it needed to create some kind of my own css?
Here is Dashboard.js component:
import React, { useState, useEffect } from 'react';
import ArticleService from '../services/article.service';
import { Link } from 'react-router-dom';
import Pagination from 'react-js-pagination';
const Dashboard = () => {
const [content, setContent] = useState([]);
const [currentPage, setCurrentPage] = useState(1);
const [postsPerPage] = useState(10);
useEffect(() => {
const fetchPosts = async () => {
const res = await ArticleService.articles();
setContent(res.data);
};
fetchPosts();
}, []);
// Get current posts
const indexOfLastPost = currentPage * postsPerPage;
const indexOfFirstPost = indexOfLastPost - postsPerPage;
const currentPosts = content.slice(indexOfFirstPost, indexOfLastPost);
// Change page
const handlePageChange = (pageNumber) => {
setCurrentPage(pageNumber);
};
return (
<div className='container'>
<div className='row'>
<div className='col-sm'>
<h4>Opis artikla</h4>
{currentPosts &&
currentPosts.map((item) => (
<div key={item.id} className='card'>
<h3>{item.descr}</h3>
<h5>Broj kvadrata: {item.sqm}</h5>
</div>
))}
</div>
<div classname='col-sm'>
<h4>Cijena</h4>
{currentPosts &&
currentPosts.map((item) => (
<div key={item.id} className='card'>
<h3>{item.price}</h3>
<h5>Cijena po kvadratu: {item.ppm2}/m2</h5>
</div>
))}
</div>
<div classname='col-sm'>
<h4>Prikaži ponudu</h4>
{currentPosts &&
currentPosts.map((item) => (
<div key={item.id} className='card'>
<Link to={`/article/${item.id}`}>
<h5>
Prikaži<br></br>
<br></br>
<br></br>
</h5>
</Link>
</div>
))}
</div>
</div>
<nav>
<div className='w3-bar w3-xlarge'>
<ul className='pagination justify-content-center'>
<li className='page-item'>
<Pagination
hideDisabled
hideNavigation
hideFirstLastPages
currentPage={currentPage}
itemsCountPerPage={10}
totalItemsCount={content.length}
pageRangeDisplayed={indexOfLastPost}
onChange={handlePageChange}
/>
</li>
</ul>
</div>
</nav>
</div>
);
};
export default Dashboard;
I think you can try using the bootstrap class - align-items-baseline on I guess the row div.
Check this answer from another post to know more about this align-items-baseline property.
If this does not work then I think you can try this:
<div className='container'>
<!-- First a row div with only the 3 column headings -->
<div className='row'>
<div className='col-4'>
<h4>Opis artikla</h4>
</div>
<div classname='col-4'>
<h4>Cijena</h4>
</div>
<div classname='col-4'>
<h4>Prikaži ponudu</h4>
</div>
</div>
<!-- Then the data of the 3 columns -->
{currentPosts && currentPosts.map((item) => (
<!-- A new row for each items data -->
<div className='row'>
<!-- For the first column -->
<div className='col-4'>
<div key={item.id} className='card'>
<h3>{item.descr}</h3>
<h5>Broj kvadrata: {item.sqm}</h5>
</div>
</div>
<!-- For the second column -->
<div className='col-4'>
<div key={item.id} className='card'>
<h3>{item.price}</h3>
<h5>Cijena po kvadratu: {item.ppm2}/m2</h5>
</div>
</div>
<!-- For the third column -->
<div className='col-4'>
<div key={item.id} className='card'>
<Link to={`/article/${item.id}`}>
<h5>
Prikaži<br></br>
<br></br>
<br></br>
</h5>
</Link>
</div>
</div>
</div>
))}
<nav>
<div className='w3-bar w3-xlarge'>
<ul className='pagination justify-content-center'>
<li className='page-item'>
<Pagination
hideDisabled
hideNavigation
hideFirstLastPages
currentPage={currentPage}
itemsCountPerPage={10}
totalItemsCount={content.length}
pageRangeDisplayed={indexOfLastPost}
onChange={handlePageChange}
/>
</li>
</ul>
</div>
</nav>
</div>
Update - I tried the above code and as you said, yes it didn't work.
But then I did the below code and it's working as you want it to or what I think you want it to work like:
import React from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
var currentPosts = [
{ sqm: 'One', ppm2: 'a', id: '1' },
{ sqm: 'Two', ppm2: 'b', id: '2' },
{ sqm: 'Three', ppm2: 'c', id: '3' }
];
const Dashboard = () => {
return (
<div className='container'>
<div className='row'>
<div className='col-4'>
<h4>Opis artikla</h4>
</div>
<div className='col-4'>
<h4>Cijena</h4>
</div>
<div className='col-4'>
<h4>Prikaži ponudu</h4>
</div>
</div>
{currentPosts && currentPosts.map((item) => (
<div className='row mt-4 align-items-baseline'>
<div className='col-4'>
<div key={item.id} className='card'>
<h3>{item.descr}</h3>
<h5>Broj kvadrata: {item.sqm}</h5>
</div>
</div>
<div className='col-4'>
<div key={item.id} className='card'>
<h3>{item.price}</h3>
<h5>Cijena po kvadratu: {item.ppm2}/m2</h5>
</div>
</div>
<div className='col-4'>
<div key={item.id} className='card'>
{/* <Link to={`/article/${item.id}`}> */}
<h5>
Prikaži<br></br>
<br></br>
<br></br>
</h5>
{/* </Link> */}
</div>
</div>
</div>
))}
</div>
);
};
export default Dashboard;
You can add the pagination and other code lines to this...
Actually the only change I made was to add the mt-4 and align-items-baseline classes to the row div that has the data.
The result I got from this code was:
I have a list of items and for every item (.item-wrapper) i want to get a video popup with unique videoId.
I have prepared videoPopup component for that but for every item I get the the last 'videoId' of 'elements' array (the same videoId for every item).
On the other hand when I am not using PopupVideo component and just loop through items iframes I get the proper id for specific item - that is just for test purpose.
(The commented out line)
I am super new to React so I am aware that problem may be also super easy to solve.
Thanks!
Code for displaying items:
class Training extends Component {
constructor(props) {
super(props);
this.state = {
popupShowed: false
};
}
togglePopup = event => {
this.setState({
popupShowed: !this.state.popupShowed
});
};
onClosePopup = () => {
this.togglePopup();
};
content = () => {
const elements = ["76979871", "72675442", "337398380"];
const items = [];
for (const [index, value] of elements.entries()) {
items.push(
<div className="item-wrapper d-flex mb-4" key={index}>
<div className="item-col training-num text-white font-weight-normal d-flex align-items-center justify-content-center">
<span>{index < 10 ? "0" + index : index}</span>
</div>
<div className="item-col desc-col">
<h3 className="text-white title font-weight-normal">
Dlaczego warto?
</h3>
<div className="text-wrapper training-desc text-white">
<p>
Dowiesz się dlaczego Social Media Ninja to Zawód Przyszłości.
Dostaniesz wiedzę na temat oferowania i briefowania klientów i
dowiesz się jak zarabiać na social mediach.
</p>
</div>
</div>
<div className="item-col text-white time-col">
<div className="inside-wrapper">
<p className="text-nowrap">
<strong>Czas trwania:</strong> 2:25:00
<br />
<strong>Twój postęp:</strong> 90%
</p>
</div>
</div>
<div className="item-col play-col d-flex align-items-center justify-content-center d-flex align-items-center justify-content-center">
<div className="play-wrapper" onClick={this.togglePopup}>
<svg
enableBackground="new 0 0 60.001 60.001"
viewBox="0 0 60.001 60.001"
xmlns="http://www.w3.org/2000/svg"
className="play-button"
>
<path d="m59.895 58.531-29-58c-.34-.678-1.449-.678-1.789 0l-29 58c-.155.31-.139.678.044.973.182.294.504.474.85.474h58c.347 0 .668-.18.851-.474.182-.295.199-.663.044-.973zm-57.277-.553 27.382-54.764 27.382 54.764z" />
</svg>
<span className="text-white mt-2 d-inline-block">zobacz</span>
{/* <iframe src={'https://player.vimeo.com/video/' + value} width="500" height="600" frameBorder="0" allowFullScreen mozallowfullscreen="true" allowFullScreen></iframe> */}
</div>
</div>
{this.state.popupShowed ? (
<PopupVideo videoId={value} closePopup={this.onClosePopup} />
) : null}
</div>
);
}
return <div className="list-wrapper">{items}</div>;
};
render() {
return <Layout content={this.content()} />;
}
}
export default Training;
Code for displaying popupVideo:
class PopupVideo extends Component {
componentDidMount = () => {
var iframe = document.querySelector("iframe");
var player = new Player(iframe);
player.on("play", function() {
console.log("played the video!");
});
};
render() {
return (
<div className="popup video-popup">
<div className="popup-inner d-flex align-items-center d-flex justify-content-center">
<div className="video">
<span
onClick={this.props.closePopup}
className="close-video d-flex align-items-center justify-content-center"
>
<img
src=""
alt="close video"
/>
</span>
<div className="embed-container">
<iframe
src={
"https://player.vimeo.com/video/" +
this.props.videoId +
"?api=1&autoplay=0#t=0"
}
title="Nazwa szkolenia"
frameBorder="0"
allowFullScreen
mozallowfullscreen="true"
allowFullScreen
></iframe>
</div>
<div className="video-nav">
<div className="video-progress"></div>
<div className="d-flex align-items-center py-4">
<div className="play">
<span className="play-video"></span>
</div>
<div className="stop">
<span className="stop-video"></span>
</div>
<div className="volume">
<span className="volume-video"></span>
</div>
<div className="time">00:00 / 05:50</div>
<div className="break"></div>
<div className="title">
<h4>
<strong className="mr-3 pr-3">01</strong>Dlaczego warto ?
</h4>
</div>
<div className="button">
<button className="btn btn-secondary d-flex justify-content-center text-uppercase text-light font-weight-bold px-4">
Zobacz następny
</button>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default PopupVideo;
I do not have any error messages in the console.
Okay so i simplified the components to show you a good pattern to handle this kind of problems.
First create a VideoContainer to hold all the videoIds in the state.
We are going to return an array of Video components and pass the videoId as props to each one.
This container will be responsible to just provide the data to the other components
class VideoContainer extends Component {
state = {
videoIds: ["76979871", "72675442", "337398380"]
};
renderVideo = videoId => <Video key={videoId} videoId={videoId} />
render() {
const { videoIds } = this.state;
return videoIds.map(this.renderVideo);
}
}
Then create a Video component which will hold the popupShowed in state and will include the PopupVideo component only when popupShowed is true using && pass in the videoId and the togglePopup handler as props.
Now every Video is an independent component which hold the state for showing the PopupVideo
class Video extends Component {
state = {
popupShowed: false
};
togglePopup = () => {
this.setState(prevState => ({
popupShowed: !prevState.popupShowed
}));
};
render() {
const { popupShowed } = this.state;
const { videoId } = this.props;
return (
<div className="item-wrapper d-flex mb-4">
<button onClick={this.togglePopup}>Show Popup</button>
{popupShowed && (
<PopupVideo videoId={videoId} closePopup={this.togglePopup} />
)}
</div>
);
}
}
And last PopupVideo
const PopupVideo = ({ videoId, closePopup }) => (
<div className="popup video-popup">
<span onClick={closePopup}>
<img
src="https://rahimblak.com/images/video-close.png"
alt="close video"
/>
</span>
<div className="embed-container">
<iframe
src={
"https://player.vimeo.com/video/" +
videoId +
"?api=1&autoplay=0#t=0"
}
title="Nazwa szkolenia"
frameBorder="0"
allowFullScreen
mozallowfullscreen="true"
/>
</div>
</div>
);
sandbox
I have rendered the repeated elements in the component. When i click a particular component, a popup should be displayed on the particular component only. Now i got the popup message on all the elements. How to clear this issue?
class Display extends component{
constructor(props){
super(props);
this.state={showResult:false};
}
renderList(){
return this.props.cars.attribute.map((car) => {
return (
<div key={car.attribute_name} className="col-sm-4" >
<div className="panel-body back-img" onClick={()=> this.setState({showResult:true})}>
<div className="row">
<div className="col-sm-6 incrementer">
<span className="titleclass"> Hala </span>
</div>
</div>
</div>
</div> { this.state.showResults ? <Results /> : null }
)}}}
class Results extends Component{
render(){
return(<div id="results" className="search-results">
Some Results
</div>); }}
Identify the clicked node by a unique property, such as attribute_name:
return this.props.cars.attribute.map((car) => {
return (
<div key={car.attribute_name} className="col-sm-4" >
<div className="panel-body back-img" onClick={()=> this.setState({showResult:true, attributeName: car.attribute_name})}> // store the current car.attribute_name in the state
<div className="row">
<div className="col-sm-6 incrementer">
<span className="titleclass"> Hala </span>
</div>
</div>
</div>
</div> { this.state.showResults && this.state.attributeName === car.attribute_name ? <Results /> : null } // only show results if the current attribute name in the state is the same as the item's
)}}}