Show popup from another component using functions in react (.jsx)? - reactjs

Hello there I'm new with Reactjs and just have a quick question.
I have a modal component that I want to show up when a function is called from another component.
The modal component
const Popup = (props) => {
const [open, setOpen] = React.useState(false);
const toggle = () => {
setOpen(!open);
};
return (
<div>
<Button onClick={toggle}>Click Me</Button>
<Modal className='successModal text-center' open={open} centered={true} size='lg'>
<ModalHeader>{props.title}</ModalHeader>
<ModalBody>
<div>
<img src={successIcon} alt='Success Icon' />
<div className='container my-4'>
<h4>{props.body}</h4>
</div>
</div>
<Button onClick={toggle}>Close</Button>
</ModalBody>
</Modal>
</div>
);
};
export default Popup;
This is the function that I need to show up the popup when it's called
const finishPayment = () => {
console.log('just checking if this function is called properly');
return (
<Popup
toggle={this.toggle}
title='Success'
body='Welcome, everything was fine.'
/>
);
};
Can someone help me how to figure out this?
I think I need to pass something as props, but not sure what.
Thanks!

Your buttons are using "onClick" events, therefore, you must pass a function as argument, but you are passing a constant. Convert your "toggle()" arrow function to function or implement another arrow function inside the "onClick" events, so as in the examples below:
With arrow function:
const Popup = (props) => {
const [open, setOpen] = React.useState(false);
const toggle = () => {
setOpen(!open);
};
return (
<div>
<Button onClick={() => toggle()}>Click Me</Button>
<Modal className='successModal text-center' open={open} centered={true} size='lg'>
<ModalHeader>{props.title}</ModalHeader>
<ModalBody>
<div>
<img src={successIcon} alt='Success Icon' />
<div className='container my-4'>
<h4>{props.body}</h4>
</div>
</div>
<Button onClick={() => toggle()}>Close</Button>
</ModalBody>
</Modal>
</div>
);
};
export default Popup;
With vanilla/traditional functions:
const Popup = (props) => {
const [open, setOpen] = React.useState(false);
function toggle() {
setOpen(!open);
};
return (
<div>
<Button onClick={toggle}>Click Me</Button>
<Modal className='successModal text-center' open={open} centered={true} size='lg'>
<ModalHeader>{props.title}</ModalHeader>
<ModalBody>
<div>
<img src={successIcon} alt='Success Icon' />
<div className='container my-4'>
<h4>{props.body}</h4>
</div>
</div>
<Button onClick={toggle}>Close</Button>
</ModalBody>
</Modal>
</div>
);
};
export default Popup;

Related

Retrieve form input values using React Children as a wrapper

I need to retrieve the input form data using the wrapper save button (Togglable component) and not a submit button inside a form component.
I have this form.
const BasicDataForm = () => {
return (
<form>
<div>
<label htmlFor="nameInput">Your Name: </label>
<input placeholder="Write your name here" type="text" id="nameInput" />
</div>
<div>
<label htmlFor="ageInput">Your Age: </label>
<input placeholder="Write your age here" type="number" id="ageInput" />
</div>
</form>
);
};
And the wrapper
const Togglable = ({ title, children }) => {
const [visible, setVisible] = useState(false);
const hideWhenVisible = { display: visible ? 'none' : '' };
const showWhenVisible = { display: visible ? '' : 'none' };
return (
<header>
<h2>{title}</h2>
<div style={hideWhenVisible}>
<button onClick={() => setVisible(true)}>Show</button>
</div>
<div style={showWhenVisible}>
<button>Save</button> {/* This button needs to retrieve all input form data from children */}
<button onClick={() => setVisible(false)}>Close</button>
{children}
</div>
</header>
);
};
And the main component
const App = () => {
return (
<>
<h1>Form Wrapper</h1>
<Togglable title="Basic Data Form">
<BasicDataForm />
</Togglable>
</>
);
};
I don't know if it's necessary to add a useState inside the form component. I also tried adding a new prop in the Togglable component that bind the onClick event of the save button to the onSubmit event of the form, but not work because there is no submit button inside form component.
The solution was much easier than I thought. You only need to wrap the entire children inside a <form> label and render only the content of the inputs. For every children a button will be added and you will manage the form outside the wrapper.
const Togglable = ({ title, children, handleSubmit }) => {
const [visible, setVisible] = useState(false);
const hideWhenVisible = { display: visible ? 'none' : '' };
const showWhenVisible = { display: visible ? '' : 'none' };
return (
<header>
<h2>{title}</h2>
<div style={hideWhenVisible}>
<button onClick={() => setVisible(true)}>Show</button>
</div>
<div style={showWhenVisible}>
<button onClick={() => setVisible(false)}>Close</button>
<form onSubmit={handleSubmit}>
{children}
<button type="submit">Save</button>
</form>
</div>
</header>
);
};

