I am attempting to create an edit form in React. I can successfully query my database and can see the data is what is expected after my get request. I then want to set the state of various properties on my component so it fills in my form, which I can then edit.
Here is my react component
constructor(props) {
super(props);
this.state = {
name: '',
teamName: '',
bio: '',
teamId: '',
uploadedFileCloudinaryUrl: ''
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
componentDidMount() {
this.findPlayerById(this.props.params.id)
}
findPlayerById(playerId) {
axios.get("/api/player/" + playerId)
.then(res => {
const player = res.data;
console.log(player);
this.setState({
name: player.name,
teamName: player.teamName,
bio: player.bio,
teamId: player.teamId,
uploadedFileCloudinaryUrl: player.profileImageUrl
});
});
}
And here is my rendered HTML
<div className="form-group">
<label className="control-label">Name</label>
<input type="text" className="form-control" ref="name"
defaultValue={this.state.name}
onChange={this.handleChange.bind(this, 'name')}/>
</div>
I don't get any errors but I don't think the state is being correctly set within my promise. Am I doing something wrong?
Related
I have user data fetched from API, using Redux and I want to display it once component renders and also be able to update it. Currently I have initialValues in interface as:
const initialMultisportList = [
{
multisportType: {
package: '',
type: '',
cost: 0,
},
person: {
name: '',
lastName: '',
type: '',
cooperationForm: '',
},
firmCost: 0,
comment: '',
},
{
multisportType: {
package: '',
type: '',
cost: 0,
},
person: {
name: '',
lastName: '',
type: '',
cooperationForm: '',
},
firmCost: 0,
comment: '',
},
];
const multisportList is state from Redux where data is already fetched from API, it's array of objects.
const { multisportList } = useSelector((state: RootState) => state.employeeMultisport);
This is how I assign multisportList to initialValues.
const { values, handleChange, handleSubmit } = useFormik({
initialValues: multisportList.map((person) => ({
...person,
id: Math.random(),
})),
onSubmit: (values) => {
console.log('submitted');
displayParagraphHandler();
},
});
Below is example how I render two input fields
<StyledSection>
<h3>Benefit Systems</h3>
<form onSubmit={handleSubmit}>
{values.map((person, index) => {
return (
<StyledInputRow key={index}>
<FloatingLabel text="Name" name="Name">
<StyledInputText
id="name"
name="name"
value={values[index].person.name}
onChange={handleChange}
type="text"
/>
</FloatingLabel>
<FloatingLabel text="Last Name" name="Last Name">
<StyledInputText
id="lastName"
name="lastName"
value={values[index].person.lastName}
onChange={handleChange}
type="text"
/>
</FloatingLabel>
</StyledInputRow>
</form>
</StyledSection>
The problem is that all InputFields are empty, initialState is filled with const initialMultisportList , and it's not filled by multisportList. I also cannot update it. Once component is rendered I have also replaced values.map by multisportList.map but it also didn't work.
Can You please suggest how shall I correct my code to make it work ?
thanks
Here is my code, I am using React:
I am using Local Storage in order to persist the state even after page refresh and to remain on the same page.
class App extends React.Component{
constructor(props){
super(props);
this.state = localStorage.getItem("app_state") ? localStorage.getItem("app_state") : {
account: {
email: "",
password: ""
},
errorMessage: "",
token: "",
authenticated: false
};
}
notLoggedInhomePage = () =>{
if(!this.state.authenticated) {
return (
<form onSubmit={this.handleSubmit}>
<br/>
<label>Email Address</label>
<input type="text" value={this.state.account.email} onChange={this.handleChange} name="email"/>
<label>Password</label>
<input type="password" value={this.state.account.password} onChange={this.handleChange} name="password" />
<div>
{this.state.errorMessage}</div>
<br/>
<Button type="submit" onClick={() => {
this.someFunction(String(this.state.account.email));
}}>Sign In</Button>
</form>
);
}else{
return(<Redirect to="/items/somelink" />);
}
}
componentDidUpdate(prevProps, prevState){
if(this.state.token !== prevState.token){ //set a new state if token changes
localStorage.setItem("app_state", this.state);
}
}
}
export default App;
Here is the error that I am getting:
It is saying that the email is undefined, what is the reason behind such error message, and why/how is the email undefined, even though it's defined as an empty string in the state.
What is a possible fix to the above ?
local storage will only return String. not object or array.
you need to parse it before assigning it to state
JSON.parse(localStorage.getItem(app_state))
let appState = localStorage.getItem(app_state)
if(appState) {
appState = JSON.parse(appState)
}
In you code
state = getState()
const getState =() => {
let appState = localStorage.getItem(app_state)
if(appState) {
return JSON.parse(appState)
} else {
return {
account: {
email: "",
password: ""
},
errorMessage: "",
token: "",
authenticated: false
};
}
}
Using setItem inserts a DOMstring value into local storage, getItem returns said DOM string (MDN), when I run your code snippet it returns "[object Object]", you can get around this by using
localStorage.setItem("app_state", JSON.stringify(this.state));
And then retrieving the data as:
this.state = localStorage.getItem("app_state") ? JSON.parse(localStorage.getItem("app_state")) : {
account: {
email: "",
password: ""
},
errorMessage: "",
token: "",
authenticated: false
};
I just started working with React and JSON and require some help. There is a textarea field in which a user enters some data. How to read row-wise the entered text as an array into a JSON variable of the request? Any assistance would be greatly appreciated.
The result I want is
{
id: 3,
name: 'Monika',
birthDay: '1999/01/01',
countryDTO: 'USA',
films: [
'Leon:The Professional',
'Star wars',
'Django Unchained',
],
} ```
My code:
import React from 'react';
import { Form, FormGroup, Label } from 'reactstrap';
import '../app.css';
export class EditActor extends React.Component {
state = {
id: '',
name: '',
birthDay: '',
countryDTO: '',
films: [],
}
componentDidMount() {
if (this.props.actor) {
const { name, birthDay, countryDTO, films } = this.props.actor
this.setState({ name, birthDay, countryDTO, films });
}
}
submitNew = e => {
alert("Actor added"),
e.preventDefault();
fetch('api/Actors', {
method: 'post',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: this.state.name,
birthDay: this.state.birthDay,
countryDTO: {
title: this.state.countryDTO
},
films: [{ title: this.state.films }]
})
})
.then(() => {
this.props.toggle();
})
.catch(err => console.log(err));
this.setState({
id: '',
name: '',
birthDay: '',
countryDTO: '',
films: ''
});
}
onChange = e => {
this.setState({ [e.target.name]: e.target.value })
}
render() {
return <div>
<table>
<tr>
<td colspan="2">
<h3> <b>Add actor</b></h3>
<FormGroup>
<Label for="id">Id: </Label>
<input type="text" name="id" onChange={this.onChange} value={this.state.id} /><p />
<Label for="name">Name:</Label>
<input type="text" name="name" onChange={this.onChange} value={this.state.name} /><p />
<Label for="birthDay">Birth day:</Label>
<input type="text" name="birthDay" onChange={this.onChange} value={this.state.birthDay} placeholder="1990/12/31" /><p />
<Label for="country">Country:</Label>
<input type="text" name="countryDTO" onChange={this.onChange} value={this.state.countryDTO} /><p />
<Label for="Films">Films:</Label>
<textarea name="films" value={this.state.films} onChange={this.onChange} /><p />
</FormGroup>
</td>
</tr>
<tr>
<td>
<Form onSubmit={this.submitNew}>
<button class="editButtn">Enter</button>
</Form>
</td>
</tr>
</table >
</div>;
}
}
export default EditActor;
If you change the below code it will work automatically.
State declaration
this.state = {
name: 'React',
films:["Palash","Kanti"]
};
Change in onechange function
onChange = e => {
console.log("values: ", e.target.value)
this.setState({ [e.target.name]: e.target.value.split(",") })
}
change in textarea
<textarea name="films" value={this.state.films.map(r=>r).join(",")} onChange={this.onChange} />
Code is here:
https://stackblitz.com/edit/react-3hrkme
You have to close textarea tag and the following code is :
<textarea name="films" value={this.state.films} onChange={this.onChange} >{this.state.films}</textarea>
My understanding of your problem is that you would like to have each line in the text area dynamically added as an entry in the films array. This can be achieved as follows:
import React, { Component } from "react";
export default class textAreaRowsInState extends Component {
constructor(props) {
super(props);
this.state = {
currentTextareaValue: "",
films: []
};
}
handleChange = e => {
const { films } = this.state;
const text = e.target.value;
if (e.key === "Enter") {
// Get last line of textarea and push into films array
const lastEl = text.split("\n").slice(-1)[0];
films.push(lastEl);
this.setState({ films });
} else {
this.setState({ currentTextareaValue: text });
}
};
render() {
const { currentTextareaValue } = this.state;
return (
<textarea
defaultValue={currentTextareaValue}
onKeyPress={this.handleChange}
/>
);
}
}
Keep in mind that this method is not perfect. For example, it will fail if you add a new line anywhere other than at the end of the textarea. You can view this solution in action here:
https://codesandbox.io/s/infallible-cdn-135du?fontsize=14&hidenavigation=1&theme=dark
change textarea() tag
to
<textarea name="films" value={this.state.films} onChange={this.onChange} >{this.state.films}</textarea>
You can use split() :
films: {this.state.films.split(",")}
I'm using input type file to upload images to strapi.io. I noticed that in the state on the react dev tools it generate a unnamed state seen in the image below.
state
constructor(props) {
super(props);
this.state = {
first_name: '',
last_name: '',
address: '',
email:'',
city: '',
country: '',
zipcode: '',
gcash_number: '',
paypal_email: '',
error: '',
bank_account: '',
bank_name: ''
}
this.handleOnChange = this.handleOnChange.bind(this)
}
JSX
<div className='col-sm-auto'>
<label htmlFor='avatar' >Avatar</label>
<input type='file' className="form-control-file form-control-sm" onChange={this.handleOnChange('avatar')}/>
</div>
handleOnChange function
handleOnChange = input => (event) => {
if (event.target.type === 'file') {
this.setState({avatars: event.target.files[0]})
}
this.setState({
[event.target.name]: event.target.value
})
}
can some explain to me how this happened? and how to put a state name on that?
this.setState({
[event.target.name]: event.target.value
});
name is undefined
Try
<input name="myInputName" type='file' className="form-control-file form-control-sm" onChange={this.handleOnChange('avatar')}/>
It's better to define an id for the input element:
<input id="InputID" type='file' className="form-control-file form-control-sm" onChange={this.handleOnChange('avatar')}/>
Because you used htmlFor in the label tag
And try the following code :
this.setState({ [event.target.id]: event.target.value });
Normally in HTML you do something like this:
<form>
<input type="text"/>
<input type="text"/>
<input type="submit"/>
</form>
I believe this is not the React way to do it.
Another way to do like i did in my app, is not the best way to do as well i believe.
Like this:
buttonclickRequest(){
var reasonn = document.getElementById("testControl").value;
}
<div>
<FormControl id="testControl"/>
<Button id="btnRequest" onClick={this.buttonclickRequest}/>
</div>
In other stackoverflow topics I saw examples like this:
constructor(props) {
super(props);
this.state = {
firstName: '',
lastName: '',
place: '',
address: '',
email: '',
phoneNumber: ''
};
}
handleClick() {
//do something
}
handleChange = (e) => {
this.setState({
[e.target.id]: e.target.value
})
}
<div>
<input type="text" onChange={e => this.handleChange(e)}/>
<button type="submit" onClick={this.handleClick}/>
</div>
But i have my questions at this point as well,
I don't know how to do this properly with multiple text inputs:
You can make multiple specific changehandlers which is inefficiƫnt,
You can make a changehandler with a switch to set the properties
Is it even efficient to do a handle change on the inputfields? Because I just want the inputfield values when the button is clicked..
This is the form I'm talking about.
So how to properly get the multiple input data with React, when the button is clicked?
Thanks for your help in advance!
I think first you should add name attribute to your input field and use the name to set the state and then use the state on handleClick:
constructor(props) {
super(props);
this.state = {
firstName: '',
lastName: '',
place: '',
address: '',
email: '',
phoneNumber: ''
};
}
handleClick = () => {
//do something
console.log(this.state);
// should be something like this {
// firstName: '',
// lastName: '',
// place: '',
// address: '',
// email: '',
// phoneNumber: ''
//}
}
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.value
})
}
render() {
return(
<div>
<input type="text" name="firstName" onChange={this.handleChange}/>
<input type="text" name="lastName" onChange={this.handleChange}/>
<button type="submit" onClick={this.handleClick}/>
</div>
)
}
Note that the name should match the state key.
Assuming you may be looking for state values
constructor(props) {
super(props);
this.state = {
firstName: '',
lastName: '',
place: '',
address: '',
email: '',
phoneNumber: ''
};
}
handleClick() {
console.log("State ==>", this.state);
}
setFirstName = (e) => {
this.setState({
firstName: e.target.value
})
}
setPhoneNumber = (e) => {
this.setState({
phoneNumber: e.target.value
})
}
render(){
return('
<div>
<label> First Name </label>
<input type="text" name="firstName" onChange={e => this.setFirstName(e)}/>
<label> Phone Number </label>
<input type="text" name="phoneNumber" onChange={e => this.setPhoneNumber(e)}/>
<button type="submit" onClick={this.handleClick}/>
</div>
')
}
and yes... you are right creating change handlers for each input its not efficient on your case, what you need is a react form that gives you the old and submit options,you cant use old form because it needs to update the page to retrieve the values.
I Suggest you to use Antd form witch gives you all in components, i even suggest you to use their Input components witch look very nice and handles pretty well.
Antd Design (User interface components for react) - Antd
some sample code.
give it a try !!! CodeSandbox