I want to open the clicked image in react modal - react-modal

I read many similar questions but they did not work. i want to open the object that clicked in gallery into the modal .
My problem is that when a user clicks on a picture to open the modal of last object in the array is opened. I dont know how to make only the modal that is selected to open.
class SingleGallery extends Component{
constructor () {
super();
this.state = {
showModal: false
};
this.handleOpenModal = this.handleOpenModal.bind(this);
this.handleCloseModal = this.handleCloseModal.bind(this);
}
handleOpenModal () {
this.setState({ showModal: true });
}
handleCloseModal () {
this.setState({ showModal: false });
}
render(){
let singleGalleryObj = [
{image: imageGallery1},
{image: imageGallery2},
{image: imageGallery3},
{image: imageGallery4},
{image: imageGallery1},
{image: imageGallery2}
]
return(
<div class="singleGallery">
<div class="SGContent">
<div class="title">Gallery 1</div>
<div class="images">
{singleGalleryObj.map((para) => {
return (
<div>
<div class="galleryBox" onClick={this.handleOpenModal}>
<div class="image">
<img src={para.image} />
</div>
</div>
<Modal
isOpen={this.state.showModal}
contentLabel="Minimal Modal Example"
>
<button onClick={this.handleCloseModal}>Close Modal</button>
<img src={para.image}/>
</Modal>
</div>
)
})}
</div>
</div>
</div>
)
}
}

I think the problem is with the controller. You only have 1 controller to show or hide the modal. You could have only 1 modal for your render function like
<div class="singleGallery">
<div class="SGContent">
<div class="title">Gallery 1</div>
<div class="images">
{singleGalleryObj.map((para) => {
return (
<div>
<div class="galleryBox" onClick={() => this.handleOpenModal(para)}>
<div class="image">
<img src={para.image} />
</div>
</div>
</div>
)
})}
<Modal
isOpen={this.state.showModal}
contentLabel="Minimal Modal Example"
>
<button onClick={this.handleCloseModal}>Close Modal</button>
{this.state.selectedImage ? <img src={selectedImage.image}/> : null}
</Modal>
</div>
</div>
</div>
and your open modal handler could be like
handleOpenModal (selectedImage) {
this.setState({ showModal: true, selectedImage });
}
let me know if it's working or not.

Related

How do you mock child component with custom HTML react jest

Im trying to test a basic component that has a nested Modal component. How could one mock the Modal and test the Modal is successfully populated by values from extraDataInfo object (i.e extraDataInfo?.title)?
export const ExtraDataButtons = ({ extraDataInfo, containerClassName }) => {
const modalSeeMoreTrigger = {
ariaLabel: 'See more',
cssClassName: 'c-extra-data-see-more',
dataAttributes: { seeMore: 'seeMore' },
text: 'See more'
};
return (
<div className={containerClassName}>
<Modal trigger={modalSeeMoreTrigger}>
<div className="c-extra-data-info-cont">
<div className="c-extra-data-number">{extraDataInfo?.offerData}</div>
<div className="c-extra-data-detail">
<div className="c-extra-data-message">
{extraDataInfo?.text && (
<h3 className="c-extra-data-heading">{extraDataInfo?.text}</h3>
)}
{extraDataInfo?.offerDescription && (
<p className="c-extra-data-description">{extraDataInfo?.offerDescription}</p>
)}
</div>
</div>
</div>
<h4 className="c-extra-data-tc-heading" data-test-id="c-extra-data-tc-heading">
{extraDataInfo?.title}
</h4>
<Markdown text={extraDataInfo?.content} />
</Modal>
<button data-test-id="see-more-btn" className="c-extra-data-see-more" type="button">
<Icon svgSource={linearArrowRight} size={20} />
</button>
</div>
);
};

react js button hide while click in button

