input field not changing in React (controlled input) - javascript

Without the bind.(this) on the this.updateEmail.bind(this) the input field value changes but I receive in error saying cannot set this.setState of undefind. So I add .bind(this) but it doesn't work at all.. a bit confused
import React, { Component } from 'react';
import Request from 'superagent';
class App extends Component {
constructor(){
super()
this.state = {
email: 'asdf',
password: ''
}
}
updateEmail(e){
this.setState={
email: e.target.value
}
}
createUser(e){
var query = 'star';
e.preventDefault()
console.log(this.state.email)
var url = `http://www.omdbapi.com?s=${query}&y=&r=json&plot=short`;
Request.get(url).then((response) => {
console.log(response)
this.setState({
movies: response.body.Search,
total: response.body.totalResults
});
});
}
render() {
return (
<div className="App">
<div className="App-header">
<form onSubmit={this.createUser.bind(this)}>
<input type="text"
name="email"
onChange={this.updateEmail.bind(this)}
value={this.state.email}
placeholder="email"/>
<br/>
<input type="text"
name="password"
value={this.state.password}
onChange={this.updatePassword}
placeholder="password"/>
<br/>
<input type="submit" value="submit"/>
</form>
</div>
</div>
);
}
}
export default App;

setState is a function, you should call it as such:
this.setState({ foo: 'bar' });

Related

trouble getting data from react input form

I am just making a simple app to learn react with redux.
I just want to get data input in the react input form on the server-side.
The problem is that the params on the server-side is like this.
{"item"=>{"name"=>"undefined","price"=>"undefined"...}...}
Here is part of my code:
import React from "react";
class ItemForm extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.update = this.update.bind(this);
}
handleSubmit(e) {
e.preventDefault();
const ItemData = new FormData();
ItemData.append("item[name]", this.props.item.name);
ItemData.append("item[price]", this.props.item.price);
};
update(field) {
return (e) => {
this.setState({ [field]: e.target.value });
};
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<div>
<label>
<div>Item</div>
<input
type="text"
value={this.props.item.name}
onChange={this.update("name")}
/>
</label>
<label>
<div>Price</div>
<input
type="number"
value={this.props.item.price}
onChange={this.update("price")}
/>
</label>
<div>
<input type="submit" value="Submit" />
</div>
</div>
</form>
</div>
);
}
}
Shoule I use store function in redux or is there more easy way?
Thanks.
Assumption
I'm assuming that the problem is that the data you can access in your handleSubmit function is not being updated, therefore you always receive the values that you initialized the component with.
Solution
Initialize the state based on the name and price props passed in
Set the value of your input tags to the state values
Access the state in your handleSubmit function
import React from "react";
import { withRouter } from "react-router-dom";
class ItemForm extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.update = this.update.bind(this);
this.state = {
name: this.props.item.name,
price: this.props.item.price
}
}
handleSubmit(e) {
e.preventDefault();
const ItemData = new FormData();
ItemData.append("item[name]", this.state.name);
ItemData.append("item[price]", this.state.price);
};
update(field) {
return (e) => {
this.setState({ [field]: e.target.value });
};
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<div>
<label>
<div>Item</div>
<input
type="text"
value={this.state.name}
onChange={this.update("name")}
/>
</label>
<label>
<div>Price</div>
<input
type="number"
value={this.state.price}
onChange={this.update("price")}
/>
</label>
<div>
<input type="submit" value="Submit" />
</div>
</div>
</form>
</div>
);
}
}
export default withRouter(ItemForm);
Other suggestions
Your redux wrapper component doesn't have any big effects on this, so you can remove it from this question for clarity 😀
This is actually one of the benefits of redux, the connected component (ItemForm) is a regular React component and does not have any knowledge that it will be acted on by redux
Hope that helps! 👍

Form input elements are messing with URL of react page

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);
}

How can I keep on adding username and status instead of updating the previous one in reactJS?

