trouble getting data from react input form - javascript

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! 👍

Related

handleSubmit function appears to be refreshing page without firing any internal logic

The handleSubmit function seems to refresh the page without firing any of the internal logic. I've set up a few console.log's along the way to test out if the internally declared const that's set to the venue property in the state would log, but nothing appears.
I've commented on various parts of the function stepwise starting with setting the scheduling variable to my Firebase schedule table.
After that, I changed the handleSubmit function from an arrow function to just handleSubmit(e) (sorry, I'm new to this so I'm not familiar with the terminology)
import React, {Component} from 'react';
import FrontNav from './nav.js';
import firebase from '../Firebase';
class FrontSchedule extends Component {
constructor () {
super();
this.state = {
venue:'',
}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange = (e) => {
e.preventDefault();
this.setState ({
venue: e.target.value,
});
}
handleSubmit = (e) => {
e.preventDefault();
// let schedule = firebase.database().ref('schedule')
const item = {
venue: this.state.venue,
}
console.log(item);
// schedule.push(item);
// console.log(firebase.database().ref('schedule'));
console.log(this.state.venue);
// this.setState({
// venue:'',
// })
}
render(){
return(
<div>
<FrontNav/>
<h1>Schedule</h1>
<form>
<input type="text"
name="venue"
onChange={this.handleChange}
onSubmit={this.handleSubmit}
value={this.state.venue}/>
<button onSubmit={this.handleSubmit}> Enter Event </button>
</form>
</div>
);
}
}
export default FrontSchedule;
Herein lies the crux of the problem. The page refreshes and the input bar clears, but no error message is provided. At this point, I'm really confused about what is going on here. Any feedback is appreciated!
Let us consider the following example:-
<form>
<label>
Name:
<input type="text" name="name" />
</label>
<input type="submit" value="Submit" />
</form>
Now, when we press on submit button the default behavior to browse to a new page. If you want this behavior it works out of the box in ReactJS. But in cases where you need more sophisticated behavior like form validations, custom logic after the form is submitted you can use controlled components.
We can do so by using following:-
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
Now coming to your solution it can be implemented as follows:-
class FrontSchedule extends React.Component {
constructor () {
super();
this.state = {
venue:'',
}
/* this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this); */
}
handleChange = (e) => {
e.preventDefault();
this.setState ({
venue: e.target.value,
});
}
handleSubmit = (e) => {
event.preventDefault();
// let schedule = firebase.database().ref('schedule')
const item = {
venue: this.state.venue,
}
console.log(item);
// schedule.push(item);
// console.log(firebase.database().ref('schedule'));
console.log(this.state.venue);
// this.setState({
// venue:'',
// })
}
render(){
console.log(this.state);
return(
<div>
<h1>Schedule</h1>
<form onSubmit={this.handleSubmit}>
<input type="text"
name="venue"
onChange={this.handleChange}
onSubmit={this.handleSubmit}
value={this.state.venue}/>
<input type="submit" value="Submit"/>
</form>
</div>
);
}
}
ReactDOM.render(<FrontSchedule />, document.querySelector("#app"))
Hope it helps :)
You can read more at react documentationhere

ReactJS: Dynamically add a component on click

