class myInfo extends Component {
constructor(props) {
super(props);
this.state = {
name: sessionStorage.getItem('name'),
};
}
componentDidMount() {
axios.post('http://localhost:8080/allProfiles', {
"name": this.state.name
})
.then((response) => {
document.getElementById("email").innerHTML = "email: " + response.data.email;
})
.catch(function (error) {
console.log(error);
});
}
render() {
return (
<div>
<p id="email"></p>
</div>
);
}
}
Noob practising react here. Given the name my rest api would just return a json will all of its profile stuff like
{
"email": ...
"description: ...
}
For simplicity it will just get the email for now. The output of this page at the moment is
email: userFromThisSession#gmail.com
All in text. My goal is
image
Without the fancy css^^
So its the username for above image but same concept for email. I want
email: a textbox (has the email from above) (and then a button to edit it)
Anyone know how? I've been searching for a while but no luck
example
class Info extends Component {
constructor(props) {
super(props);
this.state = {
name: ""
};
this.handleChange = this.handleChange.bind(this);
this.updateIsEdit = this.updateIsEdit.bind(this);
}
handleChange(e) {
this.setState({
name:e.target.value
})
}
updateIsEdit(e, value="null") {
this.setState({
isEdit: value
});
}
render() {
return (
<div>
<input type="text" name="userName" value={this.state.name} placeholder="Enter your name..." onChange={this.handleChange} onBlur={this.updateIsEdit}/>
<img src="https://img.icons8.com/android/24/000000/edit.png" className="edit" />
<p id="name">{this.state.name}</p>
</div>
);
}
}
render(<Info />, document.getElementById('root'));
What I would do is make a component that is a simple <span> that becomes a textbox when you click on the icon:
/// inside your render() method:
(this.state.editMode)
? <input className='edit-email' type='text' value={ this.state.email || '' } onBlur={this.toggleEditEmail} />
: <>
<span className='edit-email' >{ this.state.email }</span>
<img href="edit.png" onClick={this.toggleEditEmail} />
</>
/// Toggle function:
toggleEditEmail() {
this.setState({ editMode: !this.state.editMode });
}
You would have to then match the style of the <span> and <input> so that the input doesn't show the usual border, width, etc.
Also, note that you shouldn't need to set the HTML node directly:
document.getElementById("email").innerHTML = "email: " + response.data.email;
The React way of doing it is by setting the state:
this.setState({ email: response.data.email });
The render() I posted above will then use the email coming from this.state.
Related
I am trying to update my state by using a click function. However for some reason it is not updating. Could someone please explain to me what I am doing wrong?class Textbox extends
Component {
constructor(props) {
super(props);
this.handle = this.handle.bind(this);
this.state = {
text: 'jkjkljkljl'
}
}
handle(event) {
const myValue = event.target.value;
this.setState({
text: myValue
})
console.log(this.state)
}
render() {
return (
<div>
<textarea className="Textbox" rows="2" cols="30" type = "text" >
</textarea>
<button className="postbutton" onClick={this.handle.bind(this)}>Post</button>
<h1>{this.state.text}</h1>
</div>
);
}
}
export default Textbox;
Here is an updated version of your code that works.
Issue was that you were trying to set the value of the button to the state.
What you should do is setup textarea as a controlled input (have value and onChange setup as I did below) and use that value on click.
class Component extends React.Component {
constructor(props) {
super(props);
this.state = {
textArea: "",
text: "jkjkljkljl"
};
}
handle(event) {
console.log(event);
this.setState({
text: this.state.textArea
});
console.log(this.state);
}
handleChange(event) {
this.setState({ textArea: event.target.value });
}
render() {
return (
<div>
<textarea
className="Textbox"
rows="2"
cols="30"
value={this.state.textArea}
onChange={this.handleChange.bind(this)}
/>
<button className="postbutton" onClick={this.handle.bind(this)}>
Post
</button>
<h1>{this.state.text}</h1>
</div>
);
}
}
It seems you are trying to handle a form using React/JSX. There are great libraries for this purpose (React Forms).
This is the proper code:
class App extends React.Component {
constructor(props) {
super(props);
this.handle = this.handle.bind(this);
this.state = {
text: 'Static'
}
}
handleOnChange(event) {
this.setState({text: event.target.value});
}
handleSubmit(event) {
if (event.keyCode == 13) return this.sendData();
}
render() {
return (
<div>
<form onKeyUp={this.handleOnChange}>
<textarea className="Textbox"
rows="2" cols="30" type="text"
>
</textarea>
<button className="postbutton"
onClick={this.handleSubmit.bind(this)}>
Post
</button>
</form>
<h1>{this.state.text}</h1>
</div>
);
}
}
React.render(<App />, document.getElementById('app'));
In your example, you are binding the state to the root of the button and not the textarea. If you want a static example (whereas the above code changes as you type), you may simply handle the enter key via if (event.keyCode == 13) return this.sendData() and remove the onChange.
I want to pass props from AddPost component to AllPosts component only when button is clicked in AddPost.
Plus how to keep on adding new posts' data(post,title,keyid) from AddPost in a object "newArray" in AllPosts every time button is clicked and this new data gets saved in allposts array and then every post is displayed by applying map function on it.
I am facing problem about how can I get new data from AddPost in newObject and continuously keep pushing this in allposts array?
AddPost.js
class Addpost extends Component {
constructor(props) {
super(props);
this.state = {
title : '',
post : '',
keyid : 0
}
this.handleClick = this.handleClick.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({
[event.target.name] : event.target.value
})
}
handleClick() {
this.setState(prevState => ({
keyid : prevState.keyid + 1,
post : '',
title : ''
}));
console.log(this.state.keyid);
}
render() {
return(
<div>
<input type="text" name="title" value={this.state.title} onChange={this.handleChange} maxLength="30" placeholder="Title here" />
<input type="text" name="post" value={this.state.post} onChange={this.handleChange} maxLength="200" placeholder="Post here" />
<input type="button" onClick={this.handleClick} value="Add Post" />
<Allposts post={this.state.post} title={this.state.title} keyid={this.state.keyid} />
</div>
)
}
}
AllPosts.js
class Allposts extends Component {
constructor(props) {
super();
this.state = {
newObject : {
post : '',
title : '',
keyid : ''
},
allPosts : []
}
}
render() {
return (
this.state.allPosts.map((post) =><div>
{ post.post}{post.title}{post.keyid}
</div>
)
)
}
}
A better way to solve your problem would be to keep AllPosts and Addpost component isolated and rendered by their component Parents
post.js
class Post extends React.Component {
state: {
allPosts: []
}
addPost = (post) => {
this.setState(prev => ({allPosts: prev.allPosts.concat([post])}))
}
render() {
<>
<Addpost addPost={this.addPost}/>
<AllPosts allPosts={this.state.allPosts} />
</>
}
}
Addpost.js
class Addpost extends Component {
constructor(props) {
super(props);
this.state = {
title : '',
post : '',
keyid : 0
}
this.handleClick = this.handleClick.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({
[event.target.name] : event.target.value
})
}
handleClick() {
const { keyid, post, title } = this.state;
const post = { keyid, post, title };
this.props.addPost(post)
this.setState(prevState => ({
keyid : prevState.keyid + 1,
post : '',
title : ''
}));
}
render() {
return(
<div>
<input type="text" name="title" value={this.state.title} onChange={this.handleChange} maxLength="30" placeholder="Title here" />
<input type="text" name="post" value={this.state.post} onChange={this.handleChange} maxLength="200" placeholder="Post here" />
<input type="button" onClick={this.handleClick} value="Add Post" />
</div>
)
}
}
Allposts.js
const Allposts = () => {
return (
this.props.allPosts.map((post) => (
<div>
{ post.post} {post.title} {post.keyid}
</div>
))
)
}
However if you want to pass props only after clicking, you would need to maintain a state that says clicked or not. and then pass props like
const { clicked, post, keyid, title } = this.state;
const newProp = { post, keyid, title };
<AllPost {...(clicked? newProps: {})} />
I am new to react and I can fetch the result from form input fields. Now I need to update those values and submit to the backend. I am struggling to find a way to pass all the input field values at once.
constructor(props) {
super(props);
this.state = {
items: [],
isLoaded: false,
data: this.props.location.data
};
}
render() {
return (
<div>
<h2>Update Your Profile</h2>
{items.map(item => (
<Form key={item.uId} onSubmit={this.handleSubmit}>
<label>User Name</label>
<input type="text" defaultValue={item.userName}></input>
<label>Email address</label>
<input type="email" defaultValue={item.email}></input>
</div>
<button type="submit" >Update</button>
</Form>
))}
</div>
);
}
handleSubmit = (e) => {
e.preventDefault();
axios.put('http://localhost:3000/api/user/' + this.state.data, this.state.items).then(response => {
//
});
};
My API call looks like this:
app.put('/api/user/:userId', (req, res, err) => {
User.update(
{ userName: req.body.userName, email: req.body.email },
{
where: {
userId: req.params.userId
}
}
).then(function (rowsUpdated) {
res.json(rowsUpdated)
}).catch(err);
});
How can I modify this code to set a value for this.state.items with all the updated fields values and submit it?
I'd recommend to create a new component to wrap around the <Form /> and move the submit/change event handling to that component for each item. This would allow you to be able to extract individual email/userName for any given <Form /> to send as a PUT to your API endpoint as well as handle the respective input value changes.
Parent Component:
class Parent extends Component {
constructor() {
super();
this.state = {
name: 'React',
items: [
{ uId: 1, email: 'foo#test.com', userName: 'bar' },
{ uId: 2, email: 'baz#test.com', userName: 'foobar' }
]
};
}
render() {
return (
<div>
{this.state.items.map(item =>
<MyForm key={item.uId} item={item} data={this.props.location.data} />)}
</div>
);
}
}
Child/Form Component:
import React, { Component } from 'react';
class MyForm extends Component {
constructor(props) {
super(props);
this.state = {
email: this.props.item.email,
userName: this.props.item.userName
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
// https://reactjs.org/docs/forms.html#handling-multiple-inputs
handleChange(e) {
const { target} = event;
const value = target.type === 'checkbox' ? target.checked : target.value;
const { name } = target;
this.setState({ [name]: value });
}
handleSubmit(e) {
e.preventDefault();
const { email, userName } = this.state;
const body = { email, userName };
const json = JSON.stringify(body);
console.log(json);
// axios.put('http://localhost:3000/api/user/' + this.props.data, json).then(response => {});
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>User Name</label>
<input type="text" defaultValue={this.state.userName}></input>
<label>Email address</label>
<input type="email" defaultValue={this.state.email}></input>
<button type="submit" >Update</button>
</form>
);
}
}
export default MyForm;
Here is an example in action.
Hopefully that helps!
I'm not sure what kind of problem this is, but I have a state.sports which contains some data about sports. I added new data to this object and then I tried to render it on the DOM with this component.
class AddProject extends Component {
constructor() {
super();
this.state = {
newSport:{}
}
this.handleSubmit = this.handleSubmit.bind(this);
}
static defaultProps = {
Types:['air','aquatic','land']
}
handleSubmit(e){
if (!this.refs.sport.value) {
alert("title required");
} else {
this.setState({
newSport:{
sport: this.refs.sport.value,
type: this.refs.type.value
}
},function() {
this.props.addSport(this.state.newSport);
});
}
e.preventDefault();
}
render() {
let typeOptions = this.props.Types.map(type => {
return <option key={type} value={type}>{type}</option>
});
return (
<div className="addproject">
<h3>Add project </h3>
<form onSubmit={this.handleSubmit}>
<div>
<label>Sport </label><br/>
<input type="text"
key="sport"
ref="sport"
placeholder="Add project" />
</div>
<div>
<label>Type</label><br/>
<select ref='type'>
{typeOptions}
</select>
</div>
<input type='submit' value='Submit' />
</form>
</div>
);
}
}
export default AddProject;
Then I added this formatted data into a list with this component:
class Project extends Component {
render() {
let Sports;
//check if there is data in props.sports which is bind to state.sports
if (this.props.sports) {
Sports = this.props.sports.map(sport => {
return (
//after some expirements i found that the key is the cause of the problem
<ProjectItems key={sport.name} sport={sport} />
);
});
}
return (
<div className="project">
<h1>List </h1>
<ul>
{Sports}
</ul>
</div>
);
}
}
Then ProjectItems formats the data into name of the sport and type of sport. Anyway when I enter some data it only renders the type of sport and the sport's name returns undefined, like here. Can you tell me what's wrong ?
It would be more clear if you gave code of ProjectItems class, but at first glance it looks like in handleSubmit method you sholud change this:
newSport:{
sport: this.refs.sport.value,
type: this.refs.type.value
}
to this:
newSport:{
name: this.refs.sport.value,
type: this.refs.type.value
}
maybe what you want to achieve is set a nested object properties on the state.
use this:
this.setState(
{newSport:
update(this.state.newSport,
{type: {$set: this.refs.type.value}},
{name: {$set: this.refs.sport.value}}
)
});
the sports JSON structure will be:
newSport: {type: "air", name: "land"}
the
then you can display the sports:
this.props.sports.map(sport => {
return (
//the key will not be a problem, since now it has values in it.
<ProjectItems key={sport.name} sport={sport} />
);
I have a Component that is handling a contact forum submission from a user. I want to take the state that the user submits and add it to my props data. Right now everything is working, but the handleSubmit, I am not sure how to take the state and pass it to my this.data.props to update the data to include the new object.
My data is an array of Objects. The state takes user input and updates itself. Next I want to take the state object and add it to my props.data and then display it on the screen.
EDIT: UPDATED WITH LATEST CODE
import React, { Component, PropTypes } from 'react';
const testData = [
{
name: 'Joe',
email: 'joemail'
},
{
name: 'Bill',
email: 'billmail'
},
{
name: 'Dude',
email: 'dudemail'
}
]
class FormContact extends Component {
constructor(props) {
super(props)
this.state = {
formValues: {
name: '',
email: ''
}
}
}
handleChange(event) {
let formValues = this.state.formValues;
let name = event.target.name;
let value = event.target.value;
formValues[name] = value;
this.setState({
formValues
});
}
handleSubmit(event) {
event.preventDefault();
console.log("NEW FORM VALUES " + this.state.formValues.name + " " + this.state.formValues.email);
const {name, email} = this.state.formValues
this.props.addContact({name, email});
}
render() {
return (
<form onSubmit={this.handleSubmit.bind(this)}>
<label> Name:
<input type="text" name="name" placeholder="Name" value={this.state.formValues["name"]} onChange={this.handleChange.bind(this)} />
</label><br />
<label> Email:
<input type="text" name="email" placeholder="Email" value={this.state.formValues["email"]} onChange={this.handleChange.bind(this)}/>
</label><br />
<input className="btn btn-primary" type="submit" value="Submit" />
</form>
)
}
}
FormContact.PropTypes = {
data: PropTypes.arrayOf(
PropTypes.object
)
}
FormContact.defaultProps = {
data: testData
}
class Contact extends Component {
constructor(props) {
super(props)
this.state = {
data: testData
}
}
addContact(contact) {
this.setState({data: this.state.data.concat(contact)});
}
render() {
const renObjData = this.props.data.map( (anObjectMapped, index) => {
return (<p key={index}>
Name: {anObjectMapped.name} < br/>
Email: {anObjectMapped.email} <br /></p>
)
});
return (
<div>
<h1>CONTACT PAGE</h1>
<FormContact data={this.state.data} addContact={this.addContact.bind(this)} />
{renObjData}
</div>
)
}
}
Contact.PropTypes = {
data: PropTypes.arrayOf(
PropTypes.object
)
}
Contact.defaultProps = {
data: testData
}
export default Contact;
What you are looking at here is having a parent container that passes down data as props to the form component. You already have your Contact component so you can make it hold the data state.
How it would work is you would write a function on the Contact component called addContact and it would take a contact as an argument and then set its own state with the new contact IE concat it to its own data array through setting state.
class Contact extends React.Component {
constructor() {
super();
this.state = {
data: testData
}
}
addContact = (contact) => {
this.setState({data: this.state.data.concat(contact)});
};
render() {
const contacts = _.map(this.state.data, (value, index) => {
return <li key={index + value}> {value.email} {value.name} </li>
})
return (
<div>
<h1>CONTACT PAGE</h1>
<FormContact data={this.state.data} addContact={this.addContact} />
<h3> Contacts</h3>
<ul>{contacts} </ul>
</div>
)
}
}
and then in your handleSubmit function all you have to do is add
handleSubmit(event) {
event.preventDefault();
const {name, email} = this.state.formValues
this.props.addContact({name, email})
}
this will push it onto the data array in the parent component and then once the parent component updates it will pass that down as props to the form component.
Here is a code pen showing all that in action. http://codepen.io/finalfreq/pen/VKPXoN
UPDATE: Also in Contacts added how to display data, you can easily replace lodash _.map with this.state.data.map(function(value, index)