I have two components. One named 'Adduser' containing form elements so that a user may add details of post. Other named 'PostAdded', in which i want to show all posts in a list item. On every click, I want 'Adduser' to grab data from input elements and pass it to 'PostAdded' in a way that 'PostAdded' show every individual post(title and post together) in a new div instead of updating previous one. What is the best approach to do it?
File 'Adduser.js'
class AddUser extends Component {
constructor(props) {
super();
this.state = {
title : "",
post : "",
}
this.handleclick = this.handleclick.bind(this);
}
handleclick() {
this.setState(prevState => ({
title : document.getElementById("title").value,
post : document.getElementById("post").value,
}));
}
render() {
return(
<div>
<input type="text" id="title" placeholder="Title here" />
<input type="text" id="post" placeholder="Post here" />
<input type="button" onClick={this.handleclick} value="Add Post" />
<PostAdded posts={this.state.post} />
</div>
)
}
}
export default AddUser;
File 'PostAdded.js'
import React, {Component} from 'react';
class PostAdded extends Component {
constructor(props) {
super();
}
render() {
return <ul>
{ this.props.posts.map(post =>
<li>{post}</li>
)}
</ul>
}
}
export default PostAdded;
In AddUser component change your state and handleclick method. I have not modified your code too much so you can understand it easily.
class AddUser extends Component {
constructor(props) {
super();
this.state = {
posts: [],
}
this.handleclick = this.handleclick.bind(this);
}
handleclick() {
// accessing values from the input
let title = document.getElementById("title").value
let post = document.getElementById("post").value
// creating a new object
let newPostObj = {title, post}
// concatenating new object to component posts state
let newPost = this.state.posts.concat(newPostObj)
// setting newPost as component new state
this.setState({
posts: newPost
})
// emptying the input fields
document.getElementById("title").value = ''
document.getElementById("post").value = ''
}
render() {
return(
<div>
<input type="text" id="title" placeholder="Title here" />
<input type="text" id="post" placeholder="Post here" />
<input type="button" onClick={this.handleclick} value="Add Post" />
<PostAdded posts={this.state.posts} />
</div>
)
}
}
In your PostAdded component update render() method
class PostAdded extends Component {
constructor(props) {
super();
}
render() {
return (
<ul>
{ this.props.posts.map((post, i) =>
<li key={`${i}-post`}><span>{post.title}</span><span>{post.post}</span></li>
)}
</ul>
)
}
}
UPDATE
Change your AddUser Component
class AddUser extends Component {
constructor(props) {
super();
this.state = {
posts: [],
title: '',
post: ''
}
this.handleClick = this.handleClick.bind(this);
this.handleChange = this.handleChange.bind(this);
}
// called when we type something in input fields
handleChange(e) {
// you can console log here to see e.target.name and e.target.value
this.setState({
[e.target.name]: e.target.value
})
}
handleClick() {
// using spread operator to copy previous state posts and adding new post object
let newPosts = [ ...this.state.posts, { title: this.state.title, post: this.state.post}]
this.setState({
posts: newPosts,
title: '',
post: ''
})
}
render() {
return(
<div>
// added name,value attributes and onChange listener
<input type="text" name="title" value={this.state.title} onChange={this.handleChange} placeholder="Title here" />
<input type="text" name="post" value={this.state.post} onChange={this.handleChange} placeholder="Post here" />
<input type="button" onClick={this.handleClick} value="Add Post" />
<PostAdded posts={this.state.posts} />
</div>
)
}
}

Check password validation in React

I want to check the validation of Re-password in React, I wrote this code for that but when you set(for Example) passsword:"1234" and Re-password:"1234" it doesn't apply as true but when you enter the fifth character for Re-password it becomes True .
Do you know what is issue?
import React , { Component } from 'react';
export default class RegistrationForm extends Component {
constructor(props) {
super(props);
this.state = {
name: '',
email:'',
password :'',
password_re:'',
password_has_error:false
};
}
checkPassword() {
if(!this.state.password || this.state.password != this.state.password_re) {
this.setState({password_has_error:true});
}
else {
this.setState({password_has_error:false});
}
}
handleChange(event) {
this.setState({[event.target.name] : event.target.value });
if (event.target.name == 'password' || event.target.name == 'password_re')
this.checkPassword();
}
handleSubmit(event) {
event.preventDefault();
// TODO: will submit the form here
}
render(){
return (
<form onSubmit={(event)=>this.handleSubmit(event)}>
<div>
<label>Name</label>
<input
type="text"
name="name"
value={this.state.name}
onChange={(event)=>this.handleChange(event)}
/>
</div>
<div>
<label>Email address</label>
<input
name="email"
type="email"
value={this.state.email}
onChange={(event)=>this.handleChange(event)}
/>
</div>
<div>
<label>Password</label>
<input
type="password"
name="password"
value={this.state.password}
onChange={(event)=>this.handleChange(event)}
/>
</div>
<div>
<label>Re-enter password</label>
<input
type="password"
name="password_re"
value={this.state.password_re}
onChange={(event)=>this.handleChange(event)}
/>
</div>
<button type="submit">Submit</button>
</form>
)
}
}
Edit:This is my React component
This is because, setState is async, it will not update the state value immediately.
Write it like this, by using setState callback method:
handleChange(event) {
const { name, value } = e.target
this.setState({
[name] : value
}, () => {
if (name == 'password' || name == 'password_re')
this.checkPassword();
}
}
);
}
Check this for more details about setState async behaviour.

