Button click pops up all the modals instead of showing only one - reactjs

I am passing data to the modal from a parent component. I show the modal on a button click. But the modal body doesn't contain the desired data. It appends all the data inside the body instead of showing only the necessary content.
This is the parent component
{this.state.response.map((value, id) => {
return (
<div className="col-md-3 file-card-viewSection">
<Button
id={id+1}
onClick={(e) => {this.setState({ showDocumentsModal: true })}}>
<i className="fas fa-eye"></i>
</Button>
</div>
<ViewDocumentDetailsModal
show={this.state.showDocumentsModal}
onHide={this.modalClose.bind(this)}
documentdata={value.result} />
);
})}
This is the child component containing the bootstrap modal
class viewDocumentDetailsModal extends Component {
render() {
console.log(this.props)
return (
<Modal
{...this.props}
size="lg"
centered
>
<Modal.Header closeButton>
<Modal.Title id="contained-modal-title-vcenter">
Modal heading
</Modal.Title>
</Modal.Header>
<Modal.Body>
<h4>Centered Modal</h4>
<ReactJson src={this.props.documentdata} />
</Modal.Body>
<Modal.Footer>
<Button onClick={this.props.onHide}>Close</Button>
</Modal.Footer>
</Modal>
);
}
}
When i click on the button it displays both modals at once. I am not able to figure out why. Kindly help me out. Thanks.
This is how I get the output
This is the entire parent component
{this.state.response.map((value, id) => {
return(
<div>
<Card className="mb-4">
<Card.Body className="row file-card-row">
<div className="col-md-1 file-card-index">
{id+1}
</div>
<div className="col-md-4 file-card-filename">
{value.result.Filename}
</div>
<div className="col-md-4 file-card-status">
{value.result.Status}
</div>
<div className="col-md-3 file-card-viewSection">
<Button id={id+1} onClick={(e) => {this.setState({ showDocumentsModal: true, modalOpened: id })}}>
<i className="fas fa-eye"></i>
</Button>
</div>
</Card.Body>
</Card>
</div>
);
})}
<ViewDocumentDetailsModal
show={this.state.showDocumentsModal}
onHide={this.modalClose.bind(this)}
documentdata={this.state.response[this.state.modalOpened].result}
/>
</div>

First, I've tried to adjust the indentation of your code (the edit has to be accepted first), but it seems to me that, in the first piece of code, you return a <div> element and <ViewDocumentDetailsModal> element without any parent component: in React that should not be possible (you should always have a single element returned, if you are in the render() method.
Anyways, I think that you retrieve more than one Modal because <ViewDocumentDetailsModal> element is returned inside the this.state.response.map() callback: this way, for each response you return a different Modal.
If in this.state.response you have data for different Modal, but you want to display just one of them, you need to have a different number property in the state, like this.state.modalOpened, in which you keep saved the index of the modal data you want to display.
Then, in the return() method, you should write something like this:
<>
{this.state.response.map((value, id) => {
return (
<div className="col-md-3 file-card-viewSection">
<Button
id={id+1}
onClick={(e) => {this.setState({ showDocumentsModal: true, modalOpened: id })}}>
<i className="fas fa-eye"></i>
</Button>
</div>
);
})}
<ViewDocumentDetailsModal
show={this.state.showDocumentsModal}
onHide={this.modalClose.bind(this)}
documentdata={this.state.response[this.state.modalOpened].result} />
</>

Related

Need to get form values outside the form in a modal

I am using ANTD React UI library.
<Modal
width="1100px"
centered
footer={null}
title={
<div className="d-flex align-items-center">
<div className="flex-grow-1">Record Profiles</div>
<div className="mr-4">
<Button
htmlType="submit"
type="primary"
onClick={() =>{this.SaveData(this.form.getFieldValue())}}
icon={<SaveOutlined />}
className="save_btn"
loading={this.state.saving}>
</Button>
<Button
onClick={() => { this.props.onCancel() }}
htmlType="button"
type="primary"
className="cancel_btn ml-2"
icon={<CloseCircleOutlined />}>
</Button>
</div>
</div>
}
visible={true}
closable={false}
okText="Yes"
cancelText="No"
maskClosable={false}
>
<Form
autoComplete="off"
layout="horizontal"
ref={(r) => this.form = r}
initialValues={this.props.record}
onFinish={this.SaveData}
>
.
.
.
</Form>
</Modal>
I want to call the save and close buttons on top of the side of the title. It is displaying correctly, but due to outside form functionalities don't work because the form values don't get outside. Is there any method to get the values outside or form submit?

the voiceover does not automatically read the "aria-labelledby" contained in my modal when it is displayed on the screen