Material UI Dialog not closing when clicking the overlay

I have created a reusable dialog/modal using React and Material UI.
When I try to click the overlay, something weird happens.
Instead of closing the modal and setting 'open' to false, the scripts directly sets open to true again for some reason.
The handleClickOpen is triggered when clicking the overlay and I can't find the problem causing this.
Dialog component:
const { onClose, open } = props;
const handleClose = () => {
onClose();
};
const preventDef = (e) => {
e.stopPropagation();
};
return (
<Dialog open={open} onClose={onClose} className={className} onClick={handleClose}>
<Container>
<Grid container className={`${className}__container`}>
<Grid item xs={12} sm={props.colsAmount} onClick={preventDef} className={`${className}__column`}>
{props.component}
{props.closeButton && (
<div className={`${className}__close`} onClick={handleClose}>
<Close />
</div>
)}
</Grid>
</Grid>
</Container>
</Dialog>
);
The component I load and trigger the dialog in:
const [open, setOpen] = React.useState(false);
const handleClose = (e) => {
setOpen(false);
};
const handleClickOpen = () => {
setOpen(true);
};
return (
<div className={[classes.ShopCard]} onClick={handleClickOpen}>
<div className={`${classes.ShopCard}__image`}>
<div className={`${classes.ShopCard}__image__wrapper`}>
<img src={image} alt={alt} />
<div className={`${classes.ShopCard}__image__price`}>Vanaf €{price}</div>
</div>
</div>
<div className={`${classes.ShopCard}__content`}>
<Title title={title} size="h6" />
<Body>{description}</Body>
</div>
<div className={`${classes.ShopCard}__button`}>
<Button label="In winkelwagen" startIcon={<AddShoppingCart />} />
</div>
<CustomDialog
open={open}
onClose={handleClose}
colsAmount={6}
component={<ShopPopUp />}
closeButton="true"
/>
</div>
If someone could explain why the open state gets set to true, that would be great.
It's because of:
<div className={[classes.ShopCard]} onClick={handleClickOpen}>
It exists higher up in the DOM than the overlay thus it always fires.

How to pass state properties from component to component

I am currently learning React and I am trying to create a basic todo list app. I am facing an issue in the understanding of how passing data from component to component.
I need that when I add a task in the modal of my home component it gets added in the "pub" state of my public task component in order for the task to be rendered.
I joined the code of both components,
Hope someone can help me :)
function PublicTask (){
const [pub,setPub] = useState([{id: 1, value : "test"},{id: 2, value : "test2"}]);
function ToDoPublicItem() {
const pubT = pub.map(value =>{
return(
<div className= 'pubTask-item'>
<li>{value.value}</li>
</div>
)
});
return(
<div>
<div>
{pubT}
</div>
</div>
);
}
return(
<div className= 'item-container'>
<h2 style={{color:'white'}}>Public Tasks</h2>
<ToDoPublicItem/>
</div>
);
}
export default PublicTask;
function Home() {
const [show,setShow] = useState(false);
const [pubTask,setPubTask] = useState([]);
function openModal() {
setShow(true);
}
function Modal(){
const[textTodo, setTextTodo] = useState('')
const addItem = () => {
const itemTopush = textTodo;
pubTask.push(itemTopush);
}
return(
<div className='modal'>
<div className = 'modal-title'>
<h2>ADD A TODO</h2>
<hr></hr>
</div>
<div className= 'modal-body'>
<input type='text' onChange = {(e) => setTextTodo(e.target.value)}/>
<input type="checkbox" id="pub" value ='public'/>
<label Htmlfor="pub">Public</label>
<input type="checkbox" id="priv" value= 'private '/>
<label Htmlfor="riv">Private</label>
<hr></hr>
<Button id='button-add' size='large' style={{backgroundColor : 'white'}} onClick={()=> addItem()}>ADD</Button>
<hr></hr>
<Button id='button-close' size='large' style={{backgroundColor : '#af4c4c'}} onClick= {()=> setShow(false)} >CLOSE</Button>
</div>
</div>
)
}
return(
<div>
<h1 style={{textAlign:'center'}}>You are logged in !</h1>
<div>
<button id='button-logout' onClick = {() => firebaseApp.auth().signOut()}>Logout</button>
</div>
<div>
<Fab color="primary" aria-label="add" size = 'large' onClick = {() => openModal()}>
<Add/>
</Fab>
{show ? <Modal/> : <div></div>}
</div>
<div>
<Router>
<div className='pub-container'>
<Link to='/publicTasks'>Public Tasks </Link>
</div>
<div className='ongo-container'>
<Link to='/onGoingTasks'>On Going Tasks </Link>
</div>
<div className='finish-container'>
<Link to='/finishedTasks'>Finished Tasks </Link>
</div>
<Route path='/publicTasks' component = {PublicTask}/>
<Route path='/onGoingTasks' component = {OngoingTask}/>
<Route path='/finishedTasks' component = {FinishedTask}/>
</Router>
</div>
</div>
);
}
export default Home;
You can share data between react components like this:
const [value, setValue] = useState("test"); // data that you want to share
return (
<Parent data={value}> // pass data to parent in your child component
);
<h1>{this.props.data}</h1> // do something with the data in the parent component

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

