Skip to content

Instantly share code, notes, and snippets.

@leahgarrett
Created June 26, 2019 03:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save leahgarrett/f0a62291595e1bba764a6d8b59a34c02 to your computer and use it in GitHub Desktop.
Save leahgarrett/f0a62291595e1bba764a6d8b59a34c02 to your computer and use it in GitHub Desktop.
Forms

Forms

Today we will create a Wish List app. This app will use a form.


Create the app

Create the client app
npx create-react-app wish-list

Change into the app folder
cd wish-list

Install dependencies
npm install

Run the app
npm start

See a spinning logo?

Back at terminal lets open Visual Studio Code
code .


Clean-up anything that was created that we do not want

Edit the CSS file getting rid of un used styles /src/app.css

.App-logo {
  animation: App-logo-spin infinite 20s linear;
  height: 10vmin;
  pointer-events: none;
}

@keyframes App-logo-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

Edit the app file to remove things we don't need and make the App a React component. /src/app.js

import React from 'react';
import logo from './logo.svg';
import './App.css';

class App extends Component {
  render() {
  return (
    <div>
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
      </header>
    </div>
    );
  }
}

export default App;

Create files for the Form component

Now we will create a component and associated css file for the form.

Make a new file for the form styling /src/component/WishForm.css

.wish-form {
    margin-left: 20px;
}
form {
    font-size: 16px;
    max-width: 500px;

}
input {
    margin: 5px 0 25px 0;
    display: block;
    width: 100%;
    font-size: 16px;
  }
  
label {
    display: block;
    width: 100%;
  }
  
  button {
    width: 120px;
    padding: 10px 30px;
  }

Make a new file for the form. We will be adding functions to this component so we will extend Component rather then use a functional component.

/src/component/WishForm.js

import React, { Component } from 'react';
import './WishForm.css';

class WishForm extends Component {
  render(){
      return (
        <div className="wish-form">
          <h1>Wish Form</h1>
          <form>
              <label htmlFor="name">Name</label>
              <input type="text" id="name" placeholder="name" />
              <label htmlFor="priority">Priority</label>
              <input type="number" id="priority" placeholder="1" />
              <button>Save</button>
          </form>
        </div>
      );
    }
  }

export default WishForm;

Add the Form component the the App

Update the App.js to use the form component We will add the component and the import for it. We are using the uppercase Form to differentiate it from the HTML form element.

import React, { Component } from 'react';
import WishForm from './components/WishForm'
import logo from './logo.svg';
import './App.css';

class App extends Component {
  render() {
  return (
    <div>
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
      </header>
      <WishForm  />
    </div>
    );
  }
}

export default App;

The app should now run. Displaying the logo from App.js and the heading and form from WishForm.js

Clicking the button refreshes the page.


Add a click handler to the WishForm component

Add a handler for the click event tot he form button.
/src/component/WishForm.js

class WishForm extends Component {
  handleClick = () => {
    console.log('clicked')
  }
  
  render(){
      return (
        <div className="wish-form">
          <h1>Wish Form</h1>
          <form>
              <label htmlFor="name">Name</label>
              <input type="text" id="name" placeholder="name" />
              <label htmlFor="priority">Priority</label>
              <input type="number" id="priority" placeholder="1" />
              <button onClick={this.handleClick}>Save</button>
          </form>
        </div>
      );
    }
  }

The page still refreshes.

Update the handler to capture the event parameter (we had been ignoring it but not providing it with a name). The event is similar to what we had been using in vanilla javascript but we also have extra React features added to it. Try console logging e.currentTarget.

/src/component/WishForm.js

  handleClick = (e) => {
    e.preventDefault();
    console.log(e)
  }

How will we capture what has been entered into the field of the form?


Use change handlers to update state

Add a constructor to initialize the state and add a change handler to the name input field.

/src/component/WishForm.js

class WishForm extends Component {
  constructor(props) {
    super(props);
    this.state = { 
      name: '', 
      priority: '' 
    };
  }

  handleClick = (e) => {
    e.preventDefault();
    console.log(e)
  }

  handleNameChange = (e) => {
    console.log(e)
  }

  render(){
      return (
        <div className="wish-form">
          <h1>Wish Form</h1>
          <form>
              <label htmlFor="name">Name</label>
              <input onChange={this.handleNameChange} type="text" id="name" placeholder="name" />
              <label htmlFor="priority">Priority</label>
              <input type="number" id="priority" placeholder="1" />
              <button onClick={this.handleClick}>Save</button>
          </form>
        </div>
      );
    }
  }

