display Popup only on selected element - reactjs

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
)}}}

Related

How can I get my button to align right inside in a card in react?

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!

React Hover to conditional render component

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>
)
}

Passing from child to parent from a component with 3 objects

I got a component with 2 buttons and 1 input text. The button 1 decrease a item and the button 2 increment a item to a input. I need to got the value from the input when I decrease/increment a item. The decrease/increment its working, but I can't (I don't know how) get the value in parent component.
This is my child component, named ChooseQuantity:
import React, { Component } from 'react';
import './ChooseQuantity.css';
class ChooseQuantity extends Component{
constructor(props){
super(props);
}
state = {
qtd: 0,
}
addItem(){
this.setState({qtd: this.state.qtd + 1 });
}
removeItem(){
if(this.state.qtd > 0){
this.setState({qtd: this.state.qtd - 1 });
}
}
render() {
return(
<div>
<button className="minus" onClick={() => this.removeItem()}>
<i className="fas fa-minus"></i>
</button>
<input className="qtd" type="text" value={this.state.qtd} name='qtd' onChange={this.props.action} onInput={(e) => this.setState({ choose_quantity: e.target.value })} readOnly />
<button className='plus' onClick={() => this.addItem()} >
<i className="fas fa-plus"></i>
</button>
</div>
)
}
}
export default ChooseQuantity;
This is part of my parent component, named Event (note that the child component it's in a array):
{
this.state.tickets.map((ticket, i) => (
<div key={i}>
<div className="row">
<div className="col">
<h3 className="ticket-name">{ ticket.name }</h3>
</div>
</div>
{ticket.lot.map((lot, j) =>
<div className="row" key={i}>
<div className="col-8">
<h5 className="lot-name">{ lot.name }</h5>
<h6 className="lot-price">
R$ { lot.price.replace('.', ',') } <br />
<small>(R$ { lot.price.replace('.', ',') } + R$ { lot.price_tax.replace('.', ',') })</small>
</h6>
</div>
<div className="col-4">
<ChooseQuantity />
{this.state.qtd}
</div>
</div>
)}
<hr />
</div>
)
)
}
You should 'lift up' the state in to a common parent that handles the logic and pass handlers like onAddItem, onRemoveItem and a value prop down to your buttons and input.
See here for detail on lifting state up: https://reactjs.org/docs/lifting-state-up.html

React Ref for sibling component

I have Component named Home which contains LeftNav, BookSearch and HomeCart Component. BookSearch Component has a input field and HomeCart component has a button. When the button in HomeCart component clicked, I need to focus the input field in BookSearch Component.
I researched a bit and I could able to only focus an element from the same Component only. How can I achieve the desired behaviour this using React Ref?
Home.jsx
class Home extends React.Component {
render() {
return (
<React.Fragment>
<div className="row no-gutters app">
<div className="col-sm-12 col-md-12 col-lg-2">
<LeftNav />
</div>
<div className="col-sm-12 col-md-12 col-lg-7 books-panel">
<BookSearch test={this.test}/>
</div>
<div className="col-sm-12 col-md-12 col-lg-3 cart-panel">
<HomeCart onClick={thi} />
</div>
</div>
</React.Fragment>
);
}
}
BookSearch.jsx
class BookSearch extends React.Component {
render() {
return (
<React.Fragment>
<button onClick={this.test}>Focus</button>
<div className="row text-center">
<div className="col-12">
<form onSubmit={this.handleSubmit}>
<h2 className="mt-5">Start searching your favorite books</h2>
<label htmlFor="search-query" className="sr-only">
Search by book name
</label>
<input
name="search-query"
onChange={this.handleChange}
type="search"
className="book-search"
value={this.state.query}
placeholder="Start searching...."
/>
<button type="submit" className="btn btn-primary btn-lg">
Search
</button>
</form>
</div>
</div>
</React.Fragment>
);
}
}
HomeCart.jsx
class HomeCart extends React.Component {
focusSearchBookInput(){
this.props.focusSearchBookInput()
}
render() {
const { cart_items } = this.props;
const cartTable = ();
const noCartItems = (
<React.Fragment>
<p>No items currently available in your cart. </p>
<button onClick={this.focusSearchBookInput} className="btn btn-success mt-5">
<ion-icon name="search" /> Start Searching
</button>
</React.Fragment>
);
return (
<React.Fragment>
<div className="row text-center">
<div className="col-12">
<h2 className="mt-5 mb-5">Books in your cart</h2>
{cart_items.length > 0 ? cartTable : noCartItems}
</div>
</div>
</React.Fragment>
);
}
}
One solution could be...
Create the ref and a click handler that sets focus on the ref in Home.jsx
class Home extends React.Component {
inputRef = React.createRef();
focusHandler = () => {
this.inputRef.current.focus();
}
render() {
return (
<React.Fragment>
<div className="row no-gutters app">
<div className="col-sm-12 col-md-12 col-lg-2">
<LeftNav />
</div>
<div className="col-sm-12 col-md-12 col-lg-7 books-panel">
<BookSearch inputRef={this.inputRef} />
</div>
<div className="col-sm-12 col-md-12 col-lg-3 cart-panel">
<HomeCart focusHandler={this.focusHandler} />
</div>
</div>
</React.Fragment>
);
}
}
Add ref={this.props.inputRef} to the input in BookSearch.jsx
Add onClick={this.props.focusHandler} to the button in HomeCart.jsx

How to change the state of an item affected by onClick in array?

I'm making a page where I need to make multiple selections of buttons (like a filter, which I'll use for the next page).
the information from these buttons is coming from an array and I'm using .map () to mount the button list.
My problem is how do I change the state of only the button that was clicked. The way it is now, when I click, all the buttons are active.
How can I solve this?
Thank you.
import React from 'react';
import { Link } from 'react-router-dom';
import { FormattedMessage } from 'react-intl';
import messages from './messages';
import { getLevel, getDiscipline } from '../../functions';
import template from './index.pug';
export default class ConfigAssessment extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function
constructor(props){
super(props);
this.state = {
level: getLevel(),
discipline: getDiscipline(),
active: '',
first_click: true,
}
}
changeActive = () => {
if (this.state.first_click === true) {
this.setState({
active: 'active',
first_click: false
});
} else {
this.setState({
active: '',
first_click: true,
});
}
}
render() {
return(
<div className="configuration">
<div className="config-title">
<i className="ti-settings" />
<h2>
<FormattedMessage {...messages.configAssessment} />
</h2>
</div>
<div className="config-items">
<div className="form-group">
<label>
<FormattedMessage {...messages.level} />
</label>
<div className="row">
{this.state.level.map((level, i) => (
<div className="col-xs-1 col-md-4 col-lg-3" key={level.id}>
<button
className={`btn btn-light-gray btn-block ${this.state.active}`}
id={level.id}
onClick={this.changeActive}
>
{level.level}
</button>
</div>
))}
</div>
</div>
<div className="form-group">
<label>
<FormattedMessage {...messages.discipline} />
</label>
<div className="row">
{ this.state.discipline.map((discipline, i) => (
<div className="col-xs-1 col-md-4 col-lg-3" key={i}>
<button
className={`btn btn-light-gray btn-block ${this.state.active}`}
onClick={this.changeActive}
>
{discipline.discipline}
</button>
</div>
))}
</div>
</div>
<div className="form-group">
<label>
<FormattedMessage {...messages.selectQuestion} />
</label>
<div className="row">
<div className="col-xs-1 col-md-4 col-lg-3">
<button
className={`btn btn-light-gray btn-block ${this.state.active}`}
onClick={this.changeActive}
>
<FormattedMessage {...messages.typeAutomatic} />
</button>
</div>
<div className="col-xs-1 col-md-4 col-lg-3">
<button
className={`btn btn-light-gray btn-block ${this.state.active}`}
onClick={this.changeActive}
>
<FormattedMessage {...messages.typeManual} />
</button>
</div>
</div>
</div>
<div className="form-group fg-right">
<Link className="btn btn-warning" to="#">
<FormattedMessage {...messages.createAssessment} />
</Link>
</div>
</div>
</div>
);
}
}
Create a separate component for button
class MyButton extends Component {
constructor(props){
super(props);
this.state = {
person: this.props.person
}
}
buttonActiveHandler = () => {
let oldStatus = this.props.person.status;
this.props.person.status = (!oldStatus ? 'active': '');
this.setState({
person:this.props.person
});
}
render() {
return (
<button className={this.state.person.status} onClick={this.buttonActiveHandler}>{this.state.person.name}</button>
);
}
}
export default MyButton;
Then import button component. use map function to for your code block
<div className={classes.Box}>
<h4>Lorem, ipsum.</h4>
{
this.props.survey.map((person, i) => {
return (
<MyButton key={i} person={person}/>
)
})
}
</div>
The easiest solution to this problem is making the component of the content inside the map and then handling the state of that component there. Hence it will maintain individual states.
It depends what you need.
You can create separate component for button with state.
You can also keep state of each button in react state as an array, and then you can get the state of each button by index.
I'd recommend the first solution, it'd easier to manage such state, but it will be harder to get the state of a specific button from the parent component.

Resources