Updating state in parent with Draft editor state? - reactjs

I have a Draftjs editor in a form with other fields. The state for all those fields is being controlled in that parent component. How do I get the same behavior from the Draft editor as I do from the regular HTML form fields where it updates the parent state?
Regular input:
<input value={title} type="text" onChange={this.handleChange} name="title" placeholder="Title" id="title" />
Draft js editor:
<TextEditor placeholder="Write your summary..." value={summary} toolbar />
On change handler:
handleChange(event) {
this.setState({[`${event.target.name}`]: event.target.value});
};

You can simply Do :
In parent : (not that I have add the update={ this.update } props)
…
render(){
return (
<input value={title} type="text" onChange={this.handleChange} name="title" placeholder="Title" id="title" update={ this.update }/>
);
}
update(editorState){
console.log('update',editorState);
}
…
In editor :
handleChange(event) {
this.setState({[`${event.target.name}`]: event.target.value});
this.props.update(this.state);
};
This will call the update() function of the parent, is that what you are searching for ?
Edit :
import React from 'react';
import ReactDOM from 'react-dom';
import {Editor, EditorState} from 'draft-js';
class Parent extends React.Component {
…
render() {
return (
<div>
<form>
<MyEditor update={ this.update }>
<form>
</div>
);
}
update(editorState) {
console.log('editor s state', editorState);
}
…
}
// from draft website :
class MyEditor extends React.Component {
constructor(props) {
super(props);
this.state = {editorState: EditorState.createEmpty()};
this.onChange = (editorState) => {
this.setState({editorState});
this.props.update(this.state);
}
}
render() {
return (
<Editor editorState={this.state.editorState} onChange={this.onChange} />
);
}
}
ReactDOM.render(
<Parent/>,
document.getElementById('container')
);

Related

Input react wrapper

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)}
/>

Getting Data From React-Bootstrap Input

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>
)
}
}

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 bootstrap form not rendering spaces in text inputs

I'm using react bootstrap components. I have form elements that follow this sort of structure:
class Example extends React.Component {
constructor (props) {
super(props)
this.state = {
name: '',
show: false
}
this.handleChange = this.handleChange.bind(this)
this.handleShow = this.handleShow.bind(this)
this.handleClose = this.handleClose.bind(this)
}
handleShow () {
this.setState({ show: true })
}
handleClose () {
this.setState({ show: false })
}
handleChange (e) {
this.setState({
[e.target.name]: e.target.value
})
}
render () {
return (
<div>
<Button bsStyle='success' onClick={this.handleShow}>Add New</Button>
<Modal show={this.state.show} onHide={this.handleClose}>
<Modal.Header closeButton>
<Modal.Title>Add New</Modal.Title>
</Modal.Header>
<Modal.Body>
<form>
<FormGroup>
<ControlLabel className='form-input'>1. Provide Name</ControlLabel>
<FormControl onChange={this.handleChange} className='form-input' type='text' placeholder='Name' name='name' value={this.state.name} />
</FormGroup>
</form>
</Modal.Body>
</Modal>
</div>
)
}
}
When I type in the text input it removes the spaces e.g. I type 'hello world' but it renders 'helloworld'
I can't seem to find an answer for this.
Edit: I forgot to mention the form is rendering within a bootstrap modal, I don't know if that's what's causing the issue? I've just refactored my code and updated my example snippet to match.
Problem solved: The issue solved itself when we separated the button out so the button was not part of the component and we just return the modal.
import React, { Component } from 'react';
import { render } from 'react-dom';
import { FormGroup, ControlLabel, FormControl } from 'react-bootstrap'
class App extends Component {
constructor (props) {
super(props)
this.state = {
name: ''
}
this.handleChange = this.handleChange.bind(this)
}
handleChange (e) {
this.setState({
[e.target.name]: e.target.value
})
}
render () {
return (
<form>
<FormGroup>
<ControlLabel className='form-input'>1. Provide Name</ControlLabel>
<FormControl onChange={this.handleChange} className='form-input' type='text' placeholder='Name' name='name' value={this.state.name} />
</FormGroup>
</form>
)
}
}
render(<App />, document.getElementById('root'));

Redux-form onSubmit nothing happens

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/

Resources