I am trying to make a modal with accessibility. Basically, the modal gets a child and this child will be the content of the modal:
<div
id="modal"
role="dialog"
aria-labelledby="modal-label"
aria-describedby="modal-desc"
tabIndex={0}
className="modal"
>
{*/ {children} */}
<div className="flexContainer">
<div id="modal-desc">
<div>hey</div>
<div>
<div>This is the description</div>
<div>I am a button</div>
</div>
</div>
<div>
<div id="modal-label">This is the title</div>
</div>
</div>
</div>
When the modal opens, the voiceover reads the texts as it is in the gif, but I don't know why it doesn't read the aria-labelledby. My idea is that I can pass any child to my modal and the voiceover reads everything that is contained in aria-labelledby and in aria-describedby.
how can I make the voiceover read "aria-labelledby" automatically?
this is my live code
const [openModal, setOpenModal] = useState(false);
const Modal = ({ children }) => {
useEffect(() => {
document.querySelector("#modal")?.focus();
}, []);
return (
<div
id="modal"
role="dialog"
aria-labelledby="modal-label"
aria-describedby="modal-desc"
tabIndex={0}
className="modal"
>
{children}
</div>
);
};
const ModalContent = () => {
return (
<div className="flexContainer">
<div id="modal-desc">
<div>hey</div>
<div>
<div>This is the description</div>
<div>I am a button</div>
</div>
</div>
<div>
<div id="modal-label">This is the title</div>
</div>
</div>
);
};
return (
<>
<button
aria-hidden="true"
onClick={() => {
setOpenModal(true);
}}
>
open modal
</button>
{openModal && (
<Modal>
<ModalContent />
</Modal>
)}
</>
);
There's nothing wrong with the way you're using aria-labelledby, however it may be that the content of your modal (#modal-desc) is being added after the modal container (#modal), so the #modal-label ID is not immediately available in the DOM when the modal first appears. Sometimes this can cause problems for screen readers when content (particularly content that is linked to aria-labelledby or aria-describedby) is added dynamically to the DOM.
A better way to ensure that your modal label is announced is to include it in the aria-label attribute in your dialog container, e.g.:
<div id="modal" role="dialog" aria-label="This is the title" aria-describedby="modal-desc" tabIndex="0" class="modal">
As an aside, you have aria-hidden="true" on your "open modal" button. You should remove this because it hides the button from screen readers.

How to pass parameter value into modal box with react

I am still not familiar with react.js and I am doing a NFT app whereby you click a button and each individual NFT profile will show in a popup modal box which I have already successful integrate the modal box and able to pass the value to a function handleShow(owner) but I have no idea how to send or display this value (owner) into my modal box. Appreciate you guys, can help on my situation. thank you.
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
function handleShow(owner) {
alert(owner);
setShow(true);
}
<div className="min-h-screen bg-gray-100">
<div className="max-w-7xl mx-auto sm:px-6 lg:px-8 ">
<div className="text-black-100 text-6xl pt-28 pb-10">Monkey</div>
{mintedNftState.state === "PENDING" && (
<div className="text-xl text-white">LOADING...</div>
)}
{mintedNftState.state === "SUCCESS" && (
<div className="grid grid-cols-3 gap-4">
{mintedNftState.data.map(
({ id, image, name, description, owner }) => {
return (
<div key={id} className="bg-white rounded p-2">
<img src={image} className="mx-auto p-4" alt={name} />
<div className="text-xl">{name}</div>
<div className="font-myfont">{description}</div>
<hr className="my-4" />
<div className="text-left text-sm">Owned By:</div>
<div className="text-left text-xs">{owner}</div>
<div className="mt-12">
<Button variant="primary" onClick={() => handleShow(owner)}>
Launch demo modal
</Button>
</div>
</div>
);
}
)}
</div>
)}
</div>
<Modal show={show} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>Modal heading</Modal.Title>
</Modal.Header>
<Modal.Body>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
close
</Button>
<Button variant="primary" onClick={handleClose}>
Save Changes
</Button>
</Modal.Footer>
</Modal>
</div>
I would first add an owner state
const [owner, setOwner] = useState(null);
In handleShow you can set the owner like this
function handleShow(owner) {
setOwner(owner)
setShow(true);
}
You can finally display the owner value between <Modal.Body> tags
<Modal.Body>
<p>{owner}</p>
</Modal.Body>
When closing the modal you can set the owner to null
const handleClose = () => {
setShow(false);
setOwner(null);
}

React Js Multiple Modal

Hi i'm trying to learn react and i was tryign to make multiple modal but the same desgine and everything but different content inside it how?
import './Works.css';
import React, { useState } from 'react'
import Modal from '../Modal/Modal'
function Works(props){
const [isOpen, setIsOpen] = useState(false)
return(
<div>
<div className={props.NameClass}>
<h1>{props.icon}</h1>
<h1>{props.title}</h1>
<p >simple pargraph</p>
<button className="button_more" onClick={() => setIsOpen(true)}><i className="fas fa-caret-right"></i></button>
</div>
<Modal open={isOpen} title="hi" onClose={() => setIsOpen(false)}>
</Modal>
</div>
)
}
export default Works
and if you look at <Modal open={isOpen} title="here i wanna different title" onClose={() => setIsOpen(false)}>
and here the App.js calling the file on top multiple times but i wanna for example if someone click on the second project it change the title to for example "hi you're in the second modal!"
<div class="Div-Projects">
<Works NameClass="First_Project" icon="💳" title="first" />
<Works NameClass="Second_Project" icon="🎓" title="second" />
<Works NameClass="Third_Project" icon="👩🏻‍💻" title="third" />
</div>
and here the modal code!
import './Modal.css'
function Modal({open , title, onClose}){
if(!open) return null
return(
<div className="popup">
<div className="content">
<h1>{title}</h1>
<div className="p">
<p>login system for students attendees with an arduino and python it shows how fast and stable for doing the job.login system for students attendees with an arduino and python it shows how fast and stable for doing the job.login system for students attendees with an arduino and python it shows how fast and stable for doing the job.</p>
</div>
<div className="buttons">
<button className="dismiss" onClick={onClose}>Dismiss!</button>
<button className="github" onClick={() => window.open( 'https://github.com/Majiedo/Login_System')}><i className="fab fa-github"></i></button>
<button className="code"><i className="fas fa-code"></i></button>
</div>
</div>
</div>
)
}
export default Modal
Why don't you pass Works props to Modal component? Like this:
function Works(props){
const [isOpen, setIsOpen] = useState(false)
return(
<div>
<div className={props.NameClass}>
<h1>{props.icon}</h1>
<h1>{props.title}</h1>
<p >simple pargraph</p>
<button className="button_more" onClick={() => setIsOpen(true)}><i className="fas fa-caret-right"></i></button>
</div>
<Modal open={isOpen} title={`hi you're in the ${props.title} modal!`} onClose={() => setIsOpen(false)}/>
</div>
)
}
You need to pass in title {props.title}
change it:
<Modal open={isOpen} title="hi" onClose={() => setIsOpen(false)}>
</Modal>
On this:
<Modal open={isOpen} title={`hi you're in the ${props.title}`} onClose={() => setIsOpen(false)}/>

onClick Rendering is not happening ReactJs

I am creating a web application with react.js also using react-bootstrap.
What I want to accomplish is when user click on button then modal will appear but that is not happening.
Button code
<div className="rightButtons">
<button name="updateItem" className="btn btn-primary" onClick={() => { this.onUpdateItem(this.props.selectedAppTypeId)}} >Update Item</button>
</div>
function which will be called.
onUpdateItem = (id) => {
return (
<div className="static-modal">
<Modal.Dialog>
<Modal.Header>
<Modal.Title>Modal title</Modal.Title>
</Modal.Header>
<Modal.Body>One fine body...</Modal.Body>
<Modal.Footer>
<Button>Close</Button>
<Button bsStyle="primary">Save changes</Button>
</Modal.Footer>
</Modal.Dialog>
</div>
);
}
Any help would be great help. Thanks.
You are returning HTML into your onClick handler, and not into the Component's render method. If you want to show HTML content after an onClick, you need to actually return those HTML elements within the actual render. Try this:
class Component extends React.Component {
state = {
showModal: false
}
renderModal = () => {
return (
<div className="static-modal">
<Modal.Dialog>
<Modal.Header>
<Modal.Title>Modal title</Modal.Title>
</Modal.Header>
<Modal.Body>One fine body...</Modal.Body>
<Modal.Footer>
<Button>Close</Button>
<Button bsStyle="primary">Save changes</Button>
</Modal.Footer>
</Modal.Dialog>
</div>
);
}
render() {
return(
<div>
<button onClick={() => this.setState({showModal:true})}> Show </button>
{this.state.showModal && this.renderModal()}
</div>
)
}
}
Edit: You can also export that entire Modal return statement into its own component, and conditionally render the component when the showModal state is true.
const ModalComponent = (props) => {
return(
<div className="static-modal">
<Modal.Dialog>
<Modal.Header>
<Modal.Title>Modal title</Modal.Title>
</Modal.Header>
<Modal.Body>One fine body...</Modal.Body>
<Modal.Footer>
<Button>Close</Button>
<Button bsStyle="primary">Save changes</Button>
</Modal.Footer>
</Modal.Dialog>
</div>
)
}
class ParentComponent extends React.Component {
state = {
showModal: false
}
render(){
return(
<div>
<button onClick={() => this.setState({showModal:true})}>
Show Modal
</button>
{this.state.showModal && <ModalComponent id='0af141random'/>}
</div>
)
}
}
The problem that you have is that you're passing a react function component as an event handler; the return value of the function is a react component, but calling the function by itself won't mount that component in the DOM and display it.
A better way to make this happen might be to place your Modal component in your component hiearchy, and control whether it is shown by using a callback to change the state of a parent component.
Something like this:
class ParentComponent extends React.Component {
showModal() {
this.setState{
modalActive: true;
}
}
render() {
<div>
<Button onClick={showModal}>Show me the modal!</Button>
<Modal active={this.state.modalActive} />
</div>
}
}
const modalComponent = (props) => {
return (<div style={{ display: (props.isActive) ? "block" : "none "}}>
<h1>I'm a modal!</h1>
</div>)
}
I haven't checked, but I'm sure React Bootstrap has its own prop for displaying/hiding modals.
EDIT: Here's a code example from the react bootstrap documentation that shows it in use https://react-bootstrap.github.io/components/modal/#modals-live

Resources