this.state.value is undefined despite being set - javascript

I am new to reactjs. I have taken sample code from the react documentation (https://facebook.github.io/react/docs/forms.html) and modified it very slightly to create the following class:
class LoginView extends React.Component {
constructor(props) {
super(props);
this.state = {email: '',
password: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
alert(this.state.email);
this.setState({email: event.target.email});
this.setState({password: event.target.password});
}
handleSubmit(event) {
alert(this.state.email);
var response = fetch('http://0.0.0.0:5000/v1/authtoken/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
body: JSON.stringify({
email: this.state.email,
password: this.state.password,
})
}).then((response) => response.json())
var token = response.token
alert([token])
event.preventDefault();
}
render() {
return (
<div className="login-form">
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<label htmlFor="email">Email address:</label>
<input type="email" className="form-control" id="email" value={this.state.email} onChange={this.handleChange}/>
</div>
<div className="form-group">
<label htmlFor="pwd">Password:</label>
<input type="password" className="form-control" id="pwd" value={this.state.password} onChange={this.handleChange}/>
</div>
<div className="checkbox">
<label><input type="checkbox"/> Remember me</label>
</div>
<button type="submit" className="btn btn-default">Submit</button>
</form>
</div>
);
}
}
export default LoginView
The purpose of the class is to present a login form which will post the value of the email and password fields to an endpoint. I am pulling my hair out over the way the this.state object is behaving.
Note that there is an alert in both handleSubmit and handlechange. These alerts should contain the value of the email field, but they instead contain the value undefined. What is confusing me is that the fields themselves, which also present values from this.state.email, actually work. This means that state is somehow being saved, but it just isn't available within the functions.
I've been pouring over this for hours and am at a loss as to how I could be getting this behavior. Any help would be very appreciated.

In handleChange(), event.target.email and event.target.password is not valid.
event is the onChange event for the particular field that is changing. event.target returns the DOMEventTarget (https://facebook.github.io/react/docs/events.html) which is a reference to the object that dispatched the event.
So in your case, event.target is the input field that triggered the onChange.
You will need to update this to:
// If you use ES6 you can do this to use `event.target.type` as a key
handleChange(event) {
this.setState({
[event.target.type]: event.target.value
});
}
// Otherwise, you can do it like this
handleChange(event) {
var newState = {};
newState[event.target.type] = event.target.value;
this.setState(newState);
}
event.target.type will return the <input> type which for your case is either 'email' or 'password'. and event.target.value will return the value which you want to update.
Additional note: Calling .setState(nextState) will perform a shallow merge of nextState into current state. So you do not need to update both email and password in your handleChange function. https://facebook.github.io/react/docs/react-component.html#setstate

Related

onClick :call a function from componentDidMount

I have a form like this:
<form id="sendSms">
<h1 className="distance">signup</h1>
<input className="text-right" onClick={ostype} id="input1" name="mobileNumber" pattern="[0-9]+" type="text" placeholder="mobile" required />
<input name="osVersion" id="input2" type="hidden" value="" />
<input name="osType" id="input3" type="hidden" value="" />
<input name="deviceID" id="input4" type="hidden" value="Come on" />
<button className="distance" type="submit" onClick={sendData}>submit</button>
</form>
I want to sendData function POST the inputs to api
the function:
function sendData() {
axios({
method: 'post',
url: 'some api i have',
data: sendSms,
})
.then(res => this.setState({ recipes: res.data }));
}
var sendSms =
{
'mobileNumber' : document.getElementById("input1"),
'osVersion' : document.getElementById("input2"),
'osType' : document.getElementById("input3"),
'deviceID' : document.getElementById("input4"),
}
I tried to put axios in componentDidMount() but that way i cant call the sendData functuion with onClick.
and when i put the function in my code, i get NS_BINDING_ABORTED
Try something like this:
// Using Hooks
export default function SMSView() {
const [state, setState] = useState({
mobileNumber: '',
osVersion: '',
osType: '',
deviceID: ''
})
const handleChange = ({target: {value, name}}) => {
setState({...state, [name]: value})
}
const handleSubmit = e => {
e.preventDefault()
// axios here
}
return <form onSubmit={handleSubmit}>
<input name="mobileNumber" value={state.mobileNumber} onChange={handleChange}/>
<input name="osVersion" value={state.osVersion} onChange={handleChange}/>
<input name="osType" value={state.osType} onChange={handleChange}/>
<input name="deviceID" value={state.deviceID} onChange={handleChange}/>
<button type="submit">Submit</button>
</form>
}
// Using Class Component
export default class SMSView extends React.Component {
constructor(props) {
super(props);
this.state = {
mobileNumber: '',
osVersion: '',
osType: '',
deviceID: ''
}
}
handleChange = ({target: {value, name}}) => {
this.setState({...this.state, [name]: value})
}
handleSubmit = e => {
e.preventDefault()
// axios here
}
render() {
const {mobileNumber, osVersion, osType, deviceID} = this.state
return <form onSubmit={this.handleSubmit}>
<input name="mobileNumber" value={mobileNumber} onChange={this.handleChange}/>
<input name="osVersion" value={osVersion} onChange={this.handleChange}/>
<input name="osType" value={osType} onChange={this.handleChange}/>
<input name="deviceID" value={deviceID} onChange={this.handleChange}/>
<button type="submit">Submit</button>
</form>
}
}
or use libraries like [React Hook Form][1]
[1]: https://react-hook-form.com/
You have mixed two worlds in your code: In the below code(that you have written) to get the Values from the inputs, The approach is Imperative but still it is wrong, You are not assigning any value but directly assigning DOM elements to your sendSms object.
var sendSms =
{
'mobileNumber' : document.getElementById("input1"),
'osVersion' : document.getElementById("input2"),
'osType' : document.getElementById("input3"),
'deviceID' : document.getElementById("input4"),
}
You should use a Controlled Component Approach instead to get values of your inputs.
Secondly, There should not be any error at all if you use onClick the way you have, You do not need to use ComponentDidMount at all.
You simply should check two things,before sending your data via Post Axios request.
Whether I have the available data from inputs.
Whether server is allowing for Post call.
So, you need to do some homework dear Friend, Let me share some resources.
From Official React Docs Controlled Forms
Making post call (on Form submit exactly what you require) https://reactgo.com/react-post-request-axios/
Please Note: Though Class based approach will work but from React 16.8, React is officially using React Hooks, do have a look into that as well https://reactjs.org/docs/hooks-intro.html
For onClick event you must to do like this :
onClick={() => sendData()}
After I advise you to use Function components instead of Class components and use Hook instead directly use state and lifecycle fonction.

I am facing a problem in JavaScript/ReactJS

I am working in ReactJS on post API. I have given a task to create some text fields in which I have to give some values and then on click of a submit button the information from text field will be submitted to POST API which I have taken from JasonPlaceHolder.
I have written a code which is given at last. Whenever I click Register button the value in last input field (which in my case is "EMAIL") overrides the values of all the input fields.
A screenshot of my problem is also attached:
Code
import React from 'react';
import logo from './logo.svg';
import './App.css';
import axios from 'axios';
class App extends React.Component {
constructor(props){
super(props);
this.state = {
error: null,
isLoaded: false,
items: [],
inter:0,
ID: '',
Name: '',
username : '',
Email: ''
};
this.updateInput = this.updateInput.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
updateInput(event){
this.setState({ID : event.target.value})
this.setState({Name : event.target.value})
this.setState({username : event.target.value})
this.setState({Email : event.target.value})
}
handleSubmit(){
var dict = { id: this.state.ID, name:this.state.Name , username: this.state.username , email: this.state.Email };
axios.post('https://jsonplaceholder.typicode.com/users', dict)
.then(response => {
console.log(response)
this.setState({isLoaded:true,
flag:1,
})
})
.catch(error => {
alert(error);
console.log(error);
})
}
render() {
const { error, isLoaded, items } = this.state;
if (this.state.inter == 0){
return(
<div>
<form>
<p>ID:<input type="text" name="ID" onChange={this.updateInput}/> </p>
<p>Name:<input type="text" name="name" onChange={this.updateInput} /> </p>
<p>User Name:<input type="text" name="username" onChange={this.updateInput} /></p>
<p>Email: <input type="text" name="email" onChange={this.updateInput} /></p>
</form>
<button onClick={this.handleSubmit}>
Register
</button>
</div>
);
}else{
return(
<div>
<button onClick={this.handleSubmit} >
Register
</button>
<h1> Post Request Submitted Successfully</h1>
</div>
);
}
}
componentDidMount() {
}
}
export default App;
Your updateInput method overrides all the other fields, that's why the last updated field (the email) is the one you are seeing on the request payload.
To solve this you can separate the updateInput method for each input field or inside updateInput check which field you're currently updating and update only that field.
You can check here for more details:
https://medium.com/#zacjones/handle-multiple-inputs-in-react-with-es6-computed-property-name-e3d41861ae46
You have to update the fields like this,
updateInput({target: {name, value}}){
this.setState({[name]: value});
}
The issue is in the updateInput method. change it to.
const { name, value } = event.target;
this.setState(state => ({
...state, [name]: value,
}));
N:B You will have to make the names of the input element same as the state field.
Change your updateInput logic to this.
updateInput(event){
this.setState({[event.target.name] : event.target.value})
}

Form data won't bind to React component using onChange()

I've been coding up an email service for myself, and got stuck on this React form not changing state when form data is entered. Tracked down the main problem to this React form not changing state via onChange()...
How could I bind state to the React form that updates on every keystroke? Using this form data to pass later into an API call.
'''
class AddContact extends Component {
constructor(props) {
super(props);
this.state = {
'name': '',
'company': '',
'linkedin': '',
'department': '',
'email': 'Not available'
}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({ value: event.target.value });
}
handleSubmit(event) {
}
render() {
return(
<div>
<form onSubmit = {this.handleSubmit}>
<label>
Name
<input type="text" value={this.state.name} onchange = {this.handleChange}/>
</label>
<label>
Company
<input type="text" value={this.state.company} onchange = {this.handleChange}/>
</label>
<label>
LinkedIn Profile
<input type="text" value={this.state.linkedin} onchange = {this.handleChange}/>
</label>
<label>
Department
<input type="text" value={this.state.department} onchange = {this.handleChange}/>
</label>
<label>
Email (Optional)
<input type="text" value={this.state.email} onchange = {this.handleChange}/>
</label>
<input type="submit" value="Submit" />
</form>
</div>
);
}
}
'''
You're not changing the actual form values in state. This line: this.setState({ value: event.target.value }); Changes the value of the value key in the state. So if you were to call this this.setState({ value: 'potato' }); then your state would look like this:
this.state = {
'name': '',
'company': '',
'linkedin': '',
'department': '',
'email': 'Not available',
'value': 'potato'
}
So you need to pass in the actual field name you're trying to change into the onChange function. And that's another thing, you have a typo. The handler is called onChange, with camel case. Yours is incorrectly all lower case.
So here's a correct example of updating the 'name' field. Firstly, update your handleChange function to this:
handleChange(field, value) {
this.setState({ [field]: value });
}
Then change your inputs to be like this:
<input type="text" value={this.state.name} onChange={e => this.handleChange('name', e.target.value)}/>

laravel and react upload file return 500 Internal Server Error

i have a problem with my code when I try to upload a file with reactjs and laravel for backend, after click submit button server response with 500 IS error,looking forward inside code i get message Call to a member function getClientOriginalName() on null, I guess error appear because of my js function, so hopefully someone can help me finger it out, i am appreciate it
my react component :
constructor(){
super();
this.fileInput = React.createRef();
this.state = {
name: '',
avatar: '',
}
}
handleNameChange(e){
this.setState({
name: e.target.value
})
}
handleAvatarChange(e){
this.setState({
avatar:this.fileInput.current.files[0].name
})
}
handleSubmit(e){
e.preventDefault();
axios.post('/api/add', this.state).then(response => {
console.log(response)
}).then(error => {
console.log(error)
})
}
render(){
return (
<div>
home
{/*<Link to="/" className="btn btn-success">Return to Items</Link>*/}
<form className="form-horizontal" onSubmit={this.handleSubmit.bind(this)}>
<input type="text" className="form-control" id="name" value={this.state.name} onChange={this.handleNameChange.bind(this)}/>
<input type="file" ref={this.fileInput} onChange={this.handleAvatarChange.bind(this)} /><br></br>
<button type="submit" className="btn btn-default">Save</button>
</form>
</div>
)
}
}
my controller:
public function store(Request $request){
$file_name_image = $request->file('avatar')->getClientOriginalName();
$user = new User();
$user->name = $request->name;
$user ->avatar = $file_name_image;
$request->file('avatar')->move('upload/',$file_name_image);
$user->save();
return response()->json('Successfully added');
}
I think the problem in your input tag.
Input doesn't have name attribute. You should add it.
<input name="file" type="text" className="form-control" id="name" value={this.state.name} onChange={this.handleNameChange.bind(this)}/>
And I recommend you add IF statement in yours controller.
if ($request->hasFile('file')) {
//
}
I can not comment, so I will write the answer here.
So you can find the answer for your original question here: How do I set multipart in axios with react?
If you want to send other data than file too, you just simply add it like you did with the file. for example:
formData.append('name', 'Your new name')
first parameter is the name you want for the POST data key, the second one is the data you want to send. It can come from the state etc.
for anyone else who may need, thank all!
constructor(props) {
super(props);
this.state ={
file:null,
name:'',
}
this.onFormSubmit = this.onFormSubmit.bind(this)
this.onChange = this.onChange.bind(this)
this.fileUpload = this.fileUpload.bind(this)
this.handleNameChange = this.handleNameChange.bind(this)
}
onFormSubmit(e){
e.preventDefault() // Stop form submit
this.fileUpload(this.state.file,this.state.name).then((response)=>{
console.log(response.data);
})
}
onChange(e) {
this.setState({file:e.target.files[0]})
}
handleNameChange(e){
this.setState({
name: e.target.value
})
}
fileUpload(file, name){
const url = 'http://localhost:8000/api/add';
const formData = new FormData();
formData.append('file',file);
formData.append('name', name);
const config = {
headers: {
'content-type': 'multipart/form-data'
}
}
return post(url, formData,config)
}
render() {
return (
<form onSubmit={this.onFormSubmit}>
<h1>File Upload</h1>
<input type="text" value={this.state.name} onChange={this.handleNameChange}/>
<input type="file" onChange={this.onChange} />
<button type="submit">Upload</button>
</form>
)
}

Uncaught TypeError: Cannot read property 'value' of undefined in REACT JS

I am creating a login form using REACT JS as front-end and PHP as back-end. I am trying to get input values. Code is as below:
import React, { Component} from 'react';
import ReactDOM from 'react-dom';
import {Button, IconButton} from 'react-toolbox/lib/button';
import Input from 'react-toolbox/lib/input';
export default class Login extends React.Component {
constructor() {
super();
this.state = {email: ''};
this.state = {password: ''};
this.onSubmit = this.onSubmit.bind(this);
this.handleEmailChange = this.handleEmailChange.bind(this);
this.handlePasswordChange = this.handlePasswordChange.bind(this);
}
handleEmailChange(e) {
this.setState({email: e.target.value});
}
handlePasswordChange(e) {
this.setState({password: e.target.value});
}
onSubmit() {
fetch('http://xyz/check-login', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: this.state.email,
password: this.state.password,
})
})
}
And form is as below:
<form name="Login">
<Input type="text" name="email" value={this.state.email} placeholder="Email Id" className="form-control" onChange={this.handleEmailChange} />
<Input name="password" value={this.state.password} placeholder="Password" type="password" className="form-control m-b-10" onChange={this.handlePasswordChange} />
<Button type="button" className="m-t-20 orange" label="Sign in " onClick={this.onSubmit} />
</form>
But getting the following error:
Uncaught TypeError: Cannot read property 'value' of undefined
I am using react-toolbox. So, I am using component from https://github.com/react-toolbox/react-toolbox/blob/dev/components/input/Input.js and component from https://github.com/react-toolbox/react-toolbox/blob/dev/components/button/Button.js.
First of all, what are <Input ..../> and <Button .../>? Are they your components or they are only form input fields?
I suppose that they are only form fields, thus they need to be in lower case <input ..../> , <button .../>.
Try to bind your functions inside render, like : this.functionName.bind(this).
This is a working code :
class Test extends React.Component {
constructor(props){
super(props);
this.state = {
email: '',
password: '',
};
}
handleEmailChange(e) {
this.setState({email: e.target.value});
}
handlePasswordChange(e) {
this.setState({password: e.target.value});
}
render(){
return (
<div>
<form name="Login">
<input type="text" name="email" value={this.state.email} placeholder="Email Id" className="form-control" onChange={this.handleEmailChange.bind(this)} />
<input name="password" value={this.state.password} placeholder="Password" type="password" className="form-control m-b-10" onChange={this.handlePasswordChange.bind(this)} />
<button type="button" className="m-t-20 orange" label="Sign in " onClick={this.onSubmit}>Sign in</button>
</form>
</div>
)
}
}
React.render(<Test />, document.getElementById('container'));
Here is the fiddle.
UPDATE
I tested it here :
constructor(props){
super(props);
this.state = {
name: '',
email: ''
}
}
handleChange(name, value){
let state = this.state;
state[name] = value;
this.setState({state});
}
render () {
return (
<section>
<Input type='text' label='Name' name='name' value={this.state.name} onChange={this.handleChange.bind(this, 'name')} maxLength={16} />
<Input type='email' label='Email address' icon='email' value={this.state.email} onChange={this.handleChange.bind(this, 'email')} />
</section>
);
}
I'm not sure how it works, but it pass name and value as params to the handleChange function, thus, you can get value as a second param. You don't need event.
First change your this.state in constructor to single - this.state = {emai:'',password:''}, then try to bind handleEmailChange and handlePasswordChange inside of input instead in constructor, u need to set this direct to input,
UPDATE
or if Input and Button are components, u need implement changeMethod and onChange event in them, and send value back to component Login via callback
HOW IT WORKS -
class Input extends React.Component{
constructor(props){
super(props);
this.state= {
value : this.props.value
}
}
componentWillReceiveProps(nextProps){
this.setState({
value: nextProps.value,
})
}
render(){
return(
<input onChange={this.handleChangeValue.bind(this)} type="text" name={this.props.name} value={this.state.value} placeholder={this.props.placeholder} className={**just class name or send via props too**} />
)
}
handleChangeValue(e){
this.setState({value:e.target.value});
this.props.changeValue(e.target.value);
}
}
class Login extends React.Component{
constructor(props){
super(props);
this.state= {
emailValue : '',
passwordValue: '',
...
}
}
render(){
return(
<div>
<Input type="text" name='email' value={this.state.emailValue} placeholder={'Write email'} className='someName' changeValue={this.changeEmailValue.bind(this)} />
<Input type="text" name='password' value={this.state.passwordValue} placeholder={'Write password'} className='someName' changeValue={this.changePasswordValue.bind(this)} />
</div>
)
}
changeEmailValue(value){
this.setState({emailValue:value});
}
changePasswordValue(value){
this.setState({passwordValue:value});
}
}
Since you are using a custom component <Input/>, it is likely whatever special code that component has is abstracting away the default event passed from the built-in component <input/>. (note the lower case "i") So maybe you need it to read:
handleEmailChange(value) {
this.setState({email: value});
}
handlePasswordChange(value) {
this.setState({password: value});
}
Regardless the fix is likely that onChange is not returning an event, but some other value you were not expecting.
Instead on binding events in the constructor bind it with the input fields, it will solve your problem.
one more suggestion: you are using two state object, Don't use two separate state variable initialisation, define it like this:
this.state = {
email: '',
password: '',
};
If you use Formik, You should set initialValues for it.
<Formik
initialValues={{
email: '',
password: '',
}}
onSubmit={(values) => {
console.log("formik", values)
}}
>

Categories

Resources