React Bootstrap Modal not working on submit Button - javascript

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

Related

how to show react bootstrap modal inside the function

I am using react bootstrap modal popup. when user submit form, I need to modal show popup,
This is my modal (SaveConfirmationModal )
import { Button, Modal} from "react-bootstrap";
function SaveConfirmationModal(props) {
return (
<div>
<Modal {...props} size="lg">
<Modal.Header closeButton>
<Modal.Title id="contained-modal-title-vcenter">
do u want to save ?
</Modal.Title>
</Modal.Header>
<Modal.Body>
<button>YEs </button>
<button>No</button>
</Modal.Body>
</Modal>
</div>
);
}
export default SaveConfirmationModal;
this is my invoice page save function. I imported my modal in to the invoice page.
import SaveConfirmationModal from "components/createinvoice/SaveConfirmationModal";
const loadPopup= (data) => {
showmodal;
if(yes){
saveForm();
}
else{
close modal
}
}
const saveForm= (data){
my save function
}
my save button in the invoice page
<button onClick={loadPopup}> Save </button>
This is the very little sample to demonstrate my issue. If you can please help me to show this confirmation box. thanks
In the component where you use your SaveConfirmationModal, you can use state Hooks, like this:
import React, {useState} from 'react';
...
const [showModal, setShowModal] = useState(false);
const loadPopup = () => {
setShowModal(true);
};
And you need to change the state to false when the modal is dismissed:
<SaveConfirmationModal show={showModal} onHide={() => setShowModal(false)}
You can call a function from a prop on button click like below.
import { Button, Modal} from "react-bootstrap";
function SaveConfirmationModal(props) {
return (
<div>
<Modal {...props} size="lg">
<Modal.Header closeButton>
<Modal.Title id="contained-modal-title-vcenter">
do u want to save ?
</Modal.Title>
</Modal.Header>
<Modal.Body>
<button onClick={props.onYes}>YEs </button>
<button onClick={props.onNo}>No</button>
</Modal.Body>
</Modal>
</div>
);
}
export default SaveConfirmationModal;
Then in your invoice page create a state for showing a modal and pass the props like below.
import { useState } from 'react'
import SaveConfirmationModal from "components/createinvoice/SaveConfirmationModal";
const InvoicePage = () => {
const [showModal, setShowModal] = useState(false);
const saveForm = (data) {
// my save function
}
return (
<>
<button onClick={() => setShowModal(true)}> Save </button>
<SaveConfirmationModal show={showModal} onYes={() => saveForm(data)} onNow={() => setShowModal(false)} />
</>
)
}

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

TypeScript React Invalid Hook Call Error ("Error: Invalid hook call.")

