Add data to the page without refreshing it in React - reactjs

I've posted this question earlier, but probably not quite clearly formulated it. I have a chat. When I add message it goes to database but not updated on page. So I need it to be updated on page after adding a msg.
Parent component Forms
export default class Forms extends Component {
constructor() {
super()
this.state = {
messages: [],
}
this.sendMessage = this.sendMessage.bind(this);
}
componentDidMount(){
client1.getEntries({limit:300, order: 'sys.createdAt',
content_type:'nameTest'}).then(response => {
this.setState({messages: response.items});
}).catch(e => {
console.log(e);
});
}
sendMessage(data) {
client2.getSpace(client2.space)
.then((space) => space.getEnvironment('master'))
.then((environment) => environment.createEntry('nameTest', {
fields: {
chatName: {
'en-US': data.get('chatName')
... some data
}
}))
.then((entry) => entry.publish())
.catch(console.error)
}
render() {
return (
<div className="chat">
<div className="container-xl">
<MessageList messages={this.state.messages}/>
<SendMsg onSendMessage={this.sendMessage}/>
</div>
</div>
);
}
}
the child component SengMsg
export default class SendMsg extends Component {
constructor() {
super()
this.state = {
message:'',
userEmail:'ddd#gmail.com',
chatName:'ggg'
}
this.sendMessage = this.sendMessage.bind(this)
this.handleChange = this.handleChange.bind(this)
}
handleChange(e) {
this.setState({
message: e.target.value,
})
}
sendMessage(e) {
e.preventDefault();
const { onSendMessage } = this.props;
const form = e.target;
const data = new FormData(form);
// if send message handler was passed, invoke with form data
onSendMessage && onSendMessage(data);
this.setState({
message: ''
})
}
render() {
return (
<div className="send-message">
<Form className="send-msg" onSubmit={this.sendMessage}>
<FormGroup>
<Input type="hidden" name="userEmail" value={this.state.userEmail}/>
</FormGroup>
<FormGroup>
<Input type="hidden" name="chatName" value={this.state.chatName}/>
</FormGroup>
<FormGroup>
<Input
type="text"
name="text"
onChange={this.handleChange}
value={this.state.message}
placeholder="Write your message here"
required />
</FormGroup>
<FormGroup>
<Input type="hidden" name="dateCreated" value={moment().format()} onChange={this.handleChange}/>
</FormGroup>
</Form>
</div>
);
}
}

Related

Basic Form react

Hello I just want to make a form and my textboxes does not take my inputs and my submit works but sends no values. What am I doing wrong? I know it's a basic question but I don't know what the problem is in my code.
Key problems:
it doesn't update the state nor take my inputs.
fields editable but cant write into them
Code
import React, { Component } from "react";
class Postform extends Component {
constructor(props) {
super(props);
this.state = {
name: "",
category: "",
price: "",
};
}
changeHandler = (e) => {
this.setState = { [e.target.name]: e.target.value };
};
submitHandler = (e) => {
e.preventDefault();
console.log(this.state);
};
render() {
const { name, category, price } = this.state;
return (
<div>
<form onSubmit={this.submitHandler}>
<div>
<input
type="text"
name="name"
placeholder="Name"
value={name}
onChange={this.changeHandler}
/>
<input
type="text"
name="category"
placeholder="Category"
value={category}
onChange={this.changeHandler}
/>
<input
type="text"
name="price"
placeholder="Price"
value={price}
onChange={this.changeHandler}
/>
</div>
<button type="submit">Add product</button>
</form>
</div>
);
}
}
export default Postform;
Change this line to
changeHandler = e => {
this.setState({[e.target.name]: e.target.value });
};
Since setState is a function it is not a property !

Passing submitted form data to another component

I have the following code, it basically accepts some basic input and when submit button is clicked user is notified with an alert, state is constantly being updated via onChange event. What i wonder is can i somehow pass the retrieved data to another component inside the event handler for submit button (which i have called handleFormSubmit)? I have recently seen react has something called 'context' ...maybe that would be best here? Advice please? :)
class Form extends Component {
constructor(props) {
super(props)
this.state = {
username: '',
comments: '',
topic: 'react'
}
this.handleUsernameChange = this.handleUsernameChange.bind(this);
this.handleCommentsChange = this.handleCommentsChange.bind(this);
this.handleTopicChange = this.handleTopicChange.bind(this);
this.handleFormSubmit = this.handleFormSubmit.bind(this);
}
handleUsernameChange(event){
this.setState({
username: event.target.value
},
() =>{
console.log(this.state.username)
})
}
handleCommentsChange(event){
this.setState({
comments: event.target.value
},
() =>{
console.log(this.state.comments)
})
}
handleTopicChange(event){
this.setState({
topic: event.target.value
},
() =>{
console.log(this.state.topic)
})
}
handleFormSubmit(event){
event.preventDefault();
alert(`${this.state.username} ${this.state.comments} ${this.state.topic}`);
}
render() {
return (
<form onSubmit={this.handleFormSubmit}>
<div>
<label>Username</label>
<input type='text' value={this.state.username} onChange={this.handleUsernameChange}/>
</div>
<div>
<textarea value={this.state.comments} onChange={this.handleCommentsChange}></textarea>
</div>
<div>
<select value={this.state.topic} onChange={this.handleTopicChange}>
<option value="react">React</option>
<option value="angular">Angular</option>
<option value="vue">Vue</option>
</select>
</div>
<button>Submit</button>
</form>
)
}
}
Hi all i made some changes and got something working, added extra state attribute called dataSubmitted set it to false then only after i submit the data is child (which i called AcceptFormData) allowed to render and i pass the state attributes as props. I do not know if this is a good approach or not but it works and no console errors.
class Form extends Component {
constructor(props) {
super(props)
this.state = {
username: '',
comments: '',
topic: 'react',
dataSubmitted: false
}
this.handleUsernameChange = this.handleUsernameChange.bind(this);
this.handleCommentsChange = this.handleCommentsChange.bind(this);
this.handleTopicChange = this.handleTopicChange.bind(this);
this.handleFormSubmit = this.handleFormSubmit.bind(this);
}
handleUsernameChange(event){
this.setState({
username: event.target.value
},
() =>{
console.log(this.state.username)
})
}
handleCommentsChange(event){
this.setState({
comments: event.target.value
},
() =>{
console.log(this.state.comments)
})
}
handleTopicChange(event){
this.setState({
topic: event.target.value
},
() =>{
console.log(this.state.topic)
})
}
handleFormSubmit(event){
event.preventDefault();
this.setState({
dataSubmitted: true
})
}
render() {
if(this.state.dataSubmitted === false){
return (
<form onSubmit={this.handleFormSubmit}>
<div>
<label>Username</label>
<input type='text' value={this.state.username} onChange={this.handleUsernameChange}/>
</div>
<div>
<textarea value={this.state.comments} onChange={this.handleCommentsChange}></textarea>
</div>
<div>
<select value={this.state.topic} onChange={this.handleTopicChange}>
<option value="react">React</option>
<option value="angular">Angular</option>
<option value="vue">Vue</option>
</select>
</div>
<button>Submit</button>
</form>
)
}else{
return (
<AcceptFormData username={this.state.username} comments={this.state.comments} topic={this.state.topic}/>
)
}
}
}
export default Form

