Sending FormData from modal to parent component's method in react - javascript

I have a problem calling parent method - HandleInsert(formData) with the "formData" argument being made on the child component.
On the parent component (relevant code)
addModalClose = () => {
this.setState( {
addModalShow : false
});
}
addModalOpen = () => {
this.setState( {
addModalShow : true
});
}
async HandleDelete(id : string) {
this.setState({
tickets: await api.deleteTickets(id)
})
}
and I update props of Modal here:
<Button id="button" className="add_ticket" onClick={this.addModalOpen}>New Ticket</Button>
{/*define new props for Modal component in parent component*/}
<AddModal
show={this.state.addModalShow}
onHide={this.addModalClose}
onSubmit={this.HandleInsert}
/>
On the child component: (the modal itself)
import React, {Component} from 'react'
import {Modal, Button, Row, Col, Form} from 'react-bootstrap';
import {App} from './App'
export class AddModal extends Component {
constructor(props) {
super(props);
this.state = {
email : "",
title : "",
content : ""
}
}
onHide;
onSubmit;
handleEmailChange = e => {
this.setState({email: e.target.value});
};
handleTitleChange = e => {
this.setState({title: e.target.value});
};
handleContentChange = e => {
this.setState({content: e.target.value});
};
render(){
let formData = new FormData();
return(
<Modal
{...this.props}
size="lg"
aria-labelledby="contained-modal-title-vcenter"
centered
>
<Modal.Header closeButton>
<Modal.Title id="contained-modal-title-vcenter">
Ticket Details:
</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form>
<Form.Group controlId="exampleForm.ControlInput1" >
<Form.Label>Email:</Form.Label>
<Form.Control type="email" placeholder="name#example.com" value={this.state.email} onChange={this.handleEmailChange}/>
</Form.Group>
<Form.Group controlId="exampleForm.ControlInput2">
<Form.Label>Title:</Form.Label>
<Form.Control type="title" value={this.state.title} onChange={this.handleTitleChange}/>
</Form.Group>
<Form.Group controlId="exampleForm.ControlTextarea1">
<Form.Label>Content:</Form.Label>
<Form.Control as="textarea" rows="3" value={this.state.content} onChange={this.handleContentChange}/>
</Form.Group>
</Form>
</Modal.Body>
{ formData.append("id", "bded4175-a519-5dee-abed-014e7242e6f0")}
{ formData.append("title", this.state.title)}
{ formData.append("content", this.state.content)}
{ formData.append("userEmail",this.state.email)}
{ formData.append("creationTime", new Date())}
<Modal.Footer>
<Button variant="success" onClick={() => this.props.onSubmit(formData)}>Create</Button>
<Button variant="danger" onClick={this.props.onHide}>Close</Button>
</Modal.Footer>
</Modal>
);
}
}
the error I'm getting is this:
where it wont understand that it's a function..
how I define parent/child relationship? it's not enough just calling component from one compoenent to another?
I'm new on react so I don't get quite well those notions.

you are doing this wrong
onCreate(formData)={this.HandleInsert(formData)}
this is should be assing like
onCreate={(formData)=>{this.HandleInsert(formData)}}
updated answer
1.where is HandleInsert is defined in parent component???
<Button id="button" className="add_ticket" onClick={this.addModalOpen}>New
Ticket</Button>
<AddModal
show={this.state.addModalShow}
onHide={this.addModalClose}
onSubmit={this.HandleInsert}
/>
2.your child component is may not receiving HandleInsert from parent component as props.
3.as i can see in current code
<Modal.Footer>
<Button variant="success" onClick={this.props.HandleInsert(formData)}>Create</Button>
<Button variant="danger" onClick={this.props.onHide}>Close</Button>
</Modal.Footer>
you are calling handleInsert again in wrong way it should be like
onClick={()=>{this.props.HandleInser(formData)}}
another thing is where FormData is defined or imported in your code??

Related

React Bootstrap Modal not working on submit Button