I tried asking a question earlier but realized it was a bit all over the place so no one could really understand it properly. So here's a more clarified attempt.
I am currently working on a CRUD web project that allows the user to edit, view and create more users which is then displayed on a table.
I have been using react-bootstrap's components so decided to use the Modal component provided. (https://react-bootstrap.netlify.com/components/modal/#modals-live)
It was successfully working without any errors when I just called and used the component within App.tsx as follows:
const App: React.FC = () => {
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
return (
<div className="App">
<NavBar/>
<Jumbotron fluid className="userJumbotron">
<Container>
<h1>Manage Users</h1>
<Button variant="outline-dark" onClick={handleShow}>Add new user</Button>
<Modal show={show} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>Add User</Modal.Title>
</Modal.Header>
<Modal.Body><NewUserForm/></Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
<Button variant="primary" onClick={handleClose}>
Save Changes
</Button>
</Modal.Footer>
</Modal>
But I think realized that I'll need more than 1 modal component for my program and decided to make the modal component section into my own component that I can reuse as many times as I want and customize as I want within the App.tsx
So I decided to make a NewModal.tsx component that has the bootstrap modal component and button pre-made meaning I'd only have to call one line () rather than a whole chunk. the NewModal.tsx code is as follows:
export default class NewModal extends Component<any> {
constructor (props: any){
super(props)
this.state={
show:false
}
}
render() {
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
return (
<div>
<h1>Manage Users</h1>
<Button variant="outline-dark" onClick={handleShow}>Add new user</Button>
<Modal show={show} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>Add User</Modal.Title>
</Modal.Header>
<Modal.Body><NewUserForm/></Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
<Button variant="primary" onClick={handleClose}>
Save Changes
</Button>
</Modal.Footer>
</Modal>
</div>
);
}
}
I am getting the following error from this code.
What is the cause for this error?
You can't use hooks inside class components, you need to change it to be a function based component, which can look something like this:
const NewModal = () => {
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
return (
<div>
<h1>Manage Users</h1>
<Button variant="outline-dark" onClick={handleShow}>
Add new user
</Button>
<Modal show={show} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>Add User</Modal.Title>
</Modal.Header>
<Modal.Body>
<NewUserForm />
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
<Button variant="primary" onClick={handleClose}>
Save Changes
</Button>
</Modal.Footer>
</Modal>
</div>
);
}
export default NewModal;

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

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??

How to create this react modal the right way?

I have been working on my first Meteor application and am a bit stuck. I want to create my code following the latest guidelines (ES6 and React 15) but I am confused with all the recent changes in Javascript.
I want to add a Bootstrap Modal in my current comments list but can't seem to figure out how to add my content to the modal using the right up to date syntax.
Here is my current code:
In comment.js:
import React from 'react';
import { Row, Col, ListGroupItem, FormControl, Button } from 'react-bootstrap';
import { Bert } from 'meteor/themeteorchef:bert';
import { CommentsModal } from './comments-modal'
export const Comment = ({ comment }) => (
<ListGroupItem key={ comment._id }>
<Row>
<Col xs={ 8 } sm={ 10 }>
<FormControl
type="text"
defaultValue={ comment.title }
/>
</Col>
<Col xs={ 4 } sm={ 2 }>
<Button
bsStyle="danger"
className="btn-block">
Remove Comment
</Button>
</Col>
</Row>
<CommentsModal/>
</ListGroupItem>
);
In Comments-modal.js:
import React, { Component } from 'react';
import { Modal, Button, Tooltip } from 'react-bootstrap';
export class CommentsModal extends Component {
constructor(props) {
super(props);
this.state = {
showModal: false,
};
this.close = this.close.bind(this);
this.open = this.open.bind(this);
}
close() {
this.setState({ showModal: false });
}
open() {
this.setState({ showModal: true });
}
render() {
return (
<div>
<Button
bsStyle="primary"
bsSize="large"
onClick={this.open}
>
</Button>
<Modal show={this.state.showModal} onHide={this.close}>
<Modal.Header closeButton>
<Modal.Title >Modal heading</Modal.Title>
</Modal.Header>
<Modal.Body>
<h4>Text in a modal</h4>
</Modal.Body>
<Modal.Footer>
<Button onClick={this.close}>Close</Button>
</Modal.Footer>
</Modal>
</div>
);
}
}
And last comments-list.js:
import React from 'react';
import { ListGroup, Alert } from 'react-bootstrap';
import { Comment } from './comment';
export const CommentsList = ({ comments }) => (
comments.length > 0 ? <ListGroup className="comments-list">
{comments.map((com) => (
<Comment key={ com._id } comment={ com } />
))}
</ListGroup> :
<Alert bsStyle="warning">No comments yet. Please add some!</Alert>
);
CommentsList.propTypes = {
comments: React.PropTypes.array,
};
I manage to get the Modal to show up and work but when I want to display data in it, I can't get it to work. What is the best way to combine both these into one?
Pass the data in props to the CommentsModal and render it as you would normally do.
I try to keep local state out of component when using redux if possible, so to answer your question on making it stateless, I would take the following steps:
Remove the button that opens the modal from the modal.js itself
Remove the actual modal from the modal.js, just put the modal content inside of there.
Change the open modal button to hook into an action creator that sets a prop to open the modal and passes it's content (also set one to close it)
So that looks something like this
<ListGroupItem key={ comment._id }>
<Row>
<Col xs={ 8 } sm={ 10 }>
<FormControl
type="text"
defaultValue={ comment.title }
/>
</Col>
<Col xs={ 4 } sm={ 2 }>
<Button
bsStyle="danger"
className="btn-block">
Remove Comment
</Button>
</Col>
</Row>
<!-- Here is where it changes, -->
<Button
bsStyle="primary"
bsSize="large"
onClick={this.props.openModal(comment)}
>
</Button>
<Modal show={this.props.commentModal} onHide={this.props.closeModal}>
<CommentsModal content={this.props.commentModal} />
</Modal>
Keep in mind, these naming conventions are just for examples sake : use whatever works best for you.
So what happens here is when you click that button you fire this.props.openModal (an action) which does something like this in the reducers -
case actions.OPEN_COMMENT_MODAL:
return state.set('commentModal', action.content);
the close buttons fire the onHide which is linked to the this.props.closeModal action which just does:
case actions.OPEN_COMMENT_MODAL:
return state.set('commentModal', undefined);
So what this allows you to do is have just 1 modal instance and you pass the current comment to it with that button click and open it. The show just checks the truthy value, so you set it back to undefined and it will hide itself.
Then I am passing the prop of content to the modal, so you can then use it inside the modal itself. Again, change the names to whatever works best for you.

Categories