here is my reactjs button code how can hide while clicking in button
<div className='chat-bubble animated bounceInLeft' style={{display:'none'}}>
<div><img src={giabot} alt="" className="round"/></div>
<div className="chat-content"> {chatData.text[3]}<br/>
<div className="btn-group">
{
chatData.values.map((obj, index) => {
return (
<button className='button' onClick={this.buttonSubmit} key={index} value={obj}>{obj}</button>
)
})
}
</div>
</div>
</div>
you can do someting like this, at first set showButton field true and onClick make it false
buttonSubmit = ()=> {
this.setState({ showButton: false });
},
<div className='chat-bubble animated bounceInLeft' style={{display:'none'}}>
<div><img src={giabot} alt="" className="round"/></div>
<div className="chat-content"> {chatData.text[3]}<br/>
<div className="btn-group">
{
chatData.values.map((obj, index) => {
return (
{showButton && (
<button className='button' onClick={this.buttonSubmit} key={index} value={obj}>{obj}</button>
)}
)
})
}
</div>
</div>
</div>
buttonSubmit = ()=> {
this.setState({ showButton: !this.state.showButton });
},
<div className='chat-bubble animated bounceInLeft' style={{display:'none'}}>
<div><img src={giabot} alt="" className="round"/></div>
<div className="chat-content"> {chatData.text[3]}<br/>
<div className="btn-group">
{
chatData.values.map((obj, index) => {
return (
{showButton && (
<button className='button' onClick={this.buttonSubmit} key={index} value={obj}>{obj}</button>
)}
)
})
}
</div>
</div>
</div>
A small change to the above answer. You can enable and disable it onclick

How to move one object from one array to another on submit in React app