I am looking to send the value from the Form.Control to the button so I can do some logic but I cannot seem to get this value from the input. I tried using reft but I cant use refs in a functional component, so I'm using the textInput. Please help, been stuck for 3 days. thx
import React from "react";
import { Modal, Form, Row, Col, Button } from "react-bootstrap";
import "./Login.css";
export const ForgotPassword = (props) => {
let textInput = null;
const handleClick = () => {
console.log("i am here", textInput.focus());
};
return (
<>
<Modal
{...props}
aria-labelledby="contained-modal-title-vcenter"
centered
>
<Modal.Header closeButton>
<Modal.Title id="contained-modal-title-vcenter">
Forgot Password
</Modal.Title>
</Modal.Header>
<Modal.Body className="show-grid">
<Form.Label>Please enter your Employee ID.</Form.Label>
<Row>
<Col className="lm-qus" md={5}>
Employee ID:
</Col>
<Col md={7}>
<Form.Control
type="text"
required
name="answer"
placeholder=""
ref={(input) => {
textInput = input;
}}
/>
</Col>
</Row>
</Modal.Body>
<Modal.Footer>
<Button onClick={props.onHide}>Cancel</Button>
<Button onClick={handleClick} type="submit">
Continue
</Button>
</Modal.Footer>
</Modal>
</>
);
};
This is not a modal specific problem. Make your Form.Control a controlled input by providing "value" attribute. Define state and set this state on change event of the input. You can then access this state everywhere, including the button:
const [value, setValue] = React.useState("");
const handleChange = (event) => setValue(event.target.value);
const handleClick = () => alert(value);
https://codesandbox.io/s/objective-pond-rs8r9f

Errors with authentication in a Modal using bootstrap and Firebase

I am utilizing react bootstrap and firebase to create a Modal to allow signIn - I have a create user component fully implemented but when I try to use a modal to handle my sign in it error out . Any help is much appreciated.
Uncaught (in promise) TypeError: Cannot destructure property 'email' of 'event.target.elements' as it is undefined.
import React, { useState, useCallback, useContext } from 'react';
import './Homepage.css';
import { Button, Modal, Form } from 'react-bootstrap';
import { Link, Redirect } from 'react-router-dom';
// Firebase Credentials
import app from '../firebase'
import { AuthContext } from '../Auth'
const Homepage = ({ history }) => {
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
const handleLogin = useCallback(
async (event)=> {
event.preventDefault();
const { email, password } = event.target.elements;
try {
await app.auth().signInWithEmailAndPassword(email.value, password.value);
history.push('/generate')
}catch(error){
alert(error);
}
},[history]
);
const { currentUser } = useContext(AuthContext);
if (currentUser) {
return
}
return (
<div className='welcomeContainer'>
<h1 className='welcomeBanner'>Resu.Me</h1>
<h4 className='welcomeMessage'>
Resu.me is the easiest solution for cover letters and resumes.
<br></br> Simply input your credentials and contact information - We
handle the rest!
</h4>
<Link className='genLeadButton' to='/generate'>
<Button>Let's make a Resume</Button>
</Link>
<Button onClick={handleShow} className='loginButton'>
Log In to Resu.me
</Button>
{/* <h2 className="servicesBanner">Score the job you deserve with the help of our tools</h2> */}
<h2 className='servicesContainer serviceA'>PLACEHOLDER A</h2>
<h2 className='servicesContainer serviceB'>PLACEHOLDER B</h2>
<h2 className='servicesContainer serviceC'>PLACEHOLDER C</h2>
<Modal show={show} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>Login</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form>
<Form.Group controlId='formBasicEmail'>
<Form.Label className='label'>Email Address</Form.Label>
<Form.Control
name='email'
type='email'
placeholder="Login email"
/>
</Form.Group>
<br></br>
<Form.Group controlId='formBasicPassword'>
<Form.Label>Password</Form.Label>
<Form.Control
name='password'
type='password'
placeholder='Password'
/>
</Form.Group>
</Form>
</Modal.Body>
<Modal.Footer>
<Button variant='secondary' type='submit' onClick={handleLogin}>
Login
</Button>
</Modal.Footer>
</Modal>
</div>
);
};
export default Homepage;
const { email, password } = event.target.elements;
will map the value by the input id (controlId for react-bootstrap forms) in these two rows
<Form.Group controlId='formBasicEmail'>
<Form.Group controlId='formBasicPassword'>
so you have to make them identical like:
const { formBasicEmail, formBasicPassword } = event.target.elements;
or
<Form.Group controlId='email'>
<Form.Group controlId='password'>

