CSE 154

Lecture 16: Form Submission and Validation Methods

Agenda

Wrapping up Module 3 material

HW3 Milestone is due tonight (lock date also tonight)

Exploration Session Today!

Review: When to use GET vs. POST

GET

  • Requesting data from a server using filters (URL parameters)
  • Should never be used when dealing with sensitive data
  • Can be cached and bookmarked, remains in browser history
  • Examples: search queries, retrieving initial page content

POST

  • Data sent in the HTTP message body, not the URL
  • Not cached or bookmarked, no restrictions on data length
  • Examples: Signing up, logging in, sending messages to a blog, etc.

These POST examples are commonly used with forms!

Posting data with Forms

There are two ways you'll commonly see forms used with POST

  • Older: With method/action attributes in HTML form tag
  • Better: With JS using validation and AJAX

Posting with method/action attributes in <form> tag

<form id="input-form" method="post" action="submitter.php">
  City: <input name="city" type="text"/ >
  State: <input name="state" type="text" />
  ZIP: <input name="zip" type="number" />
  <button id="submit-btn">Submit!</button>
</form>

HTML

As soon as the submit button is clicked on this page, the data is sent to the web service (submitter.php) and the page is refreshed with the response (sometimes redirecting).

This is becoming less common because we lose the asynchronous features of requests.

Approach 2: Posting data through JS/AJAX

<form id="input-form">
  City: <input name="city" type="text"/ >
  State: <input name="state" type="text" />
  ZIP: <input name="zip" type="number" />
  <button id="submit-btn">Submit!</button>
</form>

HTML

let url = "submitter.php";
let data = new FormData(id("input-form"));
fetch(url, { method : "POST", body : data })
  .then(checkStatus)
  .then(...)
  .catch(...)

JS

Compare this new submit behavior here.

What do you think are the trade-offs between the two approaches?

Approach 2: Requires Preventing Default Submit Behavior

When an input is in a form along with a button, clicking the button automatically verifies the input and does a POST request. If you are not sending a POST form, you may find it helpful to use preventDefault to override default form submission behavior (used in previous example).