I'm building a simple hotel reviews app in React. I had it set up to display the first 3 reviews with the button "See all" to expand the box to see the rest of the reviews. However, I noticed that every time I try to submit a review, the last review in the first 3 reviews didn't show up in the rest of the reviews shown upon expansion. I tried a variety of solutions but couldn't solve it.
Here's my working demo: http://immense-beach-76879.herokuapp.com/
Here's my github repo: https://github.com/kikidesignnet/hotelreviews
Here is my code.
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
// import '/css/style.css';
/* An example React component */
class App extends Component {
constructor(props) {
super(props);
//Initialize the state in the constructor
this.state = {
name: "",
reviews: [],
otherReviews: [],
open: false
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.renderReviews = this.renderReviews.bind(this);
this.toggleReviews = this.toggleReviews.bind(this);
// this.addReviews = this.addReviews.bind(this);
}
// handle change
handleChange(e) {
this.setState({
name: e.target.value
});
console.log('onChange', this.state.name);
}
handleSubmit(e) {
// stop browser's default behaviour of reloading on form submit
e.preventDefault();
axios
.post('/reviews', {
name: this.state.name
})
.then(response => {
console.log('from handle submit', response);
// set state
this.setState({
reviews: [response.data, ...this.state.reviews].slice(0,3),
name: "",
otherReviews: [response.data, ...this.state.reviews].slice(3).concat([...this.state.otherReviews])
});
});
}
renderReviews() {
return this.state.reviews.map(review => (
<div key={review.id} className="media innercard">
<div className="media-body">
<div className="profile_box">
<div className="profile_img">
<img src="/images/profilepic.png" alt="" />
</div>
<div className="profile_data">
<h3>{review.user.name}</h3>
<span className="text-muted">
{this.convertTime(review.updated_at)}
</span>
</div>
</div>
<p>{review.name}</p>
</div>
</div>
));
}
//get all the reviews from backend
getReviews(){
axios.get('/reviews').then(response => this.setState({
reviews: [...response.data.reviews].slice(0,3),
otherReviews: [...response.data.reviews].slice(3)
}));
}
toggleReviews() {
this.setState({open: !this.state.open});
}
//lifecycle method
componentDidMount(){
this.getReviews();
}
render() {
return (
<div className="container">
<div className="row justify-content-center">
<div className="col-md-8">
<div className="review_card">
<div className="card-body">
<form onSubmit={this.handleSubmit} className="comment_form">
<div className="form-group">
<i className="fas fa-comment-dots"></i>
<input
onChange={this.handleChange}
value = {this.state.name}
className="form-control"
placeholder="Comment"
required
/>
</div>
<div className="btn_align">
<button type="submit" className="btn red_btn">
Submit
</button>
</div>
</form>
<div className="reviews_list">
<div className="review_header">
<h1>Reviews</h1>
<button className="toggle_btn" onClick={this.toggleReviews}>{this.state.open ? 'Hide reviews' : 'See all'}</button>
</div>
{this.renderReviews()}
{this.state.open && this.state.otherReviews.map(review =>(
<div key={review.id} className="media innercard">
<div className="media-body">
<div className="profile_box">
<div className="profile_img">
<img src="/images/profilepic.png" alt="" />
</div>
<div className="profile_data">
<h3>{review.user.name}</h3>
<span className="text-muted">
{this.convertTime(review.updated_at)}
</span>
</div>
</div>
<p>{review.name}</p>
</div>
</div>
))}
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default App;
This is the code that I'm trying to edit to show the submitted review in the box.
handleSubmit(e) {
// stop browser's default behaviour of reloading on form submit
e.preventDefault();
axios
.post('/reviews', {
name: this.state.name
})
.then(response => {
console.log('from handle submit', response);
// set state
this.setState({
reviews: [response.data, ...this.state.reviews].slice(0,3),
name: "",
otherReviews: [response.data, ...this.state.reviews].slice(3).concat([...this.state.otherReviews])
});
});
}
How do I solve this and what am I doing it wrong?

Modal not displaying on click (React)

I am trying to get a modal to function the modal I am trying to mirror is available here.
https://codesandbox.io/s/n9zn3n43o0
The button for the modal is displaying however the modal itself is not.
Here is my exact code for this function.
class App extends React.Component {
constructor(props) {
console.log("Props - ", props);
super(props);
this.state = {
modalVisible: false
};
this.openModal = this.openModal.bind(this);
}
openModal() {
console.log("Open modal called ", this.state.modalVisible);
const modalVisible = !this.state.modalVisible;
this.setState({
modalVisible
});
}
render() {
let styles = this.state.modalVisible
? { display: "block" }
: { display: "none" };
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<button
type="button"
onClick={this.openModal}
className="btn btn-info btn-lg"
>
Open Modal
</button>
<div
id="myModal"
className="modal fade in"
role="dialog"
style={styles}
>
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<button
type="button"
onClick={this.openModal}
className="close"
>
×
</button>
<h4 className="modal-title">Modal Header</h4>
</div>
<div className="modal-body">
<p>Some text in the modal.</p>
</div>
<div className="modal-footer">
<button
onClick={this.openModal}
type="button"
className="btn btn-default"
>
Close
</button>
</div>
</div>
</div>
</div>
</div>
);
}
}
And here is the code of the whole page
import React from "react";
import { Link } from "react-router-dom";
import Popup from "reactjs-popup";
import { Button, ButtonToolbar, Modal } from "react-bootstrap";
import ReactDOM from "react-dom";
import AddWorkstation from "./UpdateUserWorkStationDetailsForm";
class DisplayUserAcountDetails extends React.Component {
constructor() {
super();
this.state = { AccountDetails: [] };
}
// sets the questions form sql into state for questions
getItems() {
var user = window.localStorage.getItem("User");
if (user) {
fetch(`/profile-work-station-detailss/${user}`)
.then(recordset => recordset.json())
.then(results => {
this.setState({ AccountDetails: results.recordset });
});
} else {
alert("user not set");
}
}
//when the component mounts make the sql questions the
componentDidMount() {
this.setState({
AccountDetails: this.getItems()
});
}
render() {
try {
return (
<>
<h3 style={{ textAlign: "center" }}> Workstations</h3>
<button></button>
{this.state.AccountDetails ? (
<ul>
<App /> // calling it here
<Popup
style={{ width: "300px" }}
trigger={<button> Help?</button>}
closeOnDocumentClick
className={"tooltipBoundary"}
>
<AddWorkstation />
</Popup>
<Link to="/update-work-station-details">
<button style={{ float: "right" }}>+</button>
</Link>
<br />
<br />
{this.state.AccountDetails &&
this.state.AccountDetails.map(function(AccountDetails, index) {
return (
<div className="jumbotron">
<h3>Work Station</h3>
<li> Location: {AccountDetails.DeskLocation}</li>
<li>
ExtraInformation: {AccountDetails.ExtraInformation}
</li>
<li>
Primary Work Station:
{AccountDetails.PrimaryWorkStation}
</li>
<li> Date Added: {AccountDetails.PrimaryWorkStation}</li>
<li>
<Link to="/update-work-station-details">
<button>Update Account Details</button>
</Link>
</li>
</div>
);
})}
</ul>
) : (
<ul>
<div className="jumbotron">
<h3>Work Station</h3>
<li> Email: Null </li>
<li> Name: Null </li>
<li> Contact Number: Null </li>
<li>
<Link to="/update-work-station-details">
<button>Update Accoudnt Details</button>
</Link>
</li>
</div>
</ul>
)}
</>
);
} catch (e) {
console.log(e);
}
}
}
export default DisplayUserAcountDetails;
class App extends React.Component {
constructor(props) {
console.log("Props - ", props);
super(props);
this.state = {
modalVisible: false
};
this.openModal = this.openModal.bind(this);
}
openModal() {
console.log("Open modal called ", this.state.modalVisible);
const modalVisible = !this.state.modalVisible;
this.setState({
modalVisible
});
}
render() {
let styles = this.state.modalVisible
? { display: "block" }
: { display: "none" };
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<button
type="button"
onClick={this.openModal}
className="btn btn-info btn-lg"
>
Open Modal
</button>
<div
id="myModal"
className="modal fade in"
role="dialog"
style={styles}
>
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<button
type="button"
onClick={this.openModal}
className="close"
>
×
</button>
<h4 className="modal-title">Modal Header</h4>
</div>
<div className="modal-body">
<p>Some text in the modal.</p>
</div>
<div className="modal-footer">
<button
onClick={this.openModal}
type="button"
className="btn btn-default"
>
Close
</button>
</div>
</div>
</div>
</div>
</div>
);
}
}
I have tried multiple examples but this issue still persists.
Is there something I am missing ?
Any help greatly appreciated.
Hope this helps someone this is the code I have used instead and it worked fine.
class Header extends React.Component {
constructor(props) {
super(props);
this.handleClose = this.handleClose.bind(this);
this.handleShow = this.handleShow.bind(this);
this.state = {
show: false
};
}
handleClose() {
this.setState({
show: false
});
}
handleShow() {
this.setState({
show: true
});
}
render() {
// console.log(this.state);
return (
<div className="header-container">
<Button onClick={this.handleShow}>LOGIN</Button>
<Modal show={this.state.show} onHide={this.handleClose}>
<Modal.Header closeButton>
<Modal.Title>Modal Header</Modal.Title>
</Modal.Header>
<Modal.Body>Modal Body</Modal.Body>
</Modal>
</div>
);
}
}

React Rendering Multiple Modals in Same Component

I'm new to React and to coding in general. I'm trying to render multiple modals in the same component, but they are all being rendered at the same time so that it looks like all the links are rendering the text in the last modal.
Here's where the state is set:
class Header extends React.Component {
constructor () {
super();
this.state = {open:false}
this.openModal = this.openModal.bind(this);
this.closeModal = this.closeModal.bind(this);
this.handleModalChangeEnter = this.handleModalChange.bind(this, true);
this.handleModalChangeLogin = this.handleModalChange.bind(this, false);
}
openModal () {
this.setState({open: true}); }
closeModal () {
this.setState({open: false}); }
render() {
And here's the modal construction:
return (
<header style={home}>
<div style={hello}>
<img style={logo} src='public/ycHEAD.png'/>
<p style={slogan}>One Calendar for All of Yerevan's Tech Events</p>
</div>
<div style={subContainer}>
<ul style={modalDirectory}>
<Button onClick={this.openModal}
style={openButton}>
<li><a style={tabs}>Enter
</a></li>
</button>
<Modal style={modalCont}
isOpen={this.state.open}>
<button onClick={this.closeModal}
style={xButton}>x</button>
</Modal>
<button onClick={this.openModal}
style={openButton}>
<li><a style={tabs}>Login
</a></li>
</button>
<Modal style={modalCont}
isOpen={this.state.open}>
<p>Account</p>
<button onClick={this.closeModal}
style={xButton}>x</button>
</Modal>
Should there be a value in the empty parentheses -> openModal() & closeModal() ?
A friend helped me out with this one. The top half of code remains the same, what changes is in the modal construction (some really helpful aesthetic changes were also made to the 'html'):
return (
<header style={home}>
<div style={hello}>
<img style={logo} src='public/ycHEAD.png'/>
<p style={slogan}>One Calendar for All of Yerevan's Tech Events</p>
</div>
<div style={subContainer}>
<ul style={modalDirectory}>
<li style={tabs}>
<button
onClick={() => this.openModal('login')}
style={openButton}>
Enter
</button>
</li>
<li style={tabs}>
<button
onClick={() => this.openModal('calendar')}
style={openButton}>
Calendar
</button>
</li>
<li style={tabs}>
<button
onClick={() => this.openModal('team')}
style={openButton}>
Meet Us
</button>
</li>
</ul>
</div>
<Modal
style={modalCont}
isOpen={this.state.activeModal === 'login'}>
<p>1!</p>
<button onClick={this.closeModal}
style={xButton}>x</button>
</Modal>
<Modal
style={modalCont}
isOpen={this.state.activeModal === 'calendar'}>
<p>2!</p>
<button onClick={this.closeModal}
style={xButton}>x</button>
</Modal>
<Modal
style={modalCont}
isOpen={this.state.activeModal === 'team'}>
<p>3!</p>
<button onClick={this.closeModal}
style={xButton}>x</button>
</Modal>
</header>
If anyone else can provide a thorough explanation, please do so! Also, there is another way to do this using 'bind', but I don't know how.
I have created similar approach but more detailed model for those who need this solution when using "react-modal". It's not clear in question above if react-modal was used or not because import section is missing, but seems to have references to it. For those who are looking for solution using react-modal to display multiple modals in same component, so here is solution and demo :
import React from "react";
import Modal from "react-modal";
class MutipleButtonsWithModalInSameComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
showModal: false,
activeModal: "",
};
this.handleOpenModal = this.handleOpenModal.bind(this);
this.handleCloseModal = this.handleCloseModal.bind(this);
}
handleOpenModal(val) {
this.setState({ activeModal: val });
this.setState({ showModal: true });
}
handleCloseModal() {
this.setState({ showModal: false });
this.setState({ showModal: "" });
}
render() {
return(
<>
{/* {'one item with modal link -login'} */}
<div className="icon">
<a
className="button"
onClick={() => this.handleOpenModal("login")}
>
login (modal popup)
</a>
<Modal
isOpen={
this.state.showModal &&
this.state.activeModal === "login"
}
contentLabel="login Modal"
>
<div className="content">
<button className="close" onClick={this.handleCloseModal}>X</button>
<p>login content in here</p>
</div>
</Modal>
</div>
{/* {'another item with modal link calendar, add more by mutiplying this below'} */}
<div className="icon">
<a
className="button"
onClick={() => this.handleOpenModal("calendar")}
>
calendar (modal popup)
</a>
<Modal
isOpen={
this.state.showModal &&
this.state.activeModal === "calendar"
}
contentLabel="calendar Modal"
>
<div className="content">
<button className="close" onClick={this.handleCloseModal}>X</button>
<p>calendar content in here...</p>
</div>
</Modal>
</div>
{/* {'another item with modal link team, add more by mutiplying this below'} */}
<div className="icon">
<a
className="button"
onClick={() => this.handleOpenModal("team")}
>
team (modal popup)
</a>
<Modal
isOpen={
this.state.showModal &&
this.state.activeModal === "team"
}
contentLabel="team Modal"
>
<div className="content">
<button className="close" onClick={this.handleCloseModal}>X</button>
<p>team content in here...</p>
</div>
</Modal>
</div>
</>
)
}
}
export default MutipleButtonsWithModalInSameComponent;
Here is a stackblitz link or demo
You can do it in two ways.
1) Simple but doesn't scale: Maintain different state variables and functions for each Modal. i.e.,
this.state = {openModal1:false, openModal2:false}
this.openModal1 = this.openModal1.bind(this);
this.closeModal1 = this.closeModal1.bind(this);
this.openModal2 = this.openModal2.bind(this);
this.closeModal2 = this.closeModal2.bind(this);
As we can see, the problem with this is redundancy of the code.
2) Use functions to eliminate redundancy: Maintain a function to change the content of the modal.
class Header extends React.Component {
constructor () {
super();
this.state = {open:false, ModalContent:''}
this.openModal = this.openModal.bind(this);
this.closeModal = this.closeModal.bind(this);
this.handleModalChangeEnter = this.handleModalChange.bind(this);
this.handleModalChangeLogin = this.handleModalChange.bind(this);
}
openModal () {
this.setState({open: true}); }
closeModal () {
this.setState({open: false}); }
handleModalChange1() {
this.setState({ ModalContent : '<h1>Modal1 Content</h1>'
}
handleModalChange2() {
this.setState({ ModalContent : '<h1>Modal2 Content</h1>'
}
render() {
Modal Construction Should be :
return (
<header style={home}>
<div style={hello}>
<img style={logo} src='public/ycHEAD.png'/>
<p style={slogan}>One Calendar for All of Yerevan's Tech Events</p>
</div>
<div style={subContainer}>
<ul style={modalDirectory}>
<button onClick={this.handleModalChange1}
style={openButton}>
<li><a style={tabs}>Enter
</a></li>
</button>
<button onClick={this.handleModalChange2}
style={openButton}>
<li><a style={tabs}>Login
</a></li>
</button>
<Modal style={modalCont}
isOpen={this.state.open}>
<div dangerouslySetInnerHTML={{__html: this.state.ModalContent}} />
<button onClick={this.closeModal}
style={xButton}>x</button>
</Modal>

Resources