We can also use console log to check the value of e.target and e.target.value.

What is e.currentTarget.value?

We can use this value to record the state.

/src/component/WishForm.js

  handleNameChange = (e) => {
    console.log(e)
    console.log(e.target)
    console.log(e.target.value)
    console.log(e.target.id)
    this.setState({ name: e.target.value})
  }

Lets confirm this is being saved by logging sate in the render method:
console.log(this.state);

Working.

We will need to do the same thing for the priority field but lets for a way to reuse this method. Let looks at:
console.log(e.target.id)

Now lets use this to setState.

/src/component/WishForm.js

  handleNameChange = (e) => {
    this.setState({ [e.target.id]: e.target.value})
  }

We can see the state being logged to confirm that it is working.

Let change the handleNameChange to have a more generic name and add it to an onClick for both the input fields.

/src/component/WishForm.js

  handleChange = (e) => {
    this.setState({ [e.target.id]: e.target.value})
  }

  render(){
    console.log(this.state);
      return (
        <div className="wish-form">
          <h1>Wish Form</h1>
          <form>
              <label htmlFor="name">Name</label>
              <input onChange={this.handleChange} type="text" id="name" placeholder="name" />
              <label htmlFor="priority">Priority</label>
              <input onChange={this.handleChange} type="number" id="priority" placeholder="1" />
              <button onClick={this.handleClick}>Save</button>
          </form>
        </div>
      );
    }
<br>  

Saving from the form to the App

Create a method to receive the saved wish from the WishForm.

/src/App.js

class App extends Component {
  addNewWishHandler = () => {
    console.log('Adding a new wish');
  }
  render() {
    return (
      <div>
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
        </header>
        <WishForm addNewWish={this.addNewWishHandler} />
      </div>
      );
  }
}

Now use this method in our WishForm to pass back the values from the newly crated wish.

/src/component/WishForm.js

  handleClick = (e) => {
    e.preventDefault();
    console.log(e)
    const newWish = {name: this.state.name, priority: this.state.priority }
    this.props.addNewWish(newWish)
  }

Confirm that the wish is being past back to the App component. /src/App.js

  addNewWishHandler = (newWish) => {
    console.log('Adding a new wish');
    console.log(newWish);
  }

Create an element in App component's state for the wishes and store the value in the addNewWishHandler. Also display the list of wishes.

/src/App.js

class App extends Component {
  constructor(props) {
    super(props);
    this.state = { 
      wishes: []
    };
  }

  addNewWishHandler = (newWish) => {
    this.setState({ wishes: [...this.state.wishes, newWish]})
  }
  render() {
    return (
      <div>
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
        </header>
        <WishForm addNewWish={this.addNewWishHandler} />
        {this.state.wishes.map((item, index) => (
          <p>{index}: {item.name} ({item.priority})</p>
        ))}
      </div>
      );
  }
}

/src/App.js

class App extends Component {
  constructor(props) {
    super(props);
    this.state = { 
      wishes: [],
      adding: false
    };
  }

  addNewWishHandler = (newWish) => {
    console.log('Adding a new wish');
    console.log(newWish);
    this.setState({ 
      wishes: [...this.state.wishes, newWish],
      adding: false
    })
  }
  showAddWishForm = () => {
    this.setState({ 
      adding: true
    })
  }
  render() {
    console.log(this.state)
    return (
      <div>
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
        </header>
        {this.state.adding ? <WishForm addNewWish={this.addNewWishHandler} />
        : <button onClick={this.showAddWishForm}>Add a wish</button>}
        {this.state.wishes.map((item, index) => (
          <p>{index}: {item.name} ({item.priority})</p>
        ))}
      </div>
      );
  }
}

Challenge

  1. Add a textarea input field to the form for description. See example here https://reactjs.org/docs/forms.html

  2. Add a checkbox for completed to the form. See example here https://reactjs.org/docs/forms.html

  3. Update the App component to display the two new fields.

  4. Add styling to the wish list in the App component

  5. Add styling so the list does not move down the screen when the Wish Form is displayed.

Beast

Add the ability to edit a wish.
Hint: Add an id the the wishes. When a new wish is created it will be given an id.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment