I have a field Location, that is a mandatory field for yhe API, so can't be submitted blank. So I am trying to set 0 as initialValue for the field. the Location field is on the second step of the form and setting initialValues on WizardFormSecondPage removes all input previous input data from the state. How do I set the initialValue for the Location field and keep all my data put in the first step?
Location component:
export class GetLocation extends Component{
constructor(){
super();
this.getMyLocation = this.getMyLocation.bind(this);
}
getMyLocation = () => {
const location = window.navigator && window.navigator.geolocation;
if (location) {
location.getCurrentPosition((position) => {
this.props.onLocationChanged(position.coords);
},
(positionError) => {
console.log(positionError.message);
this.props.onLocationChanged("0")
},{maximumAge:0, timeout: 60000})
} else {
console.log();
this.props.onLocationChanged("0")
}
};
render(){
return(
<div>
<p>Your location is </p>
<Field
name="latitude"
component="input"
className="form-control" initialValues={0.0}
/>
<Field
name="longitude"
component="input"
className="form-control"
/><br/>
<button type="button" className="btn btn-success" onClick={this.getMyLocation.bind(this)}>Get Geolocation</button>
</div>
);
}
}
WizardFormSecondPage
let WizardFormSecondPage = props => {
const { handleSubmit, previousPage} = props;
const onLocationChanged = (loc) => {
props.change('location.latitude', loc.latitude);
props.change("location.longitude", loc.longitude);
};
return (
<form onSubmit={handleSubmit} className="form-horizontal">
<div className="panel">
<div className="form-group">
<label className="control-label col-sm-2" htmlFor="address">
Location
</label>
<div className="row">
<div className="col-sm-12">
<p className="label-lead">Own Address</p>
<FormSection name="location" component={Address}>
<Address />
</FormSection>
<p className="label-lead">Location Coordinates</p>
<FormSection name="location" component={GetLocation}>
<GetLocation onLocationChanged={onLocationChanged} />
</FormSection>
</div>
</div>
</div>
</div>
<div className="clearfix">
<button type="button" className="previous pull-left btn btn-default" onClick={previousPage}>
Previous
</button>
<button type="submit" className="next pull-right btn btn-primary">
Next
</button>
</div>
</div>
</form>
);
};
export default reduxForm({
form: "wizard", // <------ same form name
destroyOnUnmount: false, // <------ preserve form data
forceUnregisterOnUnmount: true, // <------ unregister fields on unmount
validate
})(WizardFormSecondPage);
Any help is much appreciated.
Turns out, my approach was wrong. I could set an initialValue to the entire WizardForm and it would not initialize again. So, in stead of trying to set initialize WizardFormSecondPage, I had to set values on WizardForm.js. Here's my WizardForm.js:
class WizardForm extends Component {
constructor(props) {
super(props);
this.nextPage = this.nextPage.bind(this);
this.previousPage = this.previousPage.bind(this);
this.state = {
page: 1,
};
}
nextPage() {
this.setState({ page: this.state.page + 1 });
}
previousPage() {
this.setState({ page: this.state.page - 1 });
}
onSubmit(values, dispatch) {
return dispatch(saveData(values));
// Call the action creator which is responsible for saving data here.
}
render() {
const { onSubmit } = this.props;
const { page } = this.state;
return (
<div>
{page === 1 && <WizardFormFirstPage onSubmit={this.nextPage} />}
{page === 2 &&
<WizardFormSecondPage
previousPage={this.previousPage}
onSubmit={this.nextPage}
/>}
{page === 3 &&
<WizardFormPreview
previousPage={this.previousPage}
onSubmit={this.onSubmit}
/>}
</div>
);
}
}
WizardForm.propTypes = {
onSubmit: PropTypes.func.isRequired,
};
// this part sets the initial values. connect if you need store.
WizardForm = reduxForm ({
form: 'wizard',
initialValues: {
location: {
latitude: "0.0",
longitude: "0.0"
}
}
})(WizardForm)
export default WizardForm;
Related
I need some help. I have created three form class, Employee, Address and Authentication. Inside the Employee form when the user click the submit button, I want it to go to the Address form page and also send the Employee form data to the Address form page. I know that I can put all this on one page, but it will make it hard to read the code. And I am trying to make it match with my backend (spring boot). initialState is a Json an I am importing it from another file if your wondering.
Code for the Employee class
class Employee extends Component {
state = initialState;
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleChange = event => {
const {formData} = this.state;
this.setState({
formData: {
...formData, // leave other values unchanged
[event.target.name]: event.target.value, // update the changed value
}
});
}
validate = () => {
const {formData, errors} = this.state;
const {firstName, lastName, email, dataOfBirth, phoneNum} = formData;
let {firstNameError, lastNameError, emailError} = errors;
if (!firstName) {
firstNameError = 'First name can not be blank'
}
if (!lastName) {
lastNameError = 'Last name can not be blank'
}
if (!validateEmail(email)) {
emailError = `${email} is not valid email`
}
if (!dataOfBirth) {
console.log(dataOfBirth.length)
dataOfBirthError = 'Enter a valid date of birth'
}
if (!phoneNum) {
phoneNumError = 'Enter a valid phone'
}
if (!validatePhoneNumber(phoneNum)) {
phoneNumError = 'Enter a valid phone number'
}
if (firstNameError || lastNameError) {
this.setState( {
errors: {
firstNameError, lastNameError, emailError,
dataOfBirthError
}
})
return false
}
return true
}
handleSubmit(event) {
event.preventDefault()
const isValid = this.validate();
if (isValid) {
this.setState(initialState)
this.props.push("/addressForm")
}
}
render() {
return (
<div className="container_fluid">
<div className="registration_form_container">
<div className="register_context">
<form action="" onSubmit={this.handleSubmit} className="registration_form">
<div className="form-group">
<input type="text" name="firstName" id="firstName"
placeholder={"Enter first name"}
onChange={this.handleChange}
/>
<span>{this.state.errors.firstNameError}</span>
</div>
<div className="form-group">
<input type="text" name="lastName" id="lastName"
placeholder={"Enter last name"}
onChange={this.handleChange}
/>
<span>{this.state.errors.lastNameError}</span>
</div>
<div className="form-group">
<input type="text" name="email" id="email"
placeholder={"Enter email address"}
onChange={this.handleChange}
/>
<span>{this.state.errors.emailError}</span>
</div>
<div className="form-group custom_btn_container">
<input type="submit" className="btn" value="Register"/>
</div>
</form>
</div>
</div>
</div>
)
}
}
export default Employee;
Code for the Address Class
class Address extends Component {
state = initialState;
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleChange = event => {
const {formData} = this.state;
this.setState({
formData: {
...formData, // leave other values unchanged
[event.target.name]: event.target.value, // update the changed value
}
});
}
validate = () => {
const {state, city, street, zipcode} = formData.employeeAddress;
let {firstNameError, lastNameError, emailError, dataOfBirthError, phoneNumError} = errors;
let {employeeAddressError: {streetError, stateError, cityError, zipcodeError}} = errors
if (!street) {
streetError = "Street can not be blank"
}
if (!city) {
cityError = "Street can not be blank"
}
if (streetError || cityError || stateError) {
console.log(dataOfBirth)
this.setState( {
errors: {
employeeAddressError: {
streetError,
cityError,
stateError,
zipcodeError
}
}
})
return false
}
return true
}
handleSubmit(event) {
event.preventDefault()
const isValid = this.validate();
if (isValid) {
this.setState(initialState)
}
}
render() {
return (
<div className="container_fluid login_form_main_container">
<div className="address_context">
<div className="form-group">
<input type="text" name="street" id="street"
placeholder={"Enter street address"}
onChange={this.handleChange}
/>
<span>{this.state.errors.employeeAddressError.streetError}</span>
</div>
<div className="form-group custom_btn_container">
<input type="submit" className="btn" value="Register"/>
</div>
</div>
</div>
)
}
}
export default Address;
In App.js
return (
<Router>
<div className="App">
<Header />
<div className="content">
<Switch>
<Route path="/register" component={Employee} />
<Route path="/login">
<Login Login={LoginDetail} error={error} />
</Route>
<Route path="/addressForm" component={Address} />
<Route path="/" component={Home} />
</Switch>
</div>
</div>
</Router>
);
Inside the header page
export default function Header () {
return (
<div className="container_fluid">
<div className="navbar_container">
<div className="logo_container">
<h2>Logo</h2>
</div>
<nav className="navbar">
<div className="links_container">
<li><Link to="/">Home</Link></li>
<li><Link to="/department">Department</Link></li>
<li><Link to="/register">Register</Link></li>
<li><Link to="/login">Login</Link></li>
</div>
</nav>
</div>
</div>
)
}
As told in comment , best way of doing so is context api and here is a small demo of context
sandbox link
import React, { createContext, useState } from "react";
export const ActualContext = createContext();
const Contextt = (props) => {
return (
<ActualContext.Provider>
{props.children}
</ActualContext.Provider>
);
};
export default Contextt;
This is the way for creating a context , sandbox code will help you.
You can use the redirect router redirect feature to pass props https://reactrouter.com/web/api/Redirect/to-object
It is not a good way to send form data on router parameters and just for readability of the code no need to add another router, I suggest using state managements like Redux or Context API as react says or if you do not want either of them just add another component for example named EmployeeForm and add Employee and Address component to it (for better UI/UX you can switch between forms as user want) and pass data like this in EmployeeForm:
class EmployeeForm extends Component{
handleSubmit = values => {
this.setState({employee: values})
}
render() {
<Address employee={this.state.employee} />
<Employee onSubmit={this.handleSubmit} />
}
}
then use this.props.employee at Address component. It is event better implementation if the forms are very related and user can go back and forth as submitting without losing the states of any of these two components.
I am trying to use two states in my Add Customer JS one is used to hide the form and the second is used for JSON.
I want to use form-State to hide a form on cancel button click and the initial-State for JSON.
I want to do something like this
Is it possible to have two states in one react component
import React from 'react';
import { Button, Form, Modal } from 'semantic-ui-react';
export default class AddCustomer extends React.Component {
constructor(props) {
super(props);
this.state = {
showCreateForm:false,
formData:{
name: '',
address: ''
}
}
this.handleChangeName = this.handleChangeName.bind(this);
this.handleChangeAddress = this.handleChangeAddress.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChangeName(event) {
const value = event.target.value;
console.log(value);
this.setState({formData:{name:value}});
//name: ""
//address: ""
console.log(this.state.formData);
}
handleChangeAddress(event) {
const value = event.target.value;
console.log(value);
this.setState({formData:{address:value}});
//name: "ram" but now there is no address in formData
console.log(this.state.formData);
}
handleSubmit(event) {
event.preventDefault();
////address: "aaaaa" now there no name in formData
console.log(this.state.formData);
this.setState({formData:{
name:this.state.name, address:this.state.address
}});
this.props.onAddFormSubmit(this.state.formData);
}
//On cancel button click close Create user form
closeCreateForm = () => {
this.setState({ showCreateForm: false })
}
//Open Create new Customer form
openCreateCustomer = () => {
this.setState({ showCreateForm: true })
}
render() {
return (
<div>
<Modal closeOnTriggerMouseLeave={false} trigger={
<Button color='blue' onClick={this.openCreateCustomer}>
New Customer
</Button>
} open={this.state.showCreateForm}>
<Modal.Header>
Create customer
</Modal.Header>
<Modal.Content>
<Form onSubmit={this.handleSubmit}>
<Form.Field>
<label>Name</label>
<input type="text" placeholder ='Name' name = "name"
value = {this.state.name}
onChange = {this.handleChangeName}/>
</Form.Field>
<Form.Field>
<label>Address</label>
<input type="text" placeholder ='Address' name = "address"
value = {this.state.address}
onChange = {this.handleChangeAddress}/>
</Form.Field>
<br/>
<Button type='submit' floated='right' color='green'>Create</Button>
<Button floated='right' onClick={this.closeCreateForm} color='black'>Cancel</Button>
<br/>
</Form>
</Modal.Content>
</Modal>
</div>
)
}
}
You can directly give initial state on the constructor. e.g
this.state ={showCreateForm: false, formModel:{name:'abc', address:'xyz'}}
Yes, you can have multiple state variables technically.
As it was already mentioned, yes, you could do it in the constructor. However you could go even further and declare it as a class member. Like following:
export default class Customer extends React.Component {
state = {
showCreateForm: false,
form: {
name: "",
address: "",
}
}
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(event) {
event.preventDefault();
this.props.onAddFormSubmit(this.state.form);
this.setState({
...this.state,
form: {
name: "",
address: "",
}
});
}
// ...
render() {
return (
<div>
<Modal
closeOnTriggerMouseLeave={false}
trigger={
<Button color="blue" onClick={this.openCreateCustomer}>
New Customer
</Button>
}
open={this.state.showCreateForm}
>
<Modal.Header>Create customer</Modal.Header>
<Modal.Content>
<Form onSubmit={this.handleSubmit}>
<Form.Field>
<label>Name</label>
<input
type="text"
placeholder="Name"
name="name"
value={this.state.form.name}
onChange={this.handleChange}
/>
</Form.Field>
<Form.Field>
<label>Address</label>
<input
type="text"
placeholder="Address"
name="address"
value={this.state.form.address}
onChange={this.handleChange}
/>
</Form.Field>
<br />
<Button type="submit" floated="right" color="green">
Create
</Button>
<Button
floated="right"
onClick={this.closeCreateForm}
color="black"
>
Cancel
</Button>
<br />
</Form>
</Modal.Content>
</Modal>
</div>
);
}
}
After typing in a team name, I want react to redirect us to the specified page (ie: "teams/this.state.searchText" w/ search text being what the user has typed into the search form). I get a re-render that does nothing/does no redirecting... Can this be done with reacts new v4 Redirect component?
export default class Nav extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
searchText: ''
}
this.submit = this.submit.bind(this);
}
onSearchChange = e => {
console.log(e.target.value)
this.setState({ searchText: e.target.value });
}
submit = e => {
e.preventDefault();
// with the new search state from above, get the state and perform a search with it to local/team/"searchValue"
e.currentTarget.reset();
}
redirectIt = () => {
this.props.history.push(`teams/${this.state.searchText}`)
}
render() {
return (
<Navbar className="bg-light justify-content-between">
<Form onSubmit={this.submit} >
<FormControl type="text" placeholder="Search Team" className=" mr-sm-2" onChange={this.onSearchChange} />
<Button type="submit">Submit</Button>
</Form >
<div className='logo'>NHL</div>
<Form inline>
<Button type="submit" onClick={this.redirectIt}>Login</Button>
</Form>
</Navbar>
);
}
}
With Redirect, it would look something like this. you could basically tell the browser to go to a different page
import { Redirect } from 'react-router-dom'
export default class Nav extends React.Component {
constructor(props) {
super(props);
this.state = {
searchText: '',
isRedirected: false
}
}
onSearchChange = e => {
console.log(e.target.value)
this.setState({ searchText: e.target.value });
}
submit = e => {
e.preventDefault();
// with the new search state from above, get the state and perform a search with it to local/team/"searchValue"
e.currentTarget.reset();
}
redirectIt = () => {
this.setState({isRedirected: true})
}
render() {
// change the to prop to the next component
if (this.state.isRedirected) return <Redirect to=`/teams/${this.state.searchText}` />
return (
<Navbar className="bg-light justify-content-between">
<Form onSubmit={this.submit}>
<FormControl type="text" placeholder="Search Team" className=" mr-sm-2" onChange={this.onSearchChange} />
<Button type="submit">Submit</Button>
</Form >
<div className='logo'>NHL</div>
<Button onClick={this.redirectIt}>Login</Button>
</Navbar>
);
}
So, I have a form and I want the user to display the values user fills in the fields as a JSON object at the end when the user clicks the submit button.
In Form.js,
state={
group:[
type-A{col1: "",
col2:""
}
]
}
handleSubmit(event) {
event.preventDefault();
<Credentials value={JSON.stringify(this.state)}/>
}
change = e =>{
this.setState({[e.target.name]: e.target.value})
};
render(){
return(
<div class="classform">
<form >
<label>
Column1:
<br/>
<input type="text"
name="group1"
placeholder="Column1"
value={this.state.column1}
onChange={e=> this.change(e)}
//other fields
//input form fields
<button onClick={this.handleSubmit}>Submit</button>
In Credentials.js,
return (
<p>{value}</p>
)
}
export default Credentials
The above code gives me an error, in handleSubmit() in second line (<Credentials value={JSON.stringify(this.state)}/>)
When the user clicks Submit button, I want to get a JSON object for the data entered in the input fields in the form and update it if the user updates any information in the fields.
Move the component to render method. and use conditional rendering.
state = {credentials: false}
handleSubmit = event => {
event.preventDefault();
this.setState({
credentials: true // display Credentials component
});
};
render() {
return (
<div>
<button onClick={this.handleSubmit}>Submit</button>
{this.state.credentials && (
<Credentials value={JSON.stringify(this.state)} />
)}
</div>
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js"></script>
<div id="root"></div>
<script type="text/babel">
const Credentials = ({ value }) => {
return <p>{value}</p>;
};
class App extends React.Component {
state = { credentials: false };
handleSubmit = event => {
event.preventDefault();
this.setState({
credentials: true // display Credentials component
});
};
change = e => {
const name = e.target.name;
const nameObj = {};
nameObj[name] = e.target.value;
this.setState({ ...nameObj });
};
render() {
return (
<div>
<input
type="text"
name="col1"
value={this.state['col1']}
onChange={e => this.change(e)}
/>
<button onClick={this.handleSubmit}>Submit</button>
{this.state.credentials && (
<Credentials value={JSON.stringify(this.state)} />
)}
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
</script>
I want create a function using with i can reset value in form inputs without submit. I tried create that function in App Component (resetFormFields) and pass it on props to Form Component. It's preety simply when I want to do this onSubmit (e.target.reset()) but I got stuck when I have to do it without submit, on a different element than the form. Can I do that without adding these values to state?
App:
class App extends Component {
state = {
people: [],
formMessages: [],
person: null
};
handleFormSubmit = e => {
e.preventDefault();
const form = e.target;
const name = form.elements["name"].value;
const username = form.elements["username"].value;
this.addPerson(name, email);
form.reset();
};
resetFormFields = () => {
return;
}
render() {
return (
<div className="App">
<Form formSubmit={this.handleFormSubmit}
reset={this.resetFormFields} />
</div>
);
}
Form:
const Form = props => (
<form className={classes.Form}
id="form"
onSubmit={props.formSubmit}>
<input autoFocus
id="name"
type="text"
defaultValue=""
placeholder="Name..."
/>
<input
id="email"
type="text"
defaultValue=""
placeholder="Email..."
/>
<Button
btnType="Submit"
form="form"
type='submit'>
Submit
</Button>
<label onClick={props.reset}>Reset fields</label>
</form> );
onHandleFormSubmit = (e) =>{
e.preventDefault();
e.target.reset();
}
You need to make your inputs controlled by passing the value you store in your state then you just have to reset the state values and your component value resets.
check this sample below
handleInputChange = (e) => {
let { name, value } = e.target;
this.setState({
...this.state,
inputs: {
[name]: value
}
});
}
your component will now look like
<input name='fullName' value={this.state.inputs.fullName} onChange={this.handleInputChange} />
Your reset function will just clear the state and your input field will be empty since it's controlled via state
resetInputFields = () => {
this.setState({ inputs: {} })
}
you should give set your input values based on component state, then just update the component state
class App extends Component {
state = {
people: [],
formMessages: [],
person: null,
name: "",
email: "",
};
updateState = (newState) => {
this.setState(newState);
}
handleFormSubmit = e => {
e.preventDefault();
this.addPerson(this.state.name, this.state.email);
form.reset();
};
resetFormFields = () => {
this.setState({name:"", email: ""});
}
render() {
return (
<div className="App">
<Form formSubmit={this.handleFormSubmit} updateState={this.updateState}
reset={this.resetFormFields} email={this.state.email} name={this.state.name} />
</div>
);
}
and then
const Form = props => (
<form className={classes.Form}
id="form"
onSubmit={props.formSubmit}>
<input autoFocus
id="name"
type="text"
defaultValue=""
value={this.props.name}
onChange={(e) => this.props.updateState({name: e.target.value})}
placeholder="Name..."
/>
<input
id="email"
type="text"
defaultValue=""
value={this.props.email}
onChange={(e) => this.props.updateState({email: e.target.value})}
placeholder="Email..."
/>
<Button
btnType="Submit"
form="form"
type='submit'>
Submit
</Button>
<label onClick={props.reset}>Reset fields</label>
</form> );