--- 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. For camper convenience, the default behavior has been disabled here to prevent refreshes from resetting challenge code. 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'); })(); ``` `handleSubmit` should call `event.preventDefault` ```js assert( __helpers.isCalledWithNoArgs( 'event.preventDefault', MyForm.prototype.handleSubmit.toString() ) ); ``` The `h1` heading element 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}

); } } ```