I want to make a form for user data and I was asked to make a wrapper react components for each type of input. My problem is passing the handler to the input component.
This is my form:
import React from 'react';
import {addUser as addNewUser} from '../../services/index';
import {TextBox} from './TextBox'
interface AddUserProps{
}
interface AddUserState{
UserName:string,
}
export default class AddUser extends React.Component<AddUserProps, AddUserState> {
constructor(props:any) {
super(props);
this.state = {
UserName: '',
};
this.updateUserName = this.updateUserName.bind(this);
}
updateUserName(event: React.ChangeEvent<HTMLInputElement>) {
this.setState({UserName: event.target.value});
}
handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
console.log(this.state)
addNewUser(this.state)
}
render() {
return (
<div>
<form
className = "user-add-form"
onSubmit={(event) => this.handleSubmit(event)}
>
<h3>Adauga utilizatori:</h3>
<label htmlFor="userName">User Name:</label>
<TextBox name="userName" type="text" value={userName} handleChange={this.updateUserName}/>
<input type="submit" value="Add user"/>
</form>
</div>
)
}
}
export {AddUser};
And this is the input component that I made:
import React from 'react'
export function TextBox(props) {
return (
<div>
<input type={props.type}
name={props.name}
value={props.value}
onChange={(event) => props.HandleInput(event)}
/>
</div>
)
}
So what I don't know is how to pass the event handler to the input component, because as it is right now it can't find it.
It should exist in Textbox's props as handleChange as it's passed in the parent component. Does this not work?
<input
type={props.type}
name={props.name}
value={props.value}
onChange={(event) => props.handleChange(event)}
/>
Related
I am not finding good docs or videos on how to get data from my inputs with React-Bootstrap. I want to be able to click the button and then bring what I typed into the input box into my onClick function.
import React from "react";
import Button from 'react-bootstrap/Button';
import './Search.css';
import InputGroup from 'react-bootstrap/InputGroup';
import FormControl from 'react-bootstrap/FormControl';
class search extends React.Component {
constructor(props){
super(props);
this.text = React.createRef();
this.searchChar = this.searchChar.bind(this);
}
searchChar = () => {
console.log("Button Clicked")
const value = this.input.current.value;
console.log(value)
}
render() {
return (
<div className="searchBar">
<form>
<InputGroup className="mb-3">
<InputGroup.Prepend>
<InputGroup.Text id="basic-addon1">Character Search</InputGroup.Text>
</InputGroup.Prepend>
<FormControl ref = {this.input}
placeholder="Character Name"
aria-label="Character Name"
aria-describedby="basic-addon1"
/>
</InputGroup>
<Button onClick={this.searchChar(this.input)} variant="outline-danger">Search </Button>
</form>
</div>
);
}
}
export default search;
Just try to write your input values in state
for example;
import React from "react";
import Button from 'react-bootstrap/Button';
import './Search.css';
import InputGroup from 'react-bootstrap/InputGroup';
import FormControl from 'react-bootstrap/FormControl';
class search extends React.Component {
constructor(props){
super(props);
this.state = {
basicAddon1 : null,
};
}
searchChar = () => {
console.log("Button Clicked")
const value = this.state.basicAddon1;
console.log(value)
}
render() {
return (
<div className="searchBar">
<form>
<InputGroup className="mb-3">
<InputGroup.Prepend>
<InputGroup.Text id="basic-addon1">Character Search</InputGroup.Text>
</InputGroup.Prepend>
<FormControl
placeholder="Character Name"
aria-label="Character Name"
aria-describedby="basic-addon1"
onChange={event => {
this.setState({
basicAddon1 : event.target.value
});
}}
value={this.state.basicAddon1 ? this.state.basicAddon1 : ""}
/>
</InputGroup>
<Button onClick={this.searchChar(this.input)} variant="outline-danger">Search </Button>
</form>
</div>
);
}
}
export default search;
you can create inputChangeHandler function or something else for improve your code
it just basic
The same way you deal with getting data from a form in pure React, you do with react-bootstrap. This answer here shows many options to do so.
My favourite approach among those options is this one. Using that approach your code would be something like:
class search extends React.Component {
constructor(props) {
super(props)
this.handleSave = this.handleSave.bind(this)
}
onChange(event) {
// Intended to run on the change of every form element
event.preventDefault()
this.setState({
[event.target.name]: event.target.value,
})
}
handleSave() {
console.log(`Do something with : {this.state.characterName}`)
}
render() {
return (
<div className="searchBar">
<form>
<InputGroup className="mb-3">
<InputGroup.Prepend>
<InputGroup.Text id="basic-addon1">
Character Search
</InputGroup.Text>
</InputGroup.Prepend>
<FormControl
name="characterName"
placeholder="Character Name"
aria-label="Character Name"
aria-describedby="basic-addon1"
onChange={this.onChange.bind(this)}
/>
</InputGroup>
<Button onClick={this.handleSave} variant="outline-danger">
Search{' '}
</Button>
</form>
</div>
)
}
}
Currently I am trying to split up the app in separate components to make it more readable and testable. But now I faced an issue, which is the general function in the parent component. How do I call the general onChange function from separate components. Because there are multiple input fields that do the same, so therefore I want to make a reusable function in parent component, that can be called from the child component.
// child component
export default class Name extends React.Component {
constructor(props) {
super(props);
}
state = {
name: '',
nameErrorMessage: ''
}
checkName = (name: string) => {
const re = /[^a-zA-Z]/;
const checkValidation = re.test(name);
const nameRequirements = !checkValidation && name.length > 1;
if(!nameRequirements) {
this.setState({ nameErrorMessage: 'name contains numbers, symbols or is too short (min length of 2 letters)', nameBoolean: false });
} else {
this.setState({ nameErrorMessage: '', nameBoolean: true });
}
}
handleNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const getName = event.target.value;
const getNameValid = this.checkName(getName);
return getNameValid;
}
onChange = () => {
this.props.parentMethod();
}
render() {
return (
<div className="two-columns two-columns-child column-block">
<label className="label-customized">First name</label><br/>
<input
name="name"
className="input-customized"
type="text"
value={this.state.name}
onBlur={this.handleNameChange}
onChange={this.onChange}
placeholder="Enter first name"
/>
<br/>
<span className="error-message">{this.state.nameErrorMessage}</span>
</div>
)
}
}
// parent component
onChange = (event: React.ChangeEvent<HTMLInputElement>) => {
let onChangeName:any = event.target.getAttribute('name');
this.setState({[onChangeName]: event.target.value })
}
return (
<div className="App">
<form onSubmit={this.checkForm}>
<Name/>
</form>
</div>
)
PARENT COMPONENT
pass onChange as property to the child component
...
return (
<div className="App">
<form onSubmit={this.checkForm}>
<Name onChange={this.onChange}/>
</form>
</div>
)
CHILD COMPONENT
call the passed prop when onChange is called for the input
return <div className="two-columns two-columns-child column-block">
<label className="label-customized">First name</label><br/>
<input
name="name"
className="input-customized"
type="text"
value={this.state.name}
onBlur={this.handleNameChange}
onChange={e => this.props.onChange(e)}
placeholder="Enter first name"
/>
<br/>
<span className="error-message">{this.state.nameErrorMessage}</span>
</div>
I am trying to send data in a form using onClick. Below is my Form
import React from 'react';
const form = props => (
<form>
<input type = "text" name = "name" placeholder="name" />
<input type = "text" name = "lastname" placeholder="last name" />
<input type = "text" name = "id" placeholder="email address" />
<button onClick = {props.clickHandler}>Send</button>
</form>
);
export default form;
Below is my App.js
import React, { Component } from 'react';
import './App.css';
import Form from './Components/Form';
class App extends Component {
clickHandler = async(e) =>{
e.preventDefault();
const name = e.target.value;
console.log(name + 'was typed');
}
render() {
return (
<div className="App">
<h1>I am a React App </h1>
<Form form = {this.Form}/>
</div>
);
}
}
export default App;
I am not sure why the value is not being visible on console. Any help is appreciated.
First of all name your components as starting with a capital letter.
For this kind of situations, you can keep the values in your main component's state, then update them via your callback functions which are being passed to the child component.
class App extends React.Component {
state = {
name: "",
lastName: "",
email: ""
};
clickHandler = e => {
e.preventDefault();
const { name, lastName, email } = this.state;
const data = `Data is: ${name}-${lastName}-${email}`;
alert(data);
};
changeHandler = e => {
e.preventDefault();
const { name, value } = e.target;
this.setState({
[name]: value
});
};
render() {
console.log(this.state);
const { clickHandler, changeHandler } = this;
return (
<div className="App">
<h1>I am a React App </h1>
<Form clickHandler={clickHandler} changeHandler={changeHandler} />
</div>
);
}
}
const Form = props => (
<form>
<input
onChange={props.changeHandler}
type="text"
name="name"
placeholder="name"
/>
<input
onChange={props.changeHandler}
type="text"
name="lastName"
placeholder="last name"
/>
<input
onChange={props.changeHandler}
type="text"
name="email"
placeholder="email address"
/>
<button onClick={props.clickHandler}>Send</button>
</form>
);
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
For the inputs, you need an onChange handler, for your button you need an onClick handler as you thought. You can see the changing state in the console. When you hit the button it creates an object using your state values then fires the alert.
You need to pass down the clickHandler as a prop to your Form component
render() {
return (
<div className="App">
<h1>I am a React App </h1>
<Form onSubmit={this.clickHandler} />
</div>
)
}
Your are using React Uncontrolled form inputs so you need to handle the form onSubmit event
import React from "react"
const form = props => (
<form
onSubmit={e => {
e.preventDefault()
this.props.onSubmit(e)
}}
>
<input type="text" name="name" placeholder="name" />
<input type="text" name="lastname" placeholder="last name" />
<input type="text" name="id" placeholder="email address" />
<input type="submit" value="Send" />
</form>
)
export default form
And in the clickHandleryou can now retrieve all values from the submit event like so
clickHandler = async e => {
e.preventDefault()
const name = e.target.elements[0]
console.log(name + "was typed")
}
Edit: Added a way to see form values
import React, { Component } from 'react';
import './App.css';
import Form from './Components/Form';
class App extends Component {
clickHandler = (data) => {
console.log('data::', data );
}
render() {
return (
<div className="App">
<h1>I am a React App </h1>
<Form clickHandler = {this.clickHandler}/>
</div>
);
}
}
export default App;
import React, { PureComponent } from 'react';
export class Form extends PureComponent {
state = {
name: '',
lastname: '',
id: ''
}
onNameChange = (event) => {
this.setState({
name: event.target.value
})
}
onLastNameChange = (event) => {
this.setState({
lastname: event.target.value
})
}
onEmailChange = (event) => {
this.setState({
id: event.target.value
})
}
render() {
return (
<form>
<input type = "text" name = "name" placeholder="name" onChange={this.onNameChange} />
<input type = "text" name = "lastname" placeholder="last name" onChange={this.onLastNameChange} />
<input type = "text" name = "id" placeholder="email address" onChange={this.onEmailChange}/>
<button onClick = {props.clickHandler.bind(null, this.state)}>Send</button>
</form>
);
}
}
I am new to react and am trying to get the value from the firstName input in handleSubmit. handleSubmit is working but for some reason the input value is undefined. I tried following some other examples but they were all forms in React components.
let SomeForm = (props) => {
let firstName = '';
const handleSubmit = (e) => {
e.preventDefault();
console.log(firstName);
}
return (
<div>
<form onSubmit={handleSubmit}>
<TextField
floatingLabelText="First Name"
floatingLabelFixed={true}
underlineStyle={styles.underlineStyle}
underlineFocusStyle={styles.underlineFocusStyle}
value={firstName}
/>
<input type="submit" value="Submit" />
</form>
</div>
)
}
SomeForm = connect()(SomeForm)
export default SomeForm
You need to add onChange to the TextField to handle the updates. And because SomeForm is a stateful component, you may need to use a class component instead of a stateless functional component.
class SomeForm extends React.Component {
state = {
firstName: ''
};
handleChange = (e, value) => {
this.setState({ firstName: value });
};
handleSubmit = (e) => {
e.preventDefault();
console.log(this.state.firstName);
};
render () {
return (
<div>
<form onSubmit={this.handleSubmit}>
<TextField
id="text-field-controlled"
floatingLabelText="First Name"
floatingLabelFixed={true}
underlineStyle={styles.underlineStyle}
underlineFocusStyle={styles.underlineFocusStyle}
value={this.state.firstName}
onChange={this.handleChange}
/>
<input type="submit" value="Submit" />
</form>
</div>
)
}
}
See the API and examples of TextField here: http://www.material-ui.com/#/components/text-field
You need function that you will throw in your TextField component and with onChange you can get value of input.
handleChange(e){
Console.log(e.target.value)
}
And in TextField
<TextField onChange={this.handleCahnge}/}
Or use refs
<TextField ref="textfield" />
And get value with this.refs.textfield.getValue()
I would like to ask, what I miss on my code. It seems submitForm function is not working/triggering when I submit the form. I can't get values from my form fields. Here's my code:
import React from 'react';
import { reduxForm,reset, Field } from 'redux-form';
class FormProfile extends React.Component {
submitForm(formProps){
console.log(formProps);
}
render(){
const { error, handleSubmit } = this.props;
return (
<form onSubmit={this.submitForm.bind(this)}>
<Row>
<Col lg={6}>
<Field name="name" type="text" component={TextBoxComponent} placeholder="Compay Name" label="* Company Name" required />
<Field name="website" type="text" component={TextBoxComponent} placeholder="www.yourdomain.com" label="Website" />
<Field name="email" type="text" component={TextBoxComponent} placeholder="How can we contact your Company" label="* Contact Email" required />
</Col>
</Row>
</form>
);
}
}
const form = reduxForm({
form: 'CreateCompanyProfileForm',
validate
});
function validate(formProps){
const error = {};
return error;
}
export default (form(FormProfile));
TextBox Componen
import React from "react";
class TextBoxComponent extends React.Component {
render(){
return (
<div className="form-group">
<label className="control-label">{this.props.label}</label>
{ this.props.sublabel !== undefined ?
<em className="text-info"> { this.props.sublabel }</em>
:null}
<input { ...this.props } type={this.props.type} placeholder={this.props.placeholder} className="form-control"/>
{ this.props.required && <span className="text-error"></span> }
</div>
);
}
}
export default TextBoxComponent;
You should modify this line:
<form onSubmit={this.submitForm.bind(this)}>
to:
<form onSubmit={handleSubmit}>
then you can remove:
submitForm(formProps){
console.log(formProps);
}
Then you can create a new component to wrap redux form component:
class SamplePage extends React.Component {
handleSubmit = (values) => {
// Do something with the form values
console.log(values);
}
render() {
return (
<FormProfile onSubmit={this.handleSubmit} />
);
}
}
Anyway, you should check the example from Redux-form docs: http://redux-form.com/6.5.0/docs/GettingStarted.md/