function init() {
  id("input-form").addEventListener("submit", function(e) {
    // Fires when submit event happens on form
    // If we've gotten in here, all HTML5 validation checks have passed
    e.preventDefault(); // prevent default behavior of submit (page refresh)
    submitRequest(); // do more validation with JS and then fetch with FormData
  });
  // rest of code

JS

Validation with HTML/CSS/JS

Many websites offer features that allow users to interact with the page and request/submit data to servers. Unfortunately, not all users will behave as expected.

Take a look at your handout and talk with your neighbors to answer the questions (handout also provided here).

User Input Validation

User input validation is the process of ensuring that any user input is well-formed and correct (valid).

Q: What are some examples of input validation you came up with?

  • Preventing blank values (e-mail address)
  • Verifying the type of values (e.g. integer, real number, currency, phone number, Social Security Number, postal address, email address, data, credit card number, ...)
  • Verifying the format and range of values (ZIP code must be a 5-digit integer)
  • Extra layer of confirmation (e.g. user types email twice, and the two must match)

A Real-World Example Form that Uses Validation

Validation Form Example

Real-World Example with Validation Feedback

Validation Form Example with Error Feedback

When To Validate Data?

Validation can be performed:

  • Client-side (before any user input is submitted to a server)
    • Can lead to a better user experience, allows for real-time feedback for invalid input. But shouldn't be used for user verification
  • Server-side (e.g. in PHP program, after user input is sent to the server)
    • Needed for truly secure validation, but slower
    • Should not skip this step under assumption that client-side validation was enough (why can't we trust all requests from a client?)
  • Both:
    • Best mix of convenience and security, but requires most effort to program

Why Prioritize Input Validation?

Prioritizing validation is important for building websites that are:

  1. User-friendly
  2. Secure

If you're interested in learning more, MDN has a good quick introduction to web security, and OWASP is a fantastic resource for all things related to web security. You can also find a good article on how to write user-friendly form UIs here.

The takeaway? There are many ways to perform validation, but MDN/OWASP both are great resources to refer to based on the context of your websites

Most importantly, don't trust that users will provide correct/safe input!

Back to our Form Example

<form>
  <label for="city-input">City: </label>
  <input name="city" type="text" />
  <label for="state-input">State: </label>
  <input name="state" type="text" />
  <label for="zip-input">ZIP: </label>
  <input name="zip" type="number" />
  <button id="submit-btn">Submit!</button>
</form>

HTML

City: State: ZIP:

output

We can validate this input in a few different ways:

  1. Client-side: HTML5 form elements and input tag attributes
  2. Client-side: JS before sending this form data to the server (e.g. a PHP web service)
  3. Server-side: PHP (later)!

HTML5 Input Validation

We've already seen some ways to use HTML5 tags to require certain types of input by adding attributes to your <input> tags to help with validation

<input type="number">

HTML

We can limit the up and down arrows with min (and max if we choose)

<input type="number" min=0>

HTML

To insist that there is a value in the input field we can add required

<input type="number" required>

HTML

To prevent a user from being able to type in erroneous values, we can add a regular expression to the required attribute

<input type="number" required="\d+">

HTML

Basic HTML5 Validation with our basic form

<form>
  <label for="city-input">City: </label>
  <input name="city" type="text" required/>
  <label for="state-input">State: </label>
  <input name="state" type="text" size="2" maxlength="2" required/>
  <label for="zip-input">ZIP: </label>
  <input name="zip" type="number" size="5" min=10000 max=99999 required/>
  <button id="submit-btn">Submit!</button>
</form>

HTML

City: State: ZIP:

Forms are HTML elements that can be used to "package" user input values baesd on the name attribute, often used with POST requests. There are many neat ways to perform validation with the right choice of form elements!

The Importance of the <label> in Forms

The label is important when building forms (especially today) to aid assistive technology in reading the form elements. Each text label should be wrapped in a label tag, and include the "for" attribute with the id of the labeled element.

<label for="name-input">Name: 
  <input type="text" id="name-input" name="student-name" />
</label>

HTML

This is read by most screenreaders as "Name, edit text"

More information here.

You can also get the ChromeVox Chrome Extension to test what screenreaders would say on your webpages!

Short Case Study: WPL Queue!

Validation Form Example

Solution code (try adding more validation methods on your own!):

wpl.html Form (with Validation Attributes)

<form id="input-form">
  <div>
    <label for="name-input">Name: </label>
    <input id="name-input" name="student-name" type="text" required/>
  </div>
  <div>
    <label for="email-input">E-mail (@uw.edu): </label>
    <input id="email-input" name="email" type="email" required/>
  </div>
  <div>
    <label for="sid-input">Student Number: </label>
    <!-- 
      A valid student number is 7 digits; demo considering students between 2010 (min) and 2019
      (max) to demonstrate min/max
    -->
    <input id="sid-input" name="sid" type="number" min=1000000 max=1999999 />
  </div>
  <div id="minute-options">
    <label>2-Minute Question <input type="radio" name="minutes" value=2 /></label>
    <label>10-Minute Question <input type="radio" name="minutes" value=10 /></label>
  </div>
  <textarea name="question" minlength=20 rows=10 placeholder="Enter your question..."></textarea>
  <button id="submit-btn" type="submit">Enter Queue!</button>
</form>

HTML

wpl.js - Preventing Default Form Submit Behavior

/**
 * Override the default submission behavior for the form's submit event.
 */
function initialize() {
  id("input-form").addEventListener("submit", function(e) {
    // if we've gotten in here, all HTML5 validation checks have passed
    e.preventDefault(); 
    submitRequest();
  });
}

wpl.js

wpl.js - Sending Form Data with POST (with form argument)

/**
 * Send form data to the WPL web service. Note that this function 
 * is called only after all HTML5 validation constraints 
 * (e.g. required attributes) have passed!
 */
function submitRequest() {
  // Solution 1: Can use form DOM element as parameter to FormData!
  let formData = new FormData(id("input-form"));

  // Note that unlike GET requests, no url parameters passed in a POST request!
  fetch(URL, { method : "POST", body : formData })
    .then(checkStatus) // The wpl.php will return text for this demo, no JSON
    .then(showResponse)
    .catch(handleError);
}

wpl.js

This submitRequest() function is called in the overriden submit behavior (from previous slide).

wpl.js - Sending Form Data with POST (Another Solution)

/**
 * Send form data to the WPL web service. 
 */
function submitRequest() {
  let formData = new FormData();

  // Build the 4 parameters for our POST request
  formData.append("sid", qs("input[name='sid']").value);
  formData.append("name", qs("input[name='name']").value);
  formData.append("minutes", qs("textarea").value);
  formData.append("question", qs("input[name='minutes']:checked").value);

  fetch(URL, { method : "POST", body : formData })
    .then(checkStatus) 
    .then(showResponse)
    .catch(handleError);
}

wpl.js

As shown on Monday, we can also use the append method to append parameters one at a time (in this example, wpl.php only expects the 4 POST parameters)

While this is a bit more work, we don't always need to send all form elements in an API request, and it also gives us more control over validation checks in JS (for properties you can't check with HTML5 attributes) before the fetch.

Friday: From Client to Server

Friday we will be starting Module 4 (PHP), where you will learn how to handle the requests you have been sending as clients!

An interactive "PHP Basics" Tutorial is posted for Friday! Please play around a bit with the language before Friday!