Conditonal rendering REACT modal component

I have a view modal component (ViewModal.js)
import React from 'react'
import { Button, Modal } from 'react-bootstrap';
import './Modal.css';
class ViewModal extends React.Component {
constructor() {
super();
this.state = {
}
}
handleModalShowHide() {
this.setState({ showHide: !this.state.showHide })
}
render() {
return (
<div>
<Button variant="success" onClick={() => this.handleModalShowHide()}>
Write a review
</Button>
<Modal show={this.state.showHide}>
<Modal.Header closeButton onClick={() => this.handleModalShowHide()}>
<Modal.Title>Add your review</Modal.Title>
</Modal.Header>
<Modal.Body>
ModalBody
</Modal.Body>
<Modal.Footer>
<Button variant="outline-secondary" onClick={() => this.handleModalShowHide()}>
Close
</Button>
<Button variant="outline-success" onClick={() => this.handleModalShowHide()}>
Save Review
</Button>
</Modal.Footer>
</Modal>
</div>
)
}
}
export default ViewModal;
I import this in another functional component called viewcard.js
The logic of viewcard.js is as follows
import React from 'react';
import ViewModal from './ViewModal';
import Card from 'Card';
function handleClick(){
console.log('in handle');
}
const viewcard = () => {
return (
<p onClick={() => handleClick()}/>
Some text in paragraph
</p>
);
}
export default viewcard;
The Card component displays some text on the screen.
What I am trying to achieve is when a user clicks on that text, I want to show the modal.
Currently If I render the modal inside viewcard, by calling it, It will show a button based on this line of logic
<Button variant="success" onClick={() => this.handleModalShowHide()}>
Write a review
</Button>
I want to remove the button and have the same behaviour happen when the user clicks on the text in viewcard.js
ViewCard component:-
import React, {useState} from 'react';
import ViewModal from './ViewModal';
import Card from 'Card';
const ViewCard = () => {
const [showModal, setShowModal] = useState(false);
function handleClick(){
setShowModal(!showModal)
}
return (
<Card onClick={() => handleClick()}/>
{showModal && <ViewModal hideBtn={true} showModal={true} />}
);
}
export default ViewCard;
ViewModal Component:
import React from 'react'
import { Button, Modal } from 'react-bootstrap';
import './Modal.css';
class ViewModal extends React.Component {
constructor() {
super();
this.state = {
showHide: this.props.showModal ? true : false
}
}
handleModalShowHide() {
this.setState({ showHide: !this.state.showHide })
}
render() {
return (
<div>
{this.props.hideBtn ? null : <Button variant="success" onClick={() => this.handleModalShowHide()}>
Write a review
</Button>}
<Modal show={this.state.showHide}>
<Modal.Header closeButton onClick={() => this.handleModalShowHide()}>
<Modal.Title>Add your review</Modal.Title>
</Modal.Header>
<Modal.Body>
ModalBody
</Modal.Body>
<Modal.Footer>
<Button variant="outline-secondary" onClick={() => this.handleModalShowHide()}>
Close
</Button>
<Button variant="outline-success" onClick={() => this.handleModalShowHide()}>
Save Review
</Button>
</Modal.Footer>
</Modal>
</div>
)
}
}
export default ViewModal;
But you should always create a separate modal component.

React direct to a "thank you" page after submitting a form

I made a simple form and after I hit the submit button of the form, I want it to automatically redirect to a "thankyou" page I have set up. Can anyone help me solve this.
Currently, this is how I think it might work, but it keeps popping up errors.
Thank you very much.
const handleSubmit = event => {
alert("Thank you for registering ");
event.preventDefault();
event.stopPropagation();
handleClose();
redirectToPage();
};
const redirectToPage = () => redirect(true);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
if (redirect) {
return <Link to="/thankyou" />
}
return (
<>
<div className="StudentForm">
<Modal show={show} onHide={handleClose} animation={true}>
<Modal.Header closeButton>
<Modal.Title>Student Information</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form onSubmit={handleSubmit}>
<Row>
<Col>
<Form.Group controlId="std_name">
<Form.Control required type="text" id="std_name" name="std_name"
placeholder="Student Name" />
</Form.Group>
</Col>
</Row>
<Button variant="secondary" onClick={event => window.location.href='/home'}>Cancel</Button>
<Button variant="primary" type="submit">
Submit
</Button>
</Form>
</Modal.Body>
</Modal>
</div>
</>
);
you wanna use Redirect from react-router-dom and i would suggest using useState hook to maintain a state variable which would determine when to redirect and in redirectToPage you would just set it to true
import React,{Fragment,useState} from "react";
import { Redirect } from "react-router-dom";
const [redirect, setRedirect] = useState(false);
const redirectToPage = () => setRedirect(true) ;
return (
{redirect && (
<Fragment>
<Redirect to='/thankyou' />
</Fragment>
)}
<div className="StudentForm">
// Rest of Code
);

React: Invalid value for prop `savehere` on <div> tag. Either remove it from the element, or pass a string or number value to keep it in the DOM

I'm calling a parent method from child component using props and I'm getting this error:
The way I'm passing props to the AddGuest child component is like this:
import React from 'react';
import globalService from '../services/globalService';
import '../styles/chairqueue.css';
import {buttonText,endPoint} from '../constants/global.constants';
import Modal from 'react-bootstrap/Modal'
import ModalDialog from 'react-bootstrap/ModalDialog'
import ModalHeader from 'react-bootstrap/ModalHeader'
import ModalTitle from 'react-bootstrap/ModalTitle'
import ModalBody from 'react-bootstrap/ModalBody'
import ModalFooter from 'react-bootstrap/ModalFooter'
import Button from 'react-bootstrap/Button'
import { useState, useEffect } from 'react';
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import AddGuest from './addGuest'
class CreateMeeting extends React.Component {
constructor(props){
super(props)
this.state={
guestModalShow:false
}
}
as=(a)=>{
console.log('saasa')
this.setState({guestModalShow:a});
}
asd=(a)=>{
console.log(a) // works perfectly
}
render(){
return (
<Modal
{...this.props}
size="lg"
aria-labelledby="contained-modal-title-vcenter"
centered
>
<Modal.Header >
<label >Cancel</label>
<Modal.Title id="contained-modal-title-vcenter">
New Meeting
</Modal.Title>
<label>Create</label>
</Modal.Header>
<Modal.Body>
<h4><input type="text" className="form-control" placeholder="Meeting title"/></h4>
{/* <DatePicker className="form-control"
selected={startDate}
onChange={setStartDate}
/> */}
<label variant="primary" onClick={()=>this.as(true)}>
Add Guest
</label>
</Modal.Body>
<Modal.Footer>
<Button onClick={this.props.onHide}>Close</Button>
</Modal.Footer>
<AddGuest
show={this.state.guestModalShow}
savehere={(a)=>this.asd(a)}
onHide={() => this.as(false)}
/>
</Modal>
)
}
}
export default CreateMeeting;
My child component is implemented as:
import React from 'react';
import '../styles/chairqueue.css';
import {buttonText,endPoint} from '../constants/global.constants';
import Modal from 'react-bootstrap/Modal'
import ModalDialog from 'react-bootstrap/ModalDialog'
import ModalHeader from 'react-bootstrap/ModalHeader'
import ModalTitle from 'react-bootstrap/ModalTitle'
import ModalBody from 'react-bootstrap/ModalBody'
import ModalFooter from 'react-bootstrap/ModalFooter'
import Button from 'react-bootstrap/Button'
import { useState, useEffect } from 'react';
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
class AddGuest extends React.Component {
constructor(props){
super(props)
this.state={
startDate:new Date(),
formControls: {
email: '',
name: ''
},
}
}
changeHandler = event => {
const name = event.target.name;
const value = event.target.value;
this.setState({
formControls: {
...this.state.formControls,
[name]:
value
}
});
}
sendData = () => {
console.log('hhhh--')
this.props.savehere("Hey Popsie, How’s it going?");
}
render(){
return (
<Modal {...this.props} >
<Modal.Header closeButton>
<Modal.Title>Add Guest</Modal.Title>
</Modal.Header>
<Modal.Body>
<h4><input type="text" name="name" value={this.state.formControls.name}
onChange={this.changeHandler} required className="form-control" placeholder="Guest Name"/></h4>
<h4><input type="text" className="form-control" name="email" value={this.state.formControls.email}
onChange={this.changeHandler} required placeholder="Guest Email"/></h4>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={this.props.onHide}>
Close
</Button>
<Button variant="primary" onClick={()=>this.sendData()}>
Save
</Button>
</Modal.Footer>
</Modal>
);
}
}
export default AddGuest;
Im using react boostrap modals and calling another modal. What could be problem causing this error?
The problem here is that a non-stardard input prop savehere of your <AddGuest/> component which is being directly spread into the <Modal/> component when AddGuest is rendered:
render(){
return (
<Modal {...this.props} > {/*<-- This is problematic, as all props
of AddGuest are spread into Modal
including those not supported by
Modal such as "savehere"*/}
...
</Modal>)
}
Rather than spread the props directly to Modal, consider only applying the props that the Modal component supports. A simple solution for your case would be to explictly specify the show and onHide props passed to AddGuest:
render(){
return (
<Modal show={this.props.show} onHide={this.props.onHide}>
...
</Modal>)
}
Hope that helps!
I also met this problem and solved it with Object Destructuring
const {savehere, ...others} = props
return (
<Modal ...others/>
)
use variable savehere to store the callback function, and use variable other to store the propertys which will be passed to <Modal/>
In general this is caused by accidentally adding a non-dom property to a dom element (in this case a div).
If you checkout the spec for div, I suspect that you will not find 'savehere' defined. As such, 'savehere' will have no effect on the div element.
You can see what attributes you can pass to such elements via the mdn pages (linked below but you can just go there and search for them).
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div
https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes
As such, it could be argued that this is a mistake on the part of react bootstrap's Modal component which appears to be passing on all props to ModalDialog and somewhere down the line that passes your prop to a .
On you side you can 'fix' this by only passing the props that you wish to give and by reformulating your approach.
The general, and quite clean, practice that seems to be ubiquitous in the React world (pushed by linter defaults, used in example code in docs and guides etc) would be to:
refactor this quite simple set of components into functions
destructure your props at the component definition
pass only the variables you need
keep your handlers in the parent
So the parent component would look sth like:
const CreateMeeting = ({modalProp1, modalProps2, whatever}) => {
const [guestModalShow, setGuestModalShow] = useState(false)
const handleSaveClick = () => {
console.log('clicked')
}
const closeModal = () => setGuestModalShow(false)
return (
<Modal
modalProp1={modalProp1}
modalProps2={modalProp2}
size="lg"
aria-labelledby="contained-modal-title-vcenter"
centered
>
<Modal.Header >
<label >Cancel</label>
<Modal.Title id="contained-modal-title-vcenter">
New Meeting
</Modal.Title>
<label>Create</label>
</Modal.Header>
<Modal.Body>
<label variant="primary" onClick={()=>this.as(true)}>
Add Guest
</label>
</Modal.Body>
<Modal.Footer>
<Button onClick={this.props.onHide}>Close</Button>
</Modal.Footer>
<AddGuest
show={guestModalShow}
savehere={handleSaveClick}
onHide={closeModal}
/>
</Modal>
)
}
}```
for react-bootstrap you might still spread out the props ( i'm using functional components, React 18.1.0 and typescript)
<CustomModal handleshow={setCustomModalShow}/> <-- from the parentcomponent with customprop (here a ReactSetAction from usestate())
custom Modal component:
CustomModal = (props:
JSX.IntrinsicAttributes &
Omit<Pick<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>,
HTMLDivElement>, "key" | keyof HTMLAttributes<HTMLDivElement>> &
{ ref?: ((instance: HTMLDivElement | null) => void) |
RefObject<HTMLDivElement> | null | undefined; },
BsPrefixProps<"div"> & ModalProps> &
BsPrefixProps<"div"> &
ModalProps &
{ children?: ReactNode; }, //all the types from a React-Bootstrap-Modal
handleshow: (e: boolean) => void // followed by the customprop and its type
) => {
return(
<Modal {...{ ...props, handleshow: handleshow }} >
...modalstuff here
<Modal/>)
}
and the error from the OP went away (it worked as intended before, yet the error popped up).
this.asd this is a function, you don’t need to wrap it in the function again.
<AddGuest
show={this.state.guestModalShow}
savehere={this.asd}
onHide={() => this.as(false)}
/>

Categories