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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With