--- id: 5a24c314108439a4d4036179 title: Create a Controlled Form challengeType: 6 forumTopicId: 301384 dashedName: create-a-controlled-form --- # --description-- The last challenge showed that React can control the internal state for certain elements like `input` and `textarea`, which makes them controlled components. This applies to other form elements as well, including the regular HTML `form` element. # --instructions-- The `MyForm` component is set up with an empty `form` with a submit handler. The submit handler will be called when the form is submitted. We've added a button which submits the form. You can see it has the `type` set to `submit` indicating it is the button controlling the form. Add the `input` element in the `form` and set its `value` and `onChange()` attributes like the last challenge. You should then complete the `handleSubmit` method so that it sets the component state property `submit` to the current input value in the local `state`. **Note:** You also must call `event.preventDefault()` in the submit handler, to prevent the default form submit behavior which will refresh the web page. Finally, create an `h1` tag after the `form` which renders the `submit` value from the component's `state`. You can then type in the form and click the button (or press enter), and you should see your input rendered to the page. # --hints-- `MyForm` should return a `div` element which contains a `form` and an `h1` tag. The form should include an `input` and a `button`. ```js assert( (() => { const mockedComponent = Enzyme.mount(React.createElement(MyForm)); return ( mockedComponent.find('div').children().find('form').length === 1 && mockedComponent.find('div').children().find('h1').length === 1 && mockedComponent.find('form').children().find('input').length === 1 && mockedComponent.find('form').children().find('button').length === 1 ); })() ); ``` The state of `MyForm` should initialize with `input` and `submit` properties, both set to empty strings. ```js assert( Enzyme.mount(React.createElement(MyForm)).state('input') === '' && Enzyme.mount(React.createElement(MyForm)).state('submit') === '' ); ``` Typing in the `input` element should update the `input` property of the component's state. ```js (() => { const mockedComponent = Enzyme.mount(React.createElement(MyForm)); const _1 = () => { mockedComponent.setState({ input: '' }); return mockedComponent.state('input'); }; const _2 = () => { mockedComponent .find('input') .simulate('change', { target: { value: 'TestInput' } }); return { state: mockedComponent.state('input'), inputVal: mockedComponent.find('input').props().value }; }; const before = _1(); const after = _2(); assert( before === '' && after.state === 'TestInput' && after.inputVal === 'TestInput' ); })(); ``` Submitting the form should run `handleSubmit` which should set the `submit` property in state equal to the current input. ```js (() => { const mockedComponent = Enzyme.mount(React.createElement(MyForm)); const _1 = () => { mockedComponent.setState({ input: '' }); mockedComponent.setState({ submit: '' }); mockedComponent .find('input') .simulate('change', { target: { value: 'SubmitInput' } }); return mockedComponent.state('submit'); }; const _2 = () => { mockedComponent.find('form').simulate('submit'); return mockedComponent.state('submit'); }; const before = _1(); const after = _2(); assert(before === '' && after === 'SubmitInput'); })(); ``` The `h1` header should render the value of the `submit` field from the component's state. ```js (() => { const mockedComponent = Enzyme.mount(React.createElement(MyForm)); const _1 = () => { mockedComponent.setState({ input: '' }); mockedComponent.setState({ submit: '' }); mockedComponent .find('input') .simulate('change', { target: { value: 'TestInput' } }); return mockedComponent.find('h1').text(); }; const _2 = () => { mockedComponent.find('form').simulate('submit'); return mockedComponent.find('h1').text(); }; const before = _1(); const after = _2(); assert(before === '' && after === 'TestInput'); })(); ``` # --seed-- ## --after-user-code-- ```jsx ReactDOM.render(, document.getElementById('root')); ``` ## --seed-contents-- ```jsx class MyForm extends React.Component { constructor(props) { super(props); this.state = { input: '', submit: '' }; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleChange(event) { this.setState({ input: event.target.value }); } handleSubmit(event) { // Change code below this line // Change code above this line } render() { return (
{/* Change code below this line */} {/* Change code above this line */}
{/* Change code below this line */} {/* Change code above this line */}
); } } ``` # --solutions-- ```jsx class MyForm extends React.Component { constructor(props) { super(props); this.state = { input: '', submit: '' }; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleChange(event) { this.setState({ input: event.target.value }); } handleSubmit(event) { event.preventDefault(); this.setState(state => ({ submit: state.input })); } render() { return (

{this.state.submit}

); } } ```