I have a menu button that when pressed has to add a new component. It seems to work (if I manually call the function to add the components they are shown). The problem is that if I click the button they are not shown, and I suppose because I should use setState to redraw them. I am not sure how to call the setState of another component within another function/component.
This is my index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import Menu from './Menu';
import * as serviceWorker from './serviceWorker';
import Blocks from './Block.js';
ReactDOM.render(
<div className="Main-container">
<Menu />
<Blocks />
</div>
, document.getElementById('root'));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers:
serviceWorker.unregister();
Then I have the Menu.js
import React from 'react';
import './Menu.css';
import {blocksHandler} from './Block.js';
class Menu extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleAdd = this.handleAdd.bind(this);
}
handleAdd(event) {
blocksHandler.add('lol');
console.log(blocksHandler.render());
}
render() {
return (
<div className="Menu">
<header className="Menu-header">
<button className="Menu-button" onClick={this.handleAdd}>Add block</button>
</header>
</div>
);
}
}
export default Menu;
And finally the Block.js
import React from 'react';
import './Block.css';
// this function adds components to an array and returns them
let blocksHandler = (function() {
let blocks = [];
return {
add: function(block) {
blocks.push(block);
},
render: function() {
return blocks;
}
}
})();
class Block extends React.Component {
constructor(props) {
super(props);
this.state = {
title: '',
content: ''
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({[event.target.name]: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.title);
event.preventDefault();
}
render() {
return (
<div className="Block-container">
<form onSubmit={this.handleSubmit}>
<div className="Block-title">
<label>
Block title:
<input type="text" name="title" value={this.state.value} onChange={this.handleChange} />
</label>
</div>
<div className="Block-content">
<label>
Block content:
<input type="text" name="content" value={this.state.value} onChange={this.handleChange} />
</label>
</div>
<input type="submit" value="Save" />
</form>
</div>
);
}
}
class Blocks extends React.Component {
render() {
return (
<div>
{blocksHandler.render().map(i => (
<Block key={i} />
))}
</div>
)
}
}
export default Blocks;
export {blocksHandler};
I am a React complete beginner so I'm not even sure my approach is correct. Thank you for any help you can provide.
Below I've knocked up a really simple Parent / Child type setup,..
The Parent is responsible for rendering the Buttons, I just used a simple numbered array here. When you click any of the buttons, it calls the setState in the Parent, and this in turns causes the Parent to re-render it's Children.
Note: I've also used React Hooks to do this, I just find them more
natural and easier to use. You can use Classes, the same principle
applies.
const {useState} = React;
function Child(props) {
const {caption} = props;
const {lines, setLines} = props.pstate;
return <button onClick={() => {
setLines([...lines, lines.length]);
}}>
{caption}
</button>;
}
function Parent(props) {
const [lines, setLines] = useState([0]);
return lines.map(m => <Child key={m} caption={`Click ${m}`} pstate={{lines, setLines}}/>);
}
ReactDOM.render(<React.Fragment>
<Parent/>
</React.Fragment>, document.querySelector('#mount'));
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="mount"></div>
Instead of creating blocksHandlers as a separate function ,you can have it nside the Menu.js like as follows
*
class Block extends React.Component {
constructor(props) {
super(props);
this.state = {
title: '',
content: ''
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({[event.target.name]: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.title);
event.preventDefault();
}
render() {
return (
<div className="Block-container">
<form onSubmit={this.handleSubmit}>
<div className="Block-title">
<label>
Block title:
<input type="text" name="title" value={this.state.value} onChange={this.handleChange} />
</label>
</div>
<div className="Block-content">
<label>
Block content:
<input type="text" name="content" value={this.state.value} onChange={this.handleChange} />
</label>
</div>
<input type="submit" value="Save" />
</form>
</div>
);
}
}
Menu.js
class Menu extends React.Component {
constructor(props) {
super(props);
this.state = {value: '',blocksArray:[]};
this.handleAdd = this.handleAdd.bind(this);
}
handleAdd() {
this.setState({
blocksArray:this.state.blocksArray.push(block)
})
}
renderBlocks = ()=>{
this.state.blocksArray.map(block=> <Block/>)
}
render() {
return (
<div className="Menu">
<header className="Menu-header">
<button className="Menu-button" onClick={()=>this.handleAdd()}>Add block</button>
</header>
{this.renderBlocks()}
</div>
);
}
}
export default Menu;

How to push into an array on submit in reactjs?

I am new to reactjs and trying to implement simple todo app. But, upon submit I am not able to push into an array i.e a state variable.
Following is my code:
import React, { Component } from 'react';
class ToDo extends Component{
constructor(props){
super(props)
this.state={list:['hello'],item:''}
this.handleSubmit=this.handleSubmit.bind(this)
this.handleSearchChange=this.handleSearchChange.bind(this)
}
handleSubmit(e){
e.preventDefault();
this.setState(state=>({list:(state.list.push(this.state.item))}))
}
handleSearchChange(e){
this.setState({item:e.target.value})
}
render(){
console.log('state:',this.state.list)
let listing=this.state.list.map((item)=><li key={item}>{item}</li>)
return(
<div >
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<label>
<input className="form-control "type="text" value={this.state.item} onChange={this.handleSearchChange} />
</label>
<label>
<input type="submit" value="Submit" className="form-control" />
</label>
</div>
</form>
<ul>{listing}</ul>
</div>
)
}
}
export default ToDo;
When I try to click on submit it redirects to error.
Help would be appreciated.
Thanks.
try this:
handleSubmit(e){
const { list, item } = this.state
e.preventDefault();
this.setState({ list: [...list, item] })
}
Explaination: you can't mutate data, concatenate it like this instead.
Advice: use es6 functions always, so you will never need binding.
It's easy and helpful to you...
handleSubmit(e){
const {list, item}=this.state;
e.preventDefault();
this.setState({ list: [...list, item] });
}

Creating a form in React that saves data

I am trying to create a customer details form in react (currently using react-json-form) where I can reuse the values in the inputs to create a saved file that the app can refer to. I have created the form and can output the results but I am unsure how to save the input values for future use or call them back once they are saved.
If anyone has any suggestions or examples of a form that does this then I would be greatly appreciative.
My code is as follows:
import React, { Component } from 'react';
import JSONTree from 'react-json-tree';
import { BasicForm as Form, Nest, createInput } from 'react-json-form';
const Input = createInput()(props => <input type="text" {...props} />);
const UserFields = () => (
<section>
<h3>User</h3>
<div>Name: <Input path="name" /></div>
<div>Email: <Input path="email" /></div>
</section>
);
export default class ExampleForm extends Component {
state = { data: {} };
updateData = data => this.setState({ data });
render() {
return (
<Form onSubmit={this.updateData}>
<Nest path="user">
<UserFields />
</Nest>
<button type="submit">Submit</button>
<JSONTree data={this.state.data} shouldExpandNode={() => true} />
</Form>
);
}
}
A more simple solution would be to use a form, like a semanti-ui-react form, store the information to the state onChange, then convert the info to JSON for storage.
import { Form, Button } from 'semantic-ui-react'
export default class App extends Component {
constructor() {
super()
this.state = {
name: "",
email: ""
}
}
handleChange = (e, {name, value}) => {
console.log(name, value)
this.setState({[name]: value})
}
render() {
return (
<div>
<Form onSubmit={this.sendDataSomewhere}>
<Form.Field>
<Form.Input name="name" value={this.state.name} onChange={this.handleChange}/>
</Form.Field>
<Form.Field>
<Form.Input name="email" value={this.state.email} onChange={this.handleChange}/>
</Form.Field>
<Button type="submit">Submit</Button>
</Form>
</div>
)
}
}
I use a dynamic method of receiving the input from different fields using the name and val attributes. The values captured in state are then accessible by this.state.whatever
Hope this helped

How to get values from input types using this.refs in reactjs?

Not able to get values of input type using this.refs...
how to get that values from input type
export class BusinessDetailsForm extends Component {
submitForm(data) {
console.log(this.refs.googleInput.value)
}
}
reder() {
return(
<form onSubmit={this.submitForm}>
<Field type="text"
name="location"
component={GoogleAutoComplete}
id="addressSearchBoxField"
ref="googleInput"
/>
</form>
)
}
}
You should avoid ref="googleInput" as it is now considered legacy. You should instead declare
ref={(googleInput) => { this.googleInput = googleInput }}
Inside of your handler, you can use this.googleInput to reference the element.
Then inside of your submitForm function, you can obtain the text value with
this.googleInput._getText()
String refs are legacy
https://facebook.github.io/react/docs/refs-and-the-dom.html
If you worked with React before, you might be familiar with an older API where the ref attribute is a string, like "textInput", and the DOM node is accessed as this.refs.textInput. We advise against it because string refs have some issues, are considered legacy, and are likely to be removed in one of the future releases. If you're currently using this.refs.textInput to access refs, we recommend the callback pattern instead.
Edit
From React 16.3, the format for creating refs are:
class Component extends React.Component
{
constructor()
{
this.googleInput = React.createRef();
}
render()
{
return
(
<div ref={this.googleInput}>
{/* Details */}
</div>
);
}
}
using ref={ inputRef => this.input = inputRef } is considered legacy now. In React 16.3 onwards, you can use the code below,
class MyForm extends React.Component {
constructor(props) {
//...
this.input = React.createRef();
}
handleSubmit(event) {
alert('A name was submitted: ' + this.input.current.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" ref={this.input} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
EDIT: thanks for the comment #stormwild
In case any one is wondering how to implement ref with hooks :
// Import
import React, { useRef } from 'react';
const Component = () => {
// Create Refs
const exampleInput = useRef();
const handleSubmit = (e) => {
e.preventDefault();
const inputTest = exampleInput.current.value;
}
return(
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" ref={exampleInput} />
</label>
<input type="submit" value="Submit" />
</form>
}
getValue: function() {
return this.refs.googleInput.value;
}
I think the more idiomatic way is to use state instead of refs, although it's a little more code in this case since you only have a single input.
export class BusinessDetailsForm extends Component {
constructor(props) {
super(props);
this.state = { googleInput: '' };
this.defaultValue = 'someValue';
this.handleChange = this.handleChange.bind(this);
this.submitForm = this.submitForm.bind(this);
}
handleChange(e) {
const { field, value } = e.target;
this.setState({ [field]: value });
}
submitForm() {
console.log(this.state.googleInput);
}
render() {
return (
<Formsy.Form onSubmit={this.submitForm} id="form_validation">
<Field type="text"
name="googleInput"
onChange={this.handleChange}
component={GoogleAutoComplete}
floatingLabelText="location"
hintText="location"
id="addressSearchBoxField"
defaultValue={this.defaultValue}
onSelectPlace={this.handlePlaceChanged}
validate={[ required ]}
/>
</Formsy.Form>
);
}
}
See https://facebook.github.io/react/docs/forms.html#controlled-components.
Using RN 0.57.8 when tried this.googleInput._getText(), It resulted in error _getText is not a function so i printed this.googleInput in console and found that _getText() is a function inside _root
this.googleInput._root._getText()
this.googleInput._root._lastNativeText - This will return the last state not the current state please be careful while using it.
In 2018 you should write in constructor this:
In constructor of class you should add something like
this.input = React.createRef()
Examples here:
https://reactjs.org/docs/uncontrolled-components.html
I tried the answer above (https://stackoverflow.com/a/52269988/1978448) and found it only worked for me when I put the refs in the state, but not when I just made them properties of the component.
Constructor:
this.state.refs={
fieldName1: React.createRef(),
fieldName2: React.createRef()
};
and in my handleSubmit I create a payload object to post to my server like this:
var payload = {
fieldName1: this.state.refs.fieldName1.current.value,
fieldName2: this.state.refs.fieldName2.current.value,
}
The react docu explains it very well: https://reactjs.org/docs/refs-and-the-dom.html
this is considered legacy:
yourHandleMethod() {
this.googleInput.click();
};
yourRenderCode(){
ref={(googleInput) => { this.googleInput = googleInput }}
};
whereas, this is considered the way to go:
constructor(props){
this.googleInput = React.createRef();
};
yourHandleMethod() {
this.googleInput.current.click();
};
yourRenderCode(){
<yourHTMLElement
ref={this.googleInput}
/>
};
From React 16.2, you can use: React.createRef
See more: https://reactjs.org/docs/refs-and-the-dom.html
1. using ref={ inputRef => this.input = inputRef }
Exam:
import React, { Component } from 'react';
class Search extends Component {
constructor(props) {
super(props);
this.name = React.createRef();
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.props.onSearch(`name=${this.name.value}`);
}
render() {
return (
<div>
<input
className="form-control name"
ref={ n => this.name = n }
type="text"
/>
<button className="btn btn-warning" onClick={ this.handleClick }>Search</button>
</div>
);
}
}
export default Search;
ref={ n => this.name = n } Use Callback Refs -> see
Or:
2. this.name.current.focusTextInput()
class Search extends Component {
constructor(props) {
super(props);
this.name = React.createRef();
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.props.onSearch(`name=${this.name.current.value}`);
}
render() {
return (
<div>
<input
className="form-control name"
ref={this.name}
type="text"
/>
<button className="btn btn-warning" onClick={ this.handleClick }>Search</button>
</div>
);
}
}
export default Search;
Hope it will help you.

Categories