How to pass Child Component's form value to Parent Component

Is there a way to pass form data from child component to Parent component, where submit buttons have been kept in parent component.
NOTE: - I don't want to use ref for this as the ref would be waste of so much of memory and I might have 6-7 children in the parent.
I have created a similar situation to show what I am stuck on.
class FirstChildForm extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
}
}
render() {
return (
<div className="form">
<input type="text" placeholder="Enter your name..." />
<input type="password" placeholder="Enter password" />
</div>
)
}
}
class SecondChildForm extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
}
}
render() {
return (
<div className="form">
<input type="text" placeholder="Enter your name..." />
<input type="password" placeholder="Enter password" />
</div>
);
}
}
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
}
}
handleSubmit = () => {
}
render() {
return (
<div className="parent">
<FirstChildForm />
<SecondChildForm />
<button onClick={this.handleSubmit}> Submit</button>
</div>
)
}
}
Sure, the concept is called lifting the state up. Basically, your <App /> component would hold the data from both components. I'm going to simplify a bit, but you should understand what I'm doing.
FirstChildForm.js
<input type="text" name="username" onChange={e => props.updateData('user', e.target.value)}
SecondChildForm.js
<input type="password" name="password" onChange={e => props.updateData('pass', e.target.value)}
App.js
export default class App extends React.Component {
constructor() {
super();
this.state = {
user: '',
pass: '',
};
}
handleSubmit = () => {};
updateData = (target, value) => {
this.setState({ [target]: value });
};
render() {
return (
<div className="parent">
<FirstChildForm updateData={this.updateData} />
<SecondChildForm updateData={this.updateData} />
<button onClick={this.handleSubmit}> Submit</button>
</div>
);
}
}
The <App /> component is the source of truth. Please note:
By lifting the state up, <FirstChildForm /> and <SecondChildForm /> don't need to be class based components anymore, they can be functional components. If you want them to remain class based for whatever reason, change props.updateData to this.props.updateData, else it won't work.
The parent is where we define the function, the child is where we execute it, sending data to parent, basically!
by passing a function to the child component as props and passing the child component's state as parameter to the function
as i dont know what you exactly want to code inside but only to understand checkout
following example
parent:
export default class App extends React.Component {
constructor(props){
super(props);
this.state = {
data: []
}
}
handleSubmit = () => {
}
handleData = (newData) => {
this.setState({data: newData});
}
render(){
return (
<div className="parent">
<FirstChildForm / >
<SecondChildForm onSelectData={this.handleData}/>
<button onClick={this.handleSubmit}> Submit</button>
</div>
)
}
}
Child:
class SecondChildForm extends React.Component{
constructor(props){
super(props);
this.state = {
data:'hello'
}
}
handleDataChange: function () {
var newData = this.state.data
this.props.onSelectData(newData);
},
render(){
return (
<div className="form">
<input type="text" placeholder="Enter your name..." />
<input type="password" placeholder="Enter password" />
<button onclick={this.handleDataChange}>submit</button>
</div>
);
}
}
You will have to pass a function down to your children components. Your children will now be able to bind this function from their props to the given fields.
class FirstChildForm extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
}
}
render() {
return (
<div className="form">
<input type="text" placeholder="Enter your name..." onChange={this.props.dataChanged('name')}/>
<input type="password" placeholder="Enter password" onChange={this.props.dataChanged('password')}/>
</div>
)
}
}
class SecondChildForm extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
}
}
render() {
return (
<div className="form">
<input type="text" placeholder="Enter your name..." onChange={this.props.dataChanged('name')}/>
<input type="password" placeholder="Enter password" onChange={this.props.dataChanged('password')}/>
</div>
);
}
}
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
}
}
handleChange = form => field => ev => {
this.setState(prev => ({ [form]: { ...prev[form], [field]: ev.target.value } }))
}
The resulting state of your parent will have the following structure :
{
'firstForm': {
'name': '',
'password': ''
},
'secondForm': {
'name': '',
'password': ''
}
}