Slack invite with react and slack api

I am attempting to set up a slack invite based on this tutorial: https://www.robinwieruch.de/slack-invite-javascript-react
I have everything set up the same as the example but I'm getting this error
TypeError: onUserAuthSignUp is not a function
I can see in the code where it's being destructured:
const { onUserAuthSignUp } = this.props
But I cannot see what I'm missing, i'm still learning JS and React so i'm thinking it's something really obvious.
Full code for the form is below, <Form /> is then imported into the index.js file.
// Form.js
import React, { Component } from "react"
import axios from 'axios';
var SLACK_TOKEN = 'slack-token';
var SLACK_INVITE_ENDPOINT = 'https://slack.com/api/users.admin.invite';
function inviteSuccess() {
console.log('success');
}
function inviteError() {
console.log('error');
}
function inviteToSlack(email) {
var QUERY_PARAMS = `email=${email}&token=${SLACK_TOKEN}&set_active=true`;
axios.get(`${SLACK_INVITE_ENDPOINT}?${QUERY_PARAMS}`)
.then(inviteSuccess)
.catch(inviteError);
}
export class Form extends Component {
constructor(props) {
super(props);
this.state = {
email: '',
passwordOne: '',
passwordTwo: '',
username: '',
isSlackInvite: true,
};
this.onSubmit = this.onSubmit.bind(this);
this.onCheckSlackInvite = this.onCheckSlackInvite.bind(this);
}
onCheckSlackInvite(e) {
this.setState(prevState => ({ isSlackInvite: !prevState.isSlackInvite }));
}
onSubmit(e) {
e.preventDefault();
const {
email,
passwordOne,
username,
isSlackInvite,
} = this.state;
const { onUserAuthSignUp } = this.props;
if (isSlackInvite) {
inviteToSlack(email);
}
onUserAuthSignUp(email, passwordOne, username);
}
render() {
const {
email,
passwordOne,
passwordTwo,
username,
isSlackInvite,
} = this.state;
return (
<form onSubmit={this.onSubmit}>
<input
type="text"
placeholder="Full Name"
value={username}
onChange={e => this.setState({ username: e.target.value})}
/>
<input
type="text"
placeholder="Email Address"
value={email}
onChange={e => this.setState({ email: e.target.value})}
/>
<input
type="password"
placeholder="Password"
value={passwordOne}
onChange={e => this.setState({ passwordOne: e.target.value})}
/>
<input
type="password"
placeholder="Confirm Password"
value={passwordTwo}
onChange={e => this.setState({ passwordTwo: e.target.value})}
/>
<div>
<label>Join Slack Group</label>
<input
type="checkbox"
checked={isSlackInvite}
onChange={this.onCheckSlackInvite}
/>
</div>
<button
disabled={passwordOne !== passwordTwo || passwordOne === '' || username === ''}
type="submit"
className="btn"
>
Sign Up
</button>
</form>
)
}
}
Tutorial author here. Sorry for being unclear in the tutorial!
The SignUp component only showcases how it can be used afterward (e.g. in a sign up process). But it doesn't show how to implement the whole sign up, it merely shows how the Slack invite can be used as an opt-in in such a form:
if (isSlackInvite) {
inviteToSlack(email);
}
If you are curious to implement the whole sign up process, checkout the Complete Firebase in React authentication tutorial. There you will implement the SignUp form where you can opt-in the Slack invite afterward.

Categories