React Modal Submit Form

I'm trying to print out a simple buttton clicked text whenever the submit button is click on my reactstrap modal and somehow my code doesn't do anything, not sure what I have wrong.
I have attached a picture for better visualisation , I'm using reactstrap Modal.
import React, { useState } from "react";
import { Modal, ModalHeader, ModalBody, ModalFooter } from "reactstrap";
import Button from "./Button";
// NOTICE
// Modal is brought in with it's own trigger, so import the component where you want the trigger to be.
const ModalComponent = (props) => {
const {
buttonText,
title,
actionButtonText,
cancelButtonText,
children,
className,
} = props;
const [modal, setModal] = useState(false);
const toggle = () => setModal(!modal);
const alertshow = () => {
alert("button clicked");
};
const closeBtn = (
<button className="close" onClick={toggle}>
×
</button>
);
return (
<div>
<a className="btn_link" onClick={toggle}>
{buttonText}
</a>
<form onSubmit={alertshow}>
<Modal isOpen={modal} toggle={toggle} className={className}>
<ModalHeader className=" border-0" toggle={toggle} close={closeBtn}>
{title}
</ModalHeader>
<ModalBody className="text-left border-0">
<p className="modal-label">Please enter your email address</p>
{children}
</ModalBody>
<ModalFooter className="modal-footer border-0">
<Button className="btn_secondary modal-btn" onClick={toggle}>
{cancelButtonText}
</Button>{" "}
<input
className="btn btn_primary modal-btn"
type="submit"
value={actionButtonText}
/>
</ModalFooter>
</Modal>
</form>
</div>
);
};
export default ModalComponent;
Its happening form should be part of modal not modal should be part of form. This is why its not referencing onSubmit. You need to do this:
<Modal isOpen={modal} toggle={toggle} className={className}>
<form onSubmit={alertshow}>
...rest all content
</Form>
</Modal>
Here is full code:
import React, { useState } from "react";
import "./styles.css";
import { Modal, ModalHeader, ModalBody, ModalFooter, Button } from "reactstrap";
// NOTICE
// Modal is brought in with it's own trigger, so import the component where you want the trigger to be.
const ModalComponent = (props) => {
const {
buttonText,
title,
actionButtonText,
cancelButtonText,
children,
className
} = props;
const [modal, setModal] = useState(false);
const toggle = () => setModal(!modal);
const alertshow = () => {
alert("button clicked");
};
const closeBtn = (
<button className="close" onClick={toggle}>
×
</button>
);
return (
<div>
<div onClick={toggle}>{buttonText}</div>
<Modal isOpen={modal} toggle={toggle} className={className}>
<form onSubmit={alertshow}>
<ModalHeader className=" border-0" toggle={toggle} close={closeBtn}>
{title}
</ModalHeader>
<ModalBody className="text-left border-0">
<p className="modal-label">Please enter your email address</p>
{children}
</ModalBody>
<ModalFooter className="modal-footer border-0">
<Button className="btn_secondary modal-btn" onClick={toggle}>
{cancelButtonText}
</Button>{" "}
<input
className="btn btn_primary modal-btn"
type="submit"
value={actionButtonText}
/>
</ModalFooter>
</form>
</Modal>
</div>
);
};
export default function App() {
return (
<div className="App">
<ModalComponent
title="Hello"
cancelButtonText="Cancel"
actionButtonText="Submit"
buttonText="testing"
/>
</div>
);
}
Here is the demo: https://codesandbox.io/s/fervent-bash-51lxe?file=/src/App.js:0-1826
Accepted answer doesn't work when Modal is scrollable.
Here is how to resolve the issue:
<Modal show={ show } onHide={ onClose }
scrollable={ true }
onSubmit={ handleSubmit(onSave) }
dialogAs={ FormWrappedModal }>
<Modal.Header closeButton>
<Modal.Title>some title</Modal.Title>
</Modal.Header>
<Modal.Body>some body</Modal.Body>
<Modal.Footer>some body</Modal.Footer>
</Modal>
We need to introduce custom component FormWrappedModal for that purpose:
const FormWrappedModal = ( props: any)=>{
return (
<form onSubmit={ props.onSubmit }>
<Modal.Dialog { ...props } />
</form>
);
};

Resources