ContactData.js
import React, { Component } from 'react';
import Button from '../../../components/UI/Button/Button';
import classes from './ContactData.module.css'
class ContactData extends Component {
state = {
name: '',
age: '',
address: {
street: '',
postalCode: ''
}
}
orderHandler = () => {
console.log(this.props.ingredients)
}
render() {
console.log(this.props.ingredients);
return (
<div className={classes.ContactData}>
<h4>Enter Your Contact Data</h4>
<form>
<input type="text" name="name" placeholder="Your Name" />
<input type="email" name="email" placeholder="Your Mail" />
<input type="text" name="street" placeholder="Street" />
<input type="text" name="postal" placeholder="Postal Code" />
<Button btnType="Success" clicked={this.orderHandler}>ORDER</Button>
</form>
</div>
);
}
}
export default ContactData;
CheckOut.js
import React from 'react';
import CheckoutSum from '../../components/Checkout/Checkout'
import { Route } from 'react-router-dom';
import ContactData from '../../container/Checkout/ContactData/ContactData'
class Checkout extends React.Component {
state = {
ingredients: {
salad: 1,
meat: 1,
cheese: 1,
bacon: 1
}
}
componentDidMount() {
const query = new URLSearchParams(this.props.location.search);
const ingredients = {};
for (let param of query.entries()) {
ingredients[param[0]] = parseInt(param[1]);
}
// console.log(ingredients);
this.setState({ ingredients: ingredients });
}
cancelHandle = () => {
this.props.history.goBack();
}
continueHandle = () => {
this.props.history.replace('/checkout/contact-data');
}
render() {
console.log(this.props)
console.log(this.state.ingredients)
return (
<div>
<CheckoutSum
cancel={this.cancelHandle}
continue={this.continueHandle}
ingredients={this.state.ingredients}
/>
<Route
path={this.props.match.path + '/contact-data'}
exact
render={() => (<ContactData ingredients={this.state.ingredients} />)} />
</div>
);
}
}
export default Checkout;
Problem is when I hit Order button in CotanctData component the page reloads and for some reason my URL changes to this http://localhost:3000/checkout/contact-data?name=&email=&street=&postal= and then Checkout component renders again and for some reason componentDidMount fires twice. At last I was expecting the printing of ingredients object.
Also, I'm using search query in URL to change the state of checkout component
Full Project At-https://github.com/aniket-hue/Burger-App-React/tree/Routes
Please bear with me if you don't like the question I didn't know how to frame the question.
You need to either:
Call e.preventDefult() on the <form>'s submit event.
OR, add <button type="button"> to your button to make it not submit your form.
You have to add preventDefault to your orderHandler method, beacause if button in form has no type, the type is automaticlly submit, so on every click your submitting a form. Also can you add type="button" to your button inside form.
orderHandler = e => {
e.preventDefault();
console.log(this.props.ingredients);
}
Related
How to redirect in react router in self page. e.g I have a component ProfileUpdate it updates name & stores to backend. After successful update I want to redirect to same page but it's not working. Here is a sample code.
class ProfileUpdate extends Component {
constructor() {
super();
this.state = {
name: ''
};
}
onSubmit(e) {
e.preventDefault();
this.props.history.replace('/');
}
onChange(e) {
const name = e.target.value;
this.setState(() => ({
name
}))
}
render() {
return (
<form onSubmit={this.onSubmit}>
<div>
<h4>Display Name:</h4>
<div>
<input name='displayName' placeholder='Display name' type='text' value={this.state.name} onChange={this.onChange} />
</div>
</div>
<div>
<button type='submit'>Update</button>
</div>
</form>
);
}
}
Expected behaviour if I update name then click submit it will replace the route/redirect & name input should be empty.
But when I choose a different path to replace it works. e.g this.props.history.replace('/users') it works. But here this.props.history.replace('/'); it doesn't work.
I am somewhat new to react, and I am having trouble recognizing whats causing my form to be broken. The submit button works fine and the name adds fine, but i cannot type into my price text-field for some reason. when adding items to the list, the dollar sign for price is adding, but i cant type anything into the price field.
import React, { Component } from 'react';
class ItemForm extends Component {
state = { name: '', price: ''}
handleChange = (e) => {
const { name, value } = e.target
this.setState({ [name]: value })
}
handleSubmit = (e) => {
//stop page from reloading
e.preventDefault();
//add item to groceries array
const { addItem } = this.props
addItem(this.state.name, this.state.price)
// this.props.addItem(this.state.price)
//clear form on submit
this.setState({name: '', price: ''})
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input
required
placeholder='add Grocery Item'
name="name"
value={this.state.name}
onChange={this.handleChange}
/>
<br />
<input
placeholder='add price (optional)'
name="price"
value={this.state.price}
onChange={this.handleChange}
/>
<br />
<input class = "btn btn-primary" type = "submit" value =
"Add" />
</form>
)
}
}
export default ItemForm;
I think you accidentally put price="price" instead of name="price"
I've just started learning React and am struggling with conditional rendering. I want to render components based on form input but i'm not sure what needs to be done or where it needs to be executed.
I have imported my Form component which has the input I want to use and have another component like this:
import React, {Component} from 'react';
import Form from './Form';
import CardOne from './CardOne';
import CardTwo from './CardTwo';
import CardThree from './CardThree';
export default class CardContainer extends Component {
render(){
return (
<div>
<CardOne />
<CardTwo />
<CardThree />
</div>
)
}
}
I basically want to be able to show certain Cards if the value of the input is greater than X when the form is submitted, but I don't know how to target an imported component.
This is my Form component:
export default class Form extends Component {
state = {
number: ''
};
change = (e) => {
this.setState({
[e.target.name]: e.target.value
});
};
onSubmit = e => {
e.preventDefault();
this.props.onSubmit(this.state);
this.setState({
number: ''
})
};
render(){
return (
<form>
<label>Number</label>
<input
type="number"
name="number"
placeholder="Number"
value={this.state.number}
onChange={e => this.change(e)} />
<button onClick={e => this.onSubmit(e)}>Submit</button>
</form>
)
}
}
Any help will be massively appreciated!
I have redesigned your Form component , Below is my code. . Let me know if u faced any issues on that .
import React, { Component } from 'react';
import CardOne from './CardOne';
import CardTwo from './CardTwo';
import CardThree from './CardThree';
export default class Form extends Component {
state = {
number: '',
showOne:true,
showTwo:false,
showThree:false,
userInputValue:''
};
change = (e) => {
this.setState({
userInputValue: e.target.value
});
};
onSubmit = e => {
e.preventDefault();
this.props.onSubmit(this.state);
if (this.state.userInputValue > 10 && this.state.userInputValue <20 ){
this.setState({
showTwo: true,
})
}
if (this.state.userInputValue > 20 && this.state.userInputValue < 30) {
this.setState({
showThree: true,
})
}
};
render() {
return (
<div>
<form>
<label>Number</label>
<input
type="number"
name="number"
placeholder="Number"
value={this.state.userInputValue}
onChange={e => this.change(e)} />
<button onClick={e => this.onSubmit(e)}>Submit</button>
</form>
<div>
{this.state.showOne ?
<CardOne />
:
<div></div>
}
{this.state.showTwo ?
<CardTwo />
:
<div></div>
}
{this.state.showThree ?
<CardThree />
:
<div></div>
}
</div>
</div>
)
}
}
// What i wrote above is your base functionality . You reedit the condition depends on ur requirement .
This is what I came up with following your logic of card rendering. I did not change Form coponent but rather worked on the Container
export default class CardContainer extends Component {
constructor(props) {
super(props);
state = {
number: 0,
}
this.onFormSubmit = this.onFormSubmit.bind(this);
}
onFormSubmit=(number)=>{
this.setState({ number: number });
}
render(){
let i=Math.floor(this.state.number/10)
return (
<div>
<Form onSubmit={() => this.onFormSubmit(number)}
[<CardOne />, <CardTwo />, <CardThree/>].slice(0,i).map(card =>
{card}
)
</div>
)
}
}
I would use render prop for this kind of problem. You can research more about render props but basically your CardContainer component will not render those cards component statically as it is. It will return props.children instead.
And then you will have a function (i.e function TestX) that will have a conditional to check what the value of X is. This is the function that will return either , , based on what X is. The function TestX will receive props from CardContainer, including the value of X that is read from the state.
So I will just use CardContainer component with as its child.
I'm a beginner with React and I'm attempting to make an address book application (front-end only, for now). I have my root component called App in the App.js file and I'm trying to move the form element from the root component into its own component (state-less I guess) in the AddContact.js file. I was able to find a way (searching SO) to pass the form input fields when the form is part of the root component to the form submit handler function. But I'm not able to do the same when the form element is part of a different component. Below are the App.js and AddContact.js files. How should I go about doing so? Preferably in the simplest way, while adhering to react/es6 best practices.
App.js
import React, { Component } from 'react';
import './App.css';
//import AddContact from './AddContact/AddContact';
//import './AddContact/AddContact.css';
import ContactList from './ContactList/ContactList.js';
import Cockpit from './Cockpit/Cockpit.js';
class App extends Component {
state = {
contacts:[]
};
addContactHandler = (event) => {
event.preventDefault();
//console.log(event.target[0].value);
//console.log(event.target.name.value);
const name = this.input1.value;
const phone = this.input2.value;
const email = this.input3.value;
let contacts = [...this.state.contacts];
if (name.length>0 && phone.length>0 && email.length>0){
let contact = {
name: name,
phone: phone,
email: email
};
contacts.push(contact);
console.log("contacts: ", contacts);
this.setState({
contacts:contacts
});
}
this.input1.value = '';
this.input2.value = '';
this.input3.value = '';
};
render() {
let contactList = null;
let contacts = [...this.state.contacts];
if (contacts.length > 0) {
contactList = (
<ContactList
contacts = {contacts}
/>
);
}
return (
<div className="App">
<Cockpit/>
<p>Add New Contact:</p>
<form className="AddContact" onSubmit={(event)=>this.addContactHandler(event)}>
<label>Name:
<input type="text" name="name" ref={(name) => {this.input1 = name}}/>
</label>
<label>Phone:
<input type="text" name="phone" ref={(phone) => {this.input2 = phone}}/>
</label>
<label>Email:
<input type="text" name="email" ref={(email) => {this.input3 = email}}/>
</label>
<input type="submit" value="Submit" />
</form>
{/* <AddContact submit={(event)=>this.addContactHandler(event)}/> */}
{contactList}
</div>
);
}
}
export default App;
AddContact.js
// Use at a later stage
import React from 'react';
import './AddContact.css';
const AddContact = (props) => {
return (
<div >
<p>Add New Contact:</p>
<form className="AddContact" onSubmit={props.submit}>
<label>Name:
<input type="text" ref={(name) => {this.input = name}}/>
</label>
<label>Phone:
<input type="text" ref={(phone) => {this.input2 = phone}}/>
</label>
<label>Email:
<input type="text" ref={(email) => {this.input3 = email}}/>
</label>
<input type="submit" value="Submit" />
</form>
</div>
);
};
export default AddContact;
Moving the form element into its own dedicated component is a great approach. But don't try to handle the child component's form submit event from the parent component. The child component owns the form, it should handle its mutations and submission too. With that in mind, this is how I'd structure the components:
Your App renders the AddContact component.
For your AddContact component, don't pass an onSubmit handler to it. Instead, pass an onAdd handler that expects a contact object as its argument.
Make your AddContact component stateful! Is there any particular reason you would want it to be stateless? Make it stateful, let it handle form updates as part of its state (use Controlled Components). And finally, on the form onSubmit event, package up a contact object and call the props.onAdd handler with it.
This will be a cleaner, more rationally separated architecture for your components. The parent component shouldn't have to worry about a child component's form submit behavior, but should rather expect a nicely packaged up contact object.
Check this out: https://mn627xy99.codesandbox.io/
class AddContact extends React.Component {
state = {
name: "",
phone: "",
email: "",
}
submit = e => {
e.preventDefault();
this.props.onAdd(this.state);
// Clear the form
this.setState({name: "", phone: "", email: ""});
}
change = e => {
e.preventDefault();
this.setState({[e.currentTarget.name]: e.currentTarget.value});
}
render() {
return (
<div >
<p>Add New Contact:</p>
<form className="AddContact" onSubmit={this.submit}>
<label>Name:
<input type="text" name="name" onChange={this.change} value={this.state.name} />
</label>
<label>Phone:
<input type="text" name="phone" onChange={this.change} value={this.state.phone} />
</label>
<label>Email:
<input type="text" name="email" onChange={this.change} value={this.state.email} />
</label>
<input type="submit" value="Submit" />
</form>
</div>
);
}
}
I am trying to create a customer details form in react (currently using react-json-form) where I can reuse the values in the inputs to create a saved file that the app can refer to. I have created the form and can output the results but I am unsure how to save the input values for future use or call them back once they are saved.
If anyone has any suggestions or examples of a form that does this then I would be greatly appreciative.
My code is as follows:
import React, { Component } from 'react';
import JSONTree from 'react-json-tree';
import { BasicForm as Form, Nest, createInput } from 'react-json-form';
const Input = createInput()(props => <input type="text" {...props} />);
const UserFields = () => (
<section>
<h3>User</h3>
<div>Name: <Input path="name" /></div>
<div>Email: <Input path="email" /></div>
</section>
);
export default class ExampleForm extends Component {
state = { data: {} };
updateData = data => this.setState({ data });
render() {
return (
<Form onSubmit={this.updateData}>
<Nest path="user">
<UserFields />
</Nest>
<button type="submit">Submit</button>
<JSONTree data={this.state.data} shouldExpandNode={() => true} />
</Form>
);
}
}
A more simple solution would be to use a form, like a semanti-ui-react form, store the information to the state onChange, then convert the info to JSON for storage.
import { Form, Button } from 'semantic-ui-react'
export default class App extends Component {
constructor() {
super()
this.state = {
name: "",
email: ""
}
}
handleChange = (e, {name, value}) => {
console.log(name, value)
this.setState({[name]: value})
}
render() {
return (
<div>
<Form onSubmit={this.sendDataSomewhere}>
<Form.Field>
<Form.Input name="name" value={this.state.name} onChange={this.handleChange}/>
</Form.Field>
<Form.Field>
<Form.Input name="email" value={this.state.email} onChange={this.handleChange}/>
</Form.Field>
<Button type="submit">Submit</Button>
</Form>
</div>
)
}
}
I use a dynamic method of receiving the input from different fields using the name and val attributes. The values captured in state are then accessible by this.state.whatever
Hope this helped