How Can i display a Modal onSubmit Form? - javascript

I have a <Form> ( reduxForm ) Where user submits the values , as soon as the values got submitted It goes to another component showResults and that component Returns the Modal Component , Currently Modal Component is displays on the top of the App component ,
How Can I get the Modal component Popup once user have
submitted(pressed the submit button) the values and then using those
values Modal gets displayed accordingly
Form.jsx
<form onSubmit={handleSubmit}>
{allQuestions}
<div>
<button type="submit" disabled={pristine || submitting}>
Submit
</button> // Once your press this button Modal should PopuP
<button type="button" disabled={pristine || submitting} onClick={reset}>
Clear Values
</button>
</div>
</form>
showResults.jsx
<Form
formData={formData}
onSubmit={e => {
this.onSubmit(e);
}}
/>
Modal.jsx
class ShowModal extends React.Component {
state = {
open: false,
};
onOpenModal = () => {
this.setState({ open: true });
};
onCloseModal = () => {
this.setState({ open: false });
};
render() {
const { open } = this.state;
return(
<Modal open={open} onClose={this.onCloseModal}>
<h4>Total : {this.props.total} Out of 10</h4>
</Modal>
</div>)

Either store the model open state outside of the component and use a property (proper way) or ref (the anti pattern way):
<ShowModal ref={(modal) => this.modal = modal} />
and later:
this.modal.setState(show:true)
but the proper property way would be:
<ShowModal open={this.sate.showModal} />
probably since you are using redux you want to store your modal open/close state in redux state as well

Related

Adding conditional to react, redux, and API

I was wondering how I can make updates to a form using React, Redux, and API. I want to add a conditional to my component. As in if, the page is in edit mode, I would like to change the page to edit mode and if it is not, render the page as it does normally.
I want the user to be able to make updates and save those changes to the backend.
class SingleCampus extends React.Component {
componentDidMount() {
this.props.getUser(this.props.match.params.id);
}
render() {
const { User } = this.props;
const hasTest = user.tests && user.tests.length;
return (
<div>
<div className="single-user">
<h1>{user.name}</h1>
<im`enter code here`g src={user.imageUrl} alt={user.name} />
<h3>
<b>Address:</b>
{user.address}
</h3>
<b>Description:</b>
<p> {user.description}</p>
</div>
<hr />
{hasTest ? (
<React.Fragment>
<div>
{user.tests.map((test) => {
return (
<span key={test.id}>
<Link to={`/test/${test.id}`}>
<h3>
{test.grade}
</h3>
</Link>
</span>
);
})}
</div>
</React.Fragment>
) : (
<h2>There are no test for this user!</h2>
)}
</div>
);
}
}
const mapState = (state) => ({
user: state.user,
});
const mapDispatch = (dispatch) => ({
getUser: (id) => {
dispatch(fetchSingleUser(id));
},
});
`
a simple way to do so is to add a variable to your state, (no matter local state or Redux state)
e.g.
// I suppose this is your Redux state used to map state to props?
const mapState = (state) => ({
user: state.user,
isDisabled: state.isDisabled,
});
change your text value in the component to text box, you may need to use some UI package such as Material UI.
Then, make it disabled depends on your isDisabled state value
also, on value change, you need to implement to dispatch the updated value.
import TextField from '#material-ui/core/TextField';
......
<b>Description:</b>
<p> {user.description}</p>
<TextField
value={user.description}
onChange={handleChange} // update description value and dispatch the user object
InputProps={{
readOnly: props.isDisabled,
}}
/>
finally, add a button to change the isDisabled value if in read only mode, process save in edit mode
import Button from '#material-ui/core/Button';
......
<Button
variant="contained"
onClick={handleEditSave} // handle edit/save logic
>{props.isDisabled ? `Edit` : `Save`}
</Button>

React handling Form Components

Alright I am trying to submit two different forms as independent components in another page
component where I only have one button to submit the data of both forms.
So I am struggling to have a shared state in the page component and I need to pass the whole state of each form component to my page component on submit.
Can anyone recommend a best practice for my use case ?
render() {
return (
<div as={Row} className="container" style={formStyle}>
<Col>
<Form onSubmit={this.submitData}>
<TripForm />
<PostForm heading="add your first blog entry" />
<Button variant="dark" type="submit">
Summing up
</Button>
</Form>
</Col>
</div>
);
}
define your state in the parent component and pass it down in props
class PageComponent = {
state = { } //define your state here
handleChange = () => {} // define a function that handles changing state
submitData = () => {
// in here you can access this.state and then submit form data with that state
}
render() {
return (
<div as={Row} className="container" style={formStyle}>
<Col>
<Form onSubmit={this.submitData}>
<TripForm handleChange={handleChange} someState={someState} />
<PostForm heading="add your first blog entry" handleChange={handleChange} someState={someState}/>
<Button variant="dark" type="submit">
Summing up
</Button>
</Form>
</Col>
</div>
);
}
}
I've also defined someState which you can pass down as props to the child/form components. once you set state in there with handleChange it will set state in the parent component and you can submitData with that state

How to pass state value from form to its child modal?

I am new to React and I'm not sure what would be the best approach to take.
I have a modal component to be displayed once the user fills out the values inside the form and click on Preview Voucher to print those values inside the modal.
I tried this code and below I have the Preview Voucher component with a constructor and events.
// PreviewVoucher.js
class PreviewVoucher extends React.Component {
constructor(props) {
super(props);
this.state = {
voucherNumber: "0",
//
addModalShow: false
};
this.handleInputChange = this.handleInputChange.bind(this);
this.handleSelectChange = this.handleSelectChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleInputChange(e) {
const target = e.target;
const value = target.type === "checkbox" ? target.checked : target.value;
const inputName = target.name;
this.setState({
[inputName]: value
});
}
handleSelectChange(e) {
this.setState({ labelSize: e.target.value });
}
handleSubmit(e) {
e.preventDefault();
}
}
And I want to render this form on the page that has a child component Modal Voucher
// PreviewVoucher.js
render() {
let addModalClose = () => this.setState({ addModalShow: false });
return (
<form onSubmit={this.handleSubmit}>
<div>
<p>Number of vouchers to create:</p>
<input
min="0"
type="number"
name="voucherNumber"
value={this.state.voucherNumber}
onChange={this.handleInputChange}
/>
</div>
<div>
<h4>Message:</h4>
<p>Some message</p>
<ButtonToolbar>
<Button onClick={() => this.setState({ addModalShow: true })}>
Preview Voucher
</Button>
<ModalVoucher
show={this.state.addModalShow}
onHide={addModalClose}
/>
</ButtonToolbar>
</div>
<input type="submit" value="Create voucher" />
</form>
);
}
And this is the child component - Modal Voucher that would contain some text and would like to display the dynamic values from the Preview Voucher component inside the < Modal Body >.
// ModalVoucher.js
class ModalVoucher extends React.Component {
render() {
return (
<Modal
{...this.props}
size="lg"
aria-labelledby="contained-modal-title-vcenter"
centered
>
<Modal.Header closeButton>
<Modal.Title id="contained-modal-title-vcenter">
Voucher preview
</Modal.Title>
</Modal.Header>
<Modal.Body>
<div>{/* update code here */}</div>
</Modal.Body>
<Modal.Footer>
<Button onClick={this.props.onHide}>Close</Button>
</Modal.Footer>
</Modal>
);
}
}
How to render parent's state within child component
You will need to pass the state value from PreviewVoucher into its child ModalVoucher as a prop.
// PreviewVoucher.js
render() {
<ModalVoucher
show={this.state.addModalShow}
onHide={addModalClose}
voucherNumber={this.state.voucherNumber}
/>
}
Then use it inside of ModalVouchers render method.
// ModalVoucher.js
render() {
<Modal.Body>
<div>{this.props.voucherNumber}</div>
</Modal.Body>
}
I put together this sandbox showing this in action.
Other suggestions
After making this change, you might see this error in the console
Warning: React does not recognize the `voucherNumber` prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase `vouchernumber` instead. If you accidentally passed it from a parent component, remove it from the DOM element.
This occurs because you are passing all the props directly into the Modal, which
the underlying library passes to a DOM element.
<Modal
{...this.props}
Because of this, I think it is usually a bad idea to directly forward all props
and I prefer to pass specific props instead.
<Modal
show={this.props.show}
onHide={this.props.onHide}

I want to add a loading screen until the other component gets loaded after submitting the form in react

I am trying to learn react. I am submitting a form. I have used handleSubmit. I want to add a loading screen until the other component gets loaded after submitting the form. How I can do that?
I have a Detail component and a Summary component.On submit it will go in either of the components.
In App.js,
handleSubmit(evt) {
let prevState = this.initialState
this.setState( prevState=> ({
disabled: !prevState,
}),
);
if (this.state.checkIds && this.state.checkIds.length > 0) {
redirect = redirect.concat(`checkids=${this.state.checkIds}&`)
}
return this.props.history.push(redirect)
}
onClick = () => {
this.setState(this.initialState)
this.props.history.push("/");
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<label>
Project ID:
<input type="text" value={this.state.projectId} name="projectId" onChange={this.handleChange}/>
</label>
<button type="button" class ="button" value="detail" onClick={this.handleSubmit}>Detail</button>
<button type="button" class ="button" value="summary" onClick={this.handleSubmit}>Summary</button>
<button type="button" class ="button" value="back" disabled={this.state.disabled} onClick={this.onClick}>Back</button>
</form>
</div>
)
}
I want a loading page which will appear on clicking the button. It will be there until one of the components gets loaded
Its not clear from your example code, but your state should have a isLoading and hasLoaded parameter. When you handle the submit, setState isLoading: true. When the loading is done, setState isLoading: false and hasLoaded: true. Then in your render you can do something like this:
render() {
const {isLoading, hasLoaded} = this.state;
return isLoading ? <Loader /> : hasLoaded ? <LoadedComponent /> : <FormWithButtonComponent />
}
First of all, on your state, create a property named loading: false. Then create a component named Spinner which includes 2 files, Spinner.js and Spinner.css.
For the css, visit this site and choose any spinner you want. Copy the CSS codes into your Spinner.css. Make sure change the .load class name with .Loader.
Then in your Spinner.js component, put this code:
import React from 'react';
import classes from './Spinner.css';
const spinner = () => (
<div className={classes.Loader}>Loading...</div>
);
export default spinner;
After created your spinner component, Create an if statement in your render() to the component you wanna add spinner and in your handleSubmit function, handle the loading like this:
handleSubmit() {
this.setState( {loading: true} );
...
// after you completed your goal, add this
this.setState( {loading: false} );
}
let button =<button type="button" class ="button" value="detail" onClick={this.handleSubmit}>Detail</button>
if (this.state.loading) {
button = <Spinner />
}

Component props not updating in shallow render

I have a payment component and when I click a button, it should update the component state isOpen to true. This works fine in practice but when trying test it via enzyme, it wont update the prop.
The component looks like this:
class CashPayment extends Component {
state = {
isOpen: false
}
toggleModal = () => {
this.setState({ isOpen: true })
}
render() {
return (
<Mutation>
{() => (
<Fragment>
<Button
id="cash-payment-button"
onClick={this.toggleModal}
/>
<Modal
id="confirm-payment-modal"
isOpen={isOpen}
>
...
</Modal>
</Fragment>
)}
</Mutation>
)
}
}
So clicking #cash-payment-button should toggle the state isOpen which should open the modal.
In my test, I want to check the prop of my modal isOpen is set to true. But for some reason, the prop doesn't update in the test. However if I console log in my toggleIsOpen function, I can see the function gets called and the state updates.
My test is as so:
describe("Click Pay button", () => {
it("Should open confirm modal", () => {
Component = shallowWithIntl(
<CashPayment bookingData={bookingData} refetchBooking={refetchBooking} />
)
.dive()
.dive()
const button = Component.find("#cash-payment-button")
.props()
.onClick()
expect(Component.find("#confirm-payment-modal").prop("isOpen")).toEqual(true)
})
})
and the results are:
CashPayment › Click Pay button › Should open confirm modal
expect(received).toEqual(expected)
Expected value to equal:
true
Received:
false
Why does the modal component props not update?

Categories