React - Login Error from PHP not displaying

I am trying to display an error text message fetched from a PHP. I see from debugging that the message is returned correctly in the responseJson.message object but I'm not able to find out whether the state is updating it or why it is not rendering properly in the HTML since the page reloads itself and the input fields are emptied right after the this.setState({ error: responseJson.message }) instruction.
import React, { Component } from "react";
import { PostData } from '../../modules/PostData';
class LoginForm extends Component {
constructor() {
super()
this.state = {
error: "",
username: "",
password: ""
}
this.onSubmit = this.onSubmit.bind(this)
this.onChange = this.onChange.bind(this)
}
onSubmit() {
this.setState({ error: "" })
PostData('login', this.state).then((responseJson) => {
if (responseJson.message === "login success") {
sessionStorage.setItem('userData', JSON.stringify(responseJson));
document.location.href = `/home`
} else {
console.log(this.state.error)
this.setState({ error: responseJson.message })
}
})
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value })
}
render() {
return (
<form onSubmit={this.onSubmit}>
<div>
<label htmlFor="username">Username:</label><br />
<input name="username" component="input" type="text" onChange={this.onChange}/>
</div>
<div>
<label htmlFor="password">Password:</label><br />
<input name="password" component="input" type="password" onChange={this.onChange}/>
</div>
<div>
<button type="submit">Login</button>
</div>
<div name="error" className='error' component="input" type="text" value={this.state.error}></div>
</form>
)
}
}
export default LoginForm
Thanks for the help!
There is no component, value, type attributes in div tag. In your case you should use:
<div name="error" className='error'>{this.state.error}</div>
or
<input name="error" className='error' component="input" type="text" value={this.state.error}></input>

More compact way to write onChange handler for form with many inputs that affect nested state properties?

What is a more compact and more easy way to write a handleChange function for multiple input than the following:
import React from "react";
function initialState() {
return ({
customer: {
name: '',
primaryContactPerson: {
name: '',
email: ''
}
}
})
}
export default class AddCustomerForm extends React.Component {
constructor(props) {
super(props);
this.state = initialState();
this.handleChange = this.handleChange.bind(this);
}
handleChange(event, field) {
console.log(event.target.name);
switch(event.target.name) {
case 'customer.name':
console.log(1);
this.setState({
this: {
customer: {
name: event.target.value
}
}
})
break;
case 'customer.primaryContactPerson.name':
console.log(2);
this.setState({
this: {
customer: {
primaryContactPerson: {
name: event.target.value
}
}
}
})
break;
case 'customer.primaryContactPerson.email':
this.setState({
this: {
customer: {
primaryContactPerson: {
email: event.target.value
}
}
}
})
break;
default:
break;
}
this.setState({[event.target.name]: event.target.value});
}
render() {
return (
<div className='section section--full-width'>
<h1>Add Customer</h1>
<form onSubmit={this.handleSubmit}>
<div className='form__row'>
<label>
Customer name
</label>
<input type="text" name="customer.name" value={this.state.customer.Name} onChange={this.handleChange} />
</div>
<div className='form__row'>
<label>
Contact person
</label>
<input type="text" name="customer.primaryContactPerson.name" value={this.state.customer.primaryContactPerson.name} onChange={this.handleChange} />
</div>
<div className='form__row'>
<label>
Contact details
</label>
<input type="text" name="customer.primaryContactPerson.email" value={this.state.customer.primaryContactPerson.email} onChange={this.handleChange} />
</div>
<div>
<input type="submit" value="Add" />
</div>
</form>
</div>
);
}
}
I have tried the following method that does not work for nested objects:
handleChange(event, field) {
this.SetState({event.targetname: event.target.value})
}
One dirty hack is using lodash _.set Link. This is not the recommended method only a workaround.
you can use
const tmp = this.state;
_.set(tmp, event.target.name, event.target.value);
this.setState({ customer: tmp.customer });
if you want to avoid direct state mutation you can also use
const tmp = _.cloneDeep(this.state)
this process will be slower.

Resources