I am sending a POST request to an endpoint in react using axios and if my returned response is successfull I am setting some state.
Here is my code:
axios.post('/some/endpoint', {mydata})
.then(res => {
console.log(res.data);
if(res.data.success)
{
setMsg('successful');
setActive('alert alert-success fade-out');
}
else
{
setMsg('Oops! An error occured!');
setActive('alert alert-danger');
}
})
After the first API request, everything is fine, I get the message and it fades out, Although If I try to send another request, It doesn't appear again and start to fade out, Why isn't the setMsg and setActive calls firing?
Heres the render:
return (
<>
<Modal open={open} onClose={onCloseModal} center closeIcon={closeIcon} modalId="response-modal">
<div className="qr-modal-header-stock">
<h5>Enter fulfillment stock</h5>
<p>{title}</p>
<p>Fulfilment Center: {fulfilmentCenterName}</p>
<p>Existing stock: {stock}</p>
<p className={active} style={{opacity:0}}>{msg}</p> <-- this appears firstly but not the second time when I submit the form, why?
<form onSubmit={handleSubmit}>
<input type="hidden" name="ean" value={data} />
<input type="hidden" name="product_stock" value={newStock} />
<input type="number" class="form-control" onChange={e => setNewStock(parseInt(e.target.value) + parseInt(stock))}/> <br />
<input type="submit" class="btn btn-primary form-control" id="submit-fulfilment-center" value="Save"/>
</form>
<br />
<p>New stock: {isNaN(newStock) ? 0 : newStock}</p>
<button className="btn btn-primary" onClick={onCloseModal}>Scan another ean</button>
</div>
</Modal>
</ >
);
You should use "useState" hook and watch "Msg" and "Active" states for changes.
useState(()=>{
// do somthing here
},[Msg,Active])
using this will re-render the page every time the value of "Msg" or "Active" changes.
Notice : Do Not set states and watch them in the same useState hook , this will will cause an infinite rendring loop
Related
I'm trying to submit a form with a form action. However the submit takes quite a long time, so I'm trying to show a loading message while the form is submitting, telling the user to wait on the screen and they'll be redirected afterwards. The problem is, when I show the loading screen, the form submit no longer works. I've narrowed it down due to the fact that the submit button that triggered the event no longer exists, thus it won't submit. Is there a way to show the loading screen and ensure the submit action goes through?
handleSubmit = () => {
...
this.setState({isLoading: true});
...
this.formRef.current.submit();
}
<form ref={this.formRef} action="https://www.google.com" method="post">
{isLoading ? (
this.renderLoading()
) : (
<>
<input type="text">input</input>
<button type="submit" onClick={this.handleSubmit}>button<button>
</>
</form>
I have tried the below solution and it works successfully, however, I don't want the button to be shown in the loading screen.
handleSubmit = () => {
...
this.setState({isLoading: true});
...
this.formRef.current.submit();
}
<form ref={this.formRef} action="https://www.google.com" method="post">
{isLoading ? (
this.renderLoading()
) : (
<>
<input type="text">input</input>
</>
<button type="submit" onClick={this.handleSubmit}>button<button>
</form>
Is there a way to make this work without showing the button in the loading screen?
Hide the controls rather than killing them:
handleSubmit = () => {
...
this.setState({isLoading: true});
...
this.formRef.current.submit();
}
<form ref={this.formRef} action="https://www.google.com" method="post">
<>
{ isLoading && this.renderLoading() }
<input type="text" className={isLoading ? 'hidden' : ''}>input</input>
<button type="submit" onClick={this.handleSubmit} className={isLoading ? 'hidden' : ''}>button<button>
</>
</form>
css for hidden class is display: none
I have a stateless react component that is a little pop up. It takes some data from the user, and passes that back to its parent, where it executes the work.
What is the best way for this component to have a handleSubmit() function, that takes the user input, and sends it back to the parent?
import React, { Component } from "react";
import "../../../node_modules/bulma/css/bulma.css";
const Transfer = (props, token, web3) => {
return (
<div className="modal is-active">
<div className="modal-background" onClick={props.onClick} />
<div className="modal-card">
<section className="modal-card-body">
<div className="content">
<h1 className="title"> Transfer Tokens </h1>
<p className="has-text-danger">
Requires that you are the owner of the token you are transferring
</p>
<p className="subtitle">How it works</p>
<p className="">
Enter the ID of the token you want to transfer, the address to
whom its going to, and thats it!
</p>
//problem area
<form onSubmit={props.onClickSubmit}>
<label htmlFor="text">Address to recieve token</label>
<input
name="Address"
className="input is-info "
required="true"
/>
<label htmlFor="number">Token ID</label>
<input
className="input is-info"
name="Token ID"
type="number"
required="true"
/>
<a className="button is-pulled-right">Submit</a>
</form>
</div>
</section>
<footer className="modal-card-foot is-clearfix">
<a className="button" onClick={props.onClick}>
Cancel
</a>
</footer>
</div>
</div>
);
};
export default Transfer;
I pass in as a prop, onClickSubmit, in my parent component, and that contains the logic for what I'm trying to do.
Very new to stateless react components
It will be difficult to accomplish what you want with a stateless component since you cannot use either refs or state in a stateless component. You can think of a stateless component as a pure function that returns a piece of UI depending on the props you give it.
You could instead use a stateful component and e.g. store the input values in state and call the onClickSubmit prop function with this state when the user submits the form.
If you want to build stateless forms component, I send you a lib that I'm working on:
react-distributed-forms
This allow you to build your Transfer Component this way, (pay attention to use Input instead of input and Button instead of button):
import React, { Component } from "react";
import "../../../node_modules/bulma/css/bulma.css";
import { Input, Button } from "react-distributed-forms";
const Transfer = (props, token, web3) => {
return (
<div className="modal is-active">
<div className="myForm">
<label htmlFor="text">Address to receive token</label>
<Input name="Address" className="input is-info " required="true" />
<label htmlFor="number">Token ID</label>
<Input
className="input is-info"
name="Token ID"
type="number"
required="true"
/>
<Button name="submit" className="button is-pulled-right">
Cancel
</Button>
</div>
</div>
);
};
export default Transfer;
And then in your parent Component, wherever it is in the hierarchy, you simply do:
<Form onSubmit={({ name }) => { console.log(name); }} onFieldChange={({ name, value} ) => { console.log(name, value); }}>
...whatever
<Transfer />
...whatever
</Form>
onFieldChange will receive every input change.
onSubmit will receive the attribute "name" on the Button when you click it.
react-distributed-forms use React context API, so you don't have to pass directly props, it just works. Is built for really dynamic forms...
I'd like to generate some HTML to show sucessfull form submission. I can't seem to do it within the handleSubmit Method.
class BookingForm extends Component{
...
handleChange(event) {
const target = event.target;
const value = target.value;
const name = target.name;
console.log(name + ' '+value);
this.setState({
[name]: value
});
}
Submit method that I'd like to render html:
handleSubmit(event) {
console.log(this.state.lessonTime)
event.preventDefault();
this.setState({'success':true})
return(
<h1>Success</h1>
);
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<TimeList defaultTime={this.state.defaultTime}
handleChange={this.handleChange}/>
<br/>
<DateList defaultDate={this.state.defaultDate}
handleChange={this.handleChange}/>
<br/>
<NumberOfLessons defaultNOL={this.state.defaultLessons}
handleChange={this.handleChange}/>
<br/>
<input type="submit" value="Book Lesson" />
</form>
<br/>
</div>
);
}
}
Any ideas on how I can get the success heading to show once submit has been clicked on.
Thanks
I think a better way to handle this is to use state to control the rendering of "success" heading. You can add the following line of code to the place you want to add the header:
{this.state.success && <div> Successful </div> }
I think the reason the html tag returned by handleSubmit in your function doesn't show up is because although it returns the tag, it doesn't know where to put it. If you want to make it work, you'll need to use methods like createElement and appendChild but that's not the way react should work.
If you want your <h1> element to render instead of form on successful completion do this in your render function:
render() {
return (
<div>
{this.state.success?(
<h1>Success</h1>
):(
<form onSubmit={this.handleSubmit}>
<TimeList defaultTime={this.state.defaultTime}
handleChange={this.handleChange}/>
<br/>
<DateList defaultDate={this.state.defaultDate}
handleChange={this.handleChange}/>
<br/>
<NumberOfLessons defaultNOL={this.state.defaultLessons}
handleChange={this.handleChange}/>
<br/>
<input type="submit" value="Book Lesson" />
</form>
<br/>)}
</div>
);
}
So I have to implement a form in modal, as you can see, the button in the modal are not the buttons in the form. I created the form as a child component of the modal. How can I submit the form using the button in the parent component. I am using React Semantic-UI react as my UI framework.
I think if I can hide the button in the form and trigger it using JavaScript. I think this might be achieved via getElementById, but is there a react way of doing it?
My current Modal looks like this:
<Modal open={this.props.open} onClose={this.props.onClose} size="small" dimmer={"blurring"}>
<Modal.Header> Edit Activity {this.props.name} </Modal.Header>
<Modal.Content>
<ActivityInfoForm/>
</Modal.Content>
<Modal.Actions>
<Button negative onClick={this.props.onClose}>
Cancel
</Button>
<Button positive
content='Submit'
onClick={this.makeActivityInfoUpdateHandler(this.props.activityId)} />
</Modal.Actions>
</Modal>
My form code looks like this:
<Form>
<Form.Group widths='equal'>
<Form.Input label='Activity Name' placeholder='eg. CIS 422' />
<Form.Input label='Activity End Date' placeholder='Pick a Date' />
</Form.Group>
<Form.Group widths='equal'>
<Form.Input label='Total Capacity' placeholder='eg. 30' />
<Form.Input label='Team Capacity' placeholder='eg. 3' />
</Form.Group>
</Form>
The simplest solution would be to use HTML form Attribute
Add "id" attribute to your form: id='my-form'
<Form id='my-form'>
<Form.Group widths='equal'>
<Form.Input label='Activity Name' placeholder='eg. CIS 422' />
<Form.Input label='Activity End Date' placeholder='Pick a Date' />
</Form.Group>
<Form.Group widths='equal'>
<Form.Input label='Total Capacity' placeholder='eg. 30' />
<Form.Input label='Team Capacity' placeholder='eg. 3' />
</Form.Group>
</Form>
Add the appropriate "form" attribute to the needed button outside of the form: form='my-form'
<Button positive form='my-form' content='Submit' value='Submit' />
What does your makeActivityInfoUpdateHandler function look like?
I assume you did it by the following way, and just continue adding more code to make it work for you:
1/ Add ref to your Form, then you can access the Form in the parent (Modal):
<Modal>
<Modal.Content>
<ActivityInfoForm ref="activityForm" />
</Modal.Content>
</Modal>
2/ Then in the makeActivityInfoUpdateHandler function:
makeActivityInfoUpdateHandler = (activityId) => {
// ...
this.refs.activityForm.getWrappedInstance().submit();
// ...
}
The above code is the way you should do, please post here some more details in case this doesn't work yet!
===========
EDITED VERSION BELOW: (after discussion with the author, and we together found a good way around!):
The idea now is put the ref on a button (this button has type="submit", and it belongs to the form), then when the button outside is clicked, we just need to call the "click()" function of the ref button [which is a smart thinking from the author himself]
(Actually, component from semantic-ui is a modified and improved version, no longer the standard form, so my previous way above may not work when it tries to submit the form, however, the below way will work)
The code will now look like:
1/ Add ref to the button on the form:
<Form onSubmit={ this.handleSubmit} >
<button style={{}} type='submit' ref={ (button) => { this.activityFormButton = button } } >Submit</button>
</Form>
2/ Then in the makeActivityInfoUpdateHandler function, trigger click() of the above button:
makeActivityInfoUpdateHandler = (activityId) => {
// ...
this.activityFormButton.click();
// ...
}
The selected answer was useful. But the method in it doesn't seem to work any longer. Here's how I went about it.
You can give a ref to the child component when it is being created.
<ChildComponent ref={this.childComponent}/>
And use it in the button's onClick method. (This is the code for the button)
<Button variant= "light" onClick={this.onClick}>
Submit
</Button>
(This is the onClick method)
onClick = (event) => {
this.childComponent.current.handleSubmit(event);
}
I'm calling a method in the child component called handleSubmit. It can look like this.
handleSubmit = (event)=> {
event.preventDefault();
//Your code here. For example,
alert("Form submitted");
}
I have been trying to develop a dashboard form similiar to airbnb listing form for understanding more deeply about react redux but i am stuck in the middle of my project. I have a multiple form where when user clicks on continue button the user will get another form to fill and so on and if user clicks on back button the user will get form of one step back with previously filled values. I could not decide what should i do for this. Do i have to create a object in action as listingName . summary, name, email etc as empty value and update it with reducer using Object.assign() or what. Till now i could only develop like when user clicks on personal tab a form related to personal information is shown and when user clicks on basic tab, a form related to basic information is shown. I want all form data to be send to server at last submit. What should i do now ? Do i use increment and decrement action for the continue and back button and use submit action on the last form button ? Could you please provide me an idea ?
Here's my code
actions/index.js
export function selectForm(form){
return{
type: 'FORM_SELECTED',
payload: form
};
}
reducers/reducer_active_form.js
export default function(state=null, action){
let newState = Object.assign({},state);
switch(action.type){
case 'FORM_SELECTED':
return action.payload;
}
return state;
}
reducers/reducer_form_option.js
export default function(){
return[
{ option: 'Personal Information', id:1},
{ option: 'Basic Information', id:2 },
{ option: 'Description', id:3},
{ option: 'Location', id:4},
{ option: 'Amenities', id:5},
{ option: 'Gallery', id:6}
]
}
containers/form-details
class FormDetail extends Component{
renderPersonalInfo(){
return(
<div className="personalInfo">
<div className="col-md-4">
<label htmlFor='name'>Owner Name</label>
<input ref="name" type="textbox" className="form-control" id="name" placeholder="Owner name" />
</div>
<div className="col-md-4">
<label htmlFor="email">Email</label>
<input ref="email" type="email" className="form-control" id="email" placeholder="email" />
</div>
<div className="col-md-4">
<label htmlFor="phoneNumber">Phone Number</label>
<input ref="phone" type="textbox" className="form-control" id="phoneNumber" placeholder="phone number" />
</div>
<div className="buttons">
<button className="btn btn-primary">Continue</button>
</div>
</div>
);
}
renderBasicInfo(){
return(
<div>
<h3>Help Rent seekers find the right fit</h3>
<p className="subtitle">People searching on Rental Space can filter by listing basics to find a space that matches their needs.</p>
<hr/>
<div className="col-md-4 basicForm">
<label htmlFor="price">Property Type</label>
<select className="form-control" name="Property Type" ref="property">
<option value="appartment">Appartment</option>
<option value="house">House</option>
</select>
</div>
<div className="col-md-4 basicForm">
<label htmlFor="price">Price</label>
<input type="textbox" ref="price" className="form-control" id="price" placeholder="Enter Price" required />
</div>
<div className="buttons">
<button className="btn btn-primary">Back</button>
<button className="btn btn-primary">Continue</button>
</div>
</div>
);
}
renderDescription(){
return(
<div>
<h3>Tell Rent Seekers about your space</h3>
<hr/>
<div className="col-md-6">
<label htmlFor="listingName">Listing Name</label>
<input ref="name" type="textbox" className="form-control" id="listingName" placeholder="Be clear" />
</div>
<div className="col-sm-6">
<label htmlFor="summary">Summary</label>
<textarea ref="summary" className="form-control" id="summary" rows="3"></textarea>
</div>
<div className="buttons">
<button className="btn btn-primary">Back</button>
<button className="btn btn-primary">Continue</button>
</div>
</div>
);
}
renderLocation(){
return(
<div>
<h3>Help guests find your place</h3>
<p className="subtitle">will use this information to find a place that’s in the right spot.</p>
<hr/>
<div className="col-md-6">
<label htmlFor="city">City</label>
<input ref="city" type="textbox" className="form-control" id="city" placeholder="Biratnagar" />
</div>
<div className="col-md-6">
<label htmlFor="placeName">Name of Place</label>
<input ref="place" type="textbox" className="form-control" id="placeName" placeholder="Ganesh Chowk" />
</div>
<div className="buttons">
<button className="btn btn-primary">Back</button>
<button className="btn btn-primary">Continue</button>
</div>
</div>
);
}
render(){
if ( !this.props.form){
return this.renderPersonalInfo();
}
const type = this.props.form.option;
console.log('type is', type);
if ( type === 'Personal Information'){
return this.renderPersonalInfo();
}
if ( type === 'Basic Information'){
return this.renderBasicInfo();
}
if ( type === 'Description'){
return this.renderDescription();
}
if ( type === 'Location'){
return this.renderLocation();
}
}
}
function mapStateToProps(state){
return{
form: state.activeForm
};
}
export default connect(mapStateToProps)(FormDetail);
The first thing you're missing is controlled components. By giving the inputs a value property, and an onChange function, you will link the input with an external state.
Your components should have access, via react-redux, to the state and actions needed. The value of the form should be your state for that object. So you might have a state like:
location: {
listingName: '123 Main St',
summary: 'The most beautiful place!'
}
Then, you'd just pass each property to inputs. I'm assuming, in this example, that you've passed the location prop in mapStateToProps, and an actions object with all the related actions in mapDispatchToProps:
changeHandler(ev, fieldName) {
const val = ev.target.value;
this.props.actions.updateField(fieldName, val);
},
render() {
return (
<input
value={this.props.location.listingName}
onChange={(ev) => { this.changeHandler(ev, 'listingName'}}
/>
);
}
You provide it an action that can be used to update the state:
function updatefield(field, val) {
return {
type: UPDATE_FIELD,
field,
val
};
}
Then, you just merge it in, in your reducer
switch (action.type) {
case UPDATE_FIELD:
state = { ...state, [action.field]: val };
(using dynamic keys and spread operator for neatness, but it's similar to Object.assign)
All of your form state lives in the Redux store this way. When you are ready to submit that data to the server, you can either use async actions with redux-thunk, or set up some middleware to run the calls. Either way, the strategy is the same; your state lasts locally and populates all your forms, and then is sent to the server when the user submits.
I went through this pretty quick, let me know if you need me to elaborate on anything :)
As you are using react-redux you can use the redux-form. It will greatly help you with the coding as it will simplify your work load and it is also bug-free (as far as I know). In my opinion you would want to use all the libraries/frameworks provided to you as you want to be as agile as possible.
Also the redux-form has a wizard form implementation. I think that is exactly what you are looking for.
http://erikras.github.io/redux-form/#/examples/wizard?_k=yspolv
Just follow the link and you will see a very good tutorial on how to implement it. Should be a piece of cake.