RU beehive logo ITEC dept promo banner
ITEC 325
2014spring
ibarland

homelectshws
D2Lbreeze (snow day)

lect23-sticky
sticky forms

Sticky forms

A “sticky” form is one where, when you re-visit the form, your previous information is already filled in. In particular, we'll think of the scenario where somebody submits a form to the server, but the server rejects it — perhaps due to server-side validation, but it could also be because of session-timed-out, or item-out-of-stock1 or offer-has-expired, or whatever.

The html for an input form with a pre-filled value is easy: You just include the attribute value for text fields, and selected/checked for other elements:

      <label>First name: <input type='text' name='fname' value='Herman' /></label>
      <label>age: <input type='radio' name='age' value='over50' checked='checked' /></label>
      <label>ageless: <input type='radio' name='age' value='under20'/></label>
      <select name='mealplan'>
        <option>Vegetarian</option>
        <option selected='selected'>Carnivore</option>
      </select>
    

What php is used, to generate/print the above HTML?

But wait a minute: How do we use $_POST in the same page that is creating the form?! The page that makes the form has to be the same as the page that receives the form: Sticky forms submit to themselves.

example: sticky-form.php

Explanation: We originally had two files:

Although these two forms will be processed as one single page, it's still helpful to keep them as separate files, just require'ing them: we'll rename the previous-form-printing-php file to “info-form-helper.php”, and make the overall info-form.php be a wrapper:
// this is info-form.php (version 0 of 2), a wrapper for info-form-helper.php and info-handle.php
//
$errMsgs = validateAll();   // A php function which checks all other input forms, similar to our validateAll in .js soln;
                                      // returns an array-of-error-messages

if (!$errMsgs) {
  require 'info-handle.php';  // Form successfully validated
  }
else {
  print_r($errMsgs);          // Well, let's print them nicer-looking than that. But you get the point.
  require 'info-form-helper.php';    // Just like before, except sticky, and submits to 'real-form.php'
  }

This is pretty good. However, there is still one big conceptual glitch (and, some smaller practical ones): If you fill out the form and submit to this new info-form.php, things are great: $_POST exists, and we validate its info. But what about the very first time you visit the page, typing the URL directly — then $_POST is entirely empty, and our validation code will think the user left every text-field empty, and did not check any boxes, etc.. We do not want to report these as validation-errors, on the very first visit! We wish we had a magic boolean got-here-via-submitting-form, indicating whether the user is at the URL because of their submit, or something else. If we had that magical bit, we'd then have:

// this is info-form.php (version 1 of 2), a wrapper for info-form-helper.php and info-handle.php
//
$errMsgs = validateAll();   // A function which checks all other input; returns array of error-messages.
if (!$errMsgs) {
  require 'info-handle.php';
  }
else {
  if (got-here-via-submitting-form), then {
     print_r($errMsgs);      // Well, let's print them nicer-looking than that. But you get the point.
     }
  require 'info-form-helper.php';   // Just like our previous info-form.php, except sticky, and submits to this new 'info-form.php'
  }

How can we magically know if we got-here-via-submitting-form, as distinct from submitting a form? Looking at whether $_POST is populated seems reasonable, except there is the corner-case of a user submitted an entirely-empty form. In that situation, we really do want to report errors, but our script is getting a $_POST which is empty2. So if we're not careful, $_POST-being-empty isn't quite the same as !got-here-via-submitting-form.

We'll fix this discrepancy by ensuring that $_POST always has at least one value in it, even if the user doesn't fill out anything: Either:

In either case, we can use isset($_POST['submitted']) to distinguish between direct-URL arrival (false), vs via submitting a form (even if left entirely blank) (true). (Using 'submitted' as the input's name is arbitrary, but a nice convention. Using the name 'got-here-via-submitting' would be fine too.) In fact, even checking if ($_POST) would now work (since php treats the empty array as false-ish), but for readability I recommend if isset($_POST['submitted']) .

There are still some practicalities to handle:

Putting that all together, we get:
<html>
  <head><head>
  <body>

<?php
// this is info-form.php (version 2 of 2), a wrapper for info-form-helper.php and info-handle.php
//
if ($_POST) {
   $errMsgs = validateAll();   // A function which checks all other input; returns array of error-messages.
   }

if (!$errMsgs) {
  require 'info-handle.php';
  }
else {
  echo "<h3>Form title</h3";
  if ($_POST) then {
     echo "Errors exist:";
     print_r($errMsgs);      // Well, let's print them nicer-looking than that. But you get the point.
     }
  require 'info-form-helper.php';   // Just like old info-form.php, except sticky, and submits to this new 'info-form.php'
  }
?>


A note on testing:
How can you test your page, for various inputs? It's a pain to keep pulling up the form and submitting. You can automate much of this by:

           // This is the file info-form-test-1.php
           $_POST = array( 'got-here-via-submitting-form' => 'a-yep',
                           'firstName' => 'Amy',
                           'creditCardNum' => '1234-5678-8765-4321'
                         );
           require('info-form.php');
        
Then, you can redirect the output to a file and scan the results by eye in a browser: php info-form-test-1.php > info-form-test-1-out.html ; open info-form-test-1-out.html (the open command works if you are the console of a unix system -- i.e. a mac or laptop running linux).

Note that a “pure” way to go would be to use functions, instead of including files: a function infoForm( postedData ) which returns a string-of-HTML (and uses helper-functions handleForm($postedData), printInfoForm($postedData), validateAll($postedData), etc.). Having everything as a function helps enable unit testing, and software-reusability (e.g. re-use the validation component even in places unassociated with a web-form — e.g. as a sanity check after retrieving info from a database, or when importing data from elsewhere). In the last copule of weeks of the semester, we'll see xpath, which is a great technology for specifying XML requirements w/o getting bogged down in character-by-character details. If you take Software Testing (ITEC 335), you'll learn about JWebUnit to invoke a web-form and run xpath queries on the result, all from within a web-free program.


1 Of course, hopefully when an item is out of stock, the server might check that before having customers fill out the order form — perhaps before even showing the product page at all. It's more server load to do this, but much better user-friendliness. You can find a compromise by having a "check availablity" button, or checking availability when they put it into their cart, etc..      

2 Okay, text-input-boxes might be in the array mapped to the empty-string; however if our form had nothing but checkboxes, then $_POST would be truly empty after the submit.      

homelectshws
D2Lbreeze (snow day)


©2014, Ian Barland, Radford University
Last modified 2014.Apr.04 (Fri)
Please mail any suggestions
(incl. typos, broken links)
to ibarlandradford.edu
Powered by PLT Scheme