Page 1 of 1

Auto-fill Form Fields from User Input. Best Practice?

Posted: Tue May 18, 2004 7:25 pm
by hawleyjr
I am curious to see how other people auto-fill form fields from user input. Say you have a form that has multiple drop down boxes, radio fields, text boxes, etc. The following page validates the (user inputted) form data. If there is an error in the form data I redirect back to the form pre-fill all form fields with the previously submitted values and inform the user of the error.

My question:

How do you prefill the form fields with the user submitted data?

I typically store the $_POST var in a session variable with an error flag:

Code: Select all

<?php
//PROCESS PAGE
//$_POST
Array
(

    [fld_18_1] => hawleyjr
    [fld_19_1] => FL
    [fld_20_1] => 8
    [fld_21_1] => 555
    [fld_22_1] => 
    [fld_25_1] => 
    [fld_26_1] => AAA Insurance Co.
    [fld_27_1] => 1
    [fld_28_1] => 1
    [fld_29_1] => No
    [fld_30_1] => 
    [fld_31_1] => No Military Experience
    [fld_32_1] => Chef
    [fld_33_1] => McDonalds
    [fld_34_1] => 5
    [fld_35_1] => MY G
    [fld_36_1] => No
    [fld_43_1] => 5 YRS COMMENTS
    [fld_69] => 
    [Submit] => Submit
)

//on error
$_SESSION['USER_DATA'] = $_POST;
//redirect back to form page
?>
Text boxes are the easiest to autofill:

Code: Select all

<?php
//FORM PAGE
$a_user_data = $_SESSION['USER_DATA'];
?>
<input type="text" name="fld_18_1" value="<?php echo a_user_data['fld_18_1'];?>">
When it comes to listboxes there are a few options:

For instance, if you have a listbox of states:

Code: Select all

&lt;select name="fld_19_1"&gt;
	&lt;option value="AL"&gt;Alabama&lt;/OPTION&gt;
	&lt;option value="AK"&gt;Alaska&lt;/OPTION&gt;
	&lt;option value="AZ"&gt;Arizona&lt;/OPTION&gt;
	&lt;option value="AR"&gt;Arkansas&lt;/OPTION&gt;
	&lt;option value="CA"&gt;California&lt;/OPTION&gt;
	&lt;option value="CO"&gt;Colorado&lt;/OPTION&gt;
	&lt;option value="CT"&gt;Connecticut&lt;/OPTION&gt;
	&lt;option value="DE"&gt;Delaware&lt;/OPTION&gt;
	&lt;option value="DC"&gt;District Of Columbia&lt;/OPTION&gt;
	&lt;option value="FL"&gt;Florida&lt;/OPTION&gt;
	&lt;option value="GA"&gt;Georgia&lt;/OPTION&gt;
	&lt;option value="HI"&gt;Hawaii&lt;/OPTION&gt;
	...
	&lt;/select&gt;
I have used three different methods to auto fill a list box so the selected values are displayed.
1. Insert if Statement into each Option.
2. Call function to loop through array of values and labels.
3. Use JavaScript to setIndex onLoad.

1. Insert if statement in each <option>:

Code: Select all

<?php
		$s = ' selected';
?>	
		<option value="AL"<?php if($a_user_data[fld_19_1]=='AL')echo $s;?>>Alabama</OPTION>
		<option value="AK"<?php if($a_user_data[fld_19_1]=='AK')echo $s;?>>Alaska</OPTION>
		<option value="AZ"<?php if($a_user_data[fld_19_1]=='AZ')echo $s;?>>Arizona</OPTION>
		<option value="AR"<?php if($a_user_data[fld_19_1]=='AR')echo $s;?>>Arkansas</OPTION>
		<option value="CA"<?php if($a_user_data[fld_19_1]=='CA')echo $s;?>>California</OPTION>
		<option value="CO"<?php if($a_user_data[fld_19_1]=='CO')echo $s;?>>Colorado</OPTION>
		<option value="CT"<?php if($a_user_data[fld_19_1]=='CT')echo $s;?>>Connecticut</OPTION>
		<option value="DE"<?php if($a_user_data[fld_19_1]=='DE')echo $s;?>>Delaware</OPTION>
		<option value="DC"<?php if($a_user_data[fld_19_1]=='DC')echo $s;?>>District Of Columbia</OPTION>
		<option value="FL"<?php if($a_user_data[fld_19_1]=='FL')echo $s;?>>Florida</OPTION>
		<option value="GA"<?php if($a_user_data[fld_19_1]=='GA')echo $s;?>>Georgia</OPTION>
		<option value="HI"<?php if($a_user_data[fld_19_1]=='HI')echo $s;?>>Hawaii</OPTION>
OK, it’s easy to say how ugly and cumbersome this is. It works for small list boxes. In my opinion; poor programming practice.

2. Call a function that will loop through an array and echo out the list box:

Code: Select all

<?php
		$a_st_abrev = array('AL','AK','AZ','AR','CA','CO','CT','DE','DC','FL','GA','HI'....);
		$a_st_long_name = array('Alabama','Alaska','Arizona','Arkansas','California','Colorado',
					'Connecticut','Delaware','District Of Columbia','Florida','Georgia','Hawaii'....);
		
		$selected_value = $a_user_data['fld_19_1'];
	?>	
		<select name="fld_19_1">
			<?php 
			//FUNCTION IS LOCATED AT BOTTOM OF POST
			echo getSelectBoxOptions($a_st_long_name,$a_st_abrev,$selected_value,FALSE);
			?>
		</select>
Probably my most favorable option. My only concern is page load time. If I have a couple dozen list boxes that are over 50 elements each, how much will this drag on the page load?

3. Have JavaScript set the selected Index onLoad:

Code: Select all

<SCRIPT language="javascript">
			function setState(){
		
				fld_st = eval("document.form1.fld_19_1");
				fld_cur_len = fld_st.length;
				for(x=0;x<fld_cur_len;x++){
					if(fld_st[x].value == "<?php echo $a_user_data['fld_19_1'];?>"){
						fld_st.selectedIndex = x;
						break;
					}
				}
			}
		</SCRIPT>
		<BODY ONLOAD="setState();">
Probably my least favorite option just because it’s JavaScript and I'm now relying on my user to have the correct JavaScript browser settings.

For Radio Buttons and Check Boxes I have found the first option to be the most useful.

I am curious to find out what you do in the same circumstance is there another method I overlooked?


Code: Select all

<?php
//FUNCTION USED IN OPTION 2:
/*  ECHO OUT THE HTML NEEDED FOR A HTML LIST BOX 

	$a_displayValues	LABEL OF EACH OPTION
	$a_optionValues		OPTION VALUES
	$selected_option_value	SELECTED INDEX
	IF $a_optionValues IS NULL USE DISPLAYVALUES ARRAY KEY
	IF $echoHTML IS TRUE ECHO HTML ELSE RETURN HTML
*/

function printSelectBoxOptions($a_displayValues, $a_optionValues, $selected_option_value,$echoHTML){
	
	$html = '';
	
	$arrayCount = 0;
	foreach ($a_displayValues as $x => $v) {
		
		if($a_optionValues==null){
			$a_optionValues = array_keys($a_displayValues);
		}
	
		if($selected_option_value==$a_optionValues[$arrayCount])
			$sel = ' selected';
		else
			$sel = '';
			
	  $html.= '<option value="'.$a_optionValues[$arrayCount].'"'.$sel.'>'.$a_displayValues[$x].'</option>'."\r";
	  $arrayCount++;

	}
	if($echoHTML){
		echo $html;
		return TRUE;
	}else{
		return $html;
	}

}
?>

I usually put the Data in MySql

Posted: Tue May 18, 2004 8:33 pm
by apple
For example:

I strored the options on MySql, I just add another table on the recent database I have.

Code: Select all

<?php 

echo '<select prefix_id="$prefix">';	
	  // Display the type_id:
	$query_result = mysql_query("SELECT * FROM prefix ORDER BY id");
	 while ($row = mysql_fetch_array($query_result, MYSQL_NUM)) {
echo "<option value="$row[0]">$row[1]</option>\n";
	};
echo '</select>';
	// Tidy up (not required):
	mysql_free_result($query_result);
	mysql_close();

?>
So If I want to add additional options I dont have to rewrite the Script, I just simple add the options on MySql

Posted: Tue May 18, 2004 8:47 pm
by hawleyjr
Which is fine for populating select fields. (I don't recommend imbedding queries in HTML) But how do you auto index a select box based off of user input when the page loads?

Posted: Wed May 19, 2004 2:59 am
by dave420
I usually make an associative array tying the field names (as indices) to an array describing conditions the field has to make to be valid. These include regular expression matches, to function callbacks. It's trivial to make a function that checks these fields against, say, $_POST data. The function can even update the array, to note which fields are incorrect. If any are found to be incorrect, passing the modified array back to my templating engine allows the template to display error text next to the field (using conditions, based on the errors noted in the array).

I was fed up of having to code the problem you describe for each user-input form, and decided to make some intelligent code to do it for me. Now, the whole process can be done in a few lines of code, and is totally re-usable.

Posted: Wed May 19, 2004 1:03 pm
by hawleyjr
Dave interesting concept. I'd love to see any code examples you have.

-James

Posted: Wed May 19, 2004 1:21 pm
by jason
One of these days I will format, and post my validation stuff to the wiki. It's good stuff, and makes my life easier.

The key to validation is to go beyond regular expressions. The difference between reporting an error and fixing it for the user is immense.

Take a simple thing such as a username. If the user enters a username that's already taken, the system should provide the user with other choices of usernames that are not already taken.

Or a phone number. For example, in England, whose country code is 44, someone could enter a phone number like so:

Code: Select all

44 (020) 33445555
Now, let's say you only want numbers for the phone number. This means that the above phone number is incorrect. It's also incorrect because it doesn't have a 011 in front of it (something North American's need to dial outside North America), and there is a 0 in the front of city code (020).

However, rather than report this as an error to the user and explain to him all those rules, you can clean it up for him.

Remove the ( and ), remove the leading 0 from 020, place 011 at the beginning, and remove the spaces. It's all something you can easily do from coding using [php_man]str_replace[/php_man] and other hand functions.

Then you will have a correct phone number without having the problem of annoying the user with an error. The user, after all, entered a correct phone number.

Posted: Wed May 19, 2004 1:31 pm
by hawleyjr
I haven't dealt with international phone numbers but I do the same thing for ss# and dates

555-22-5555 same as 555225555
4.22.2004 same as 04.22.2004

Posted: Thu May 20, 2004 3:10 am
by dave420
jason - that's exactly it. You assign callbacks to correct data where you can. Automating the process means you always have a rigid structure in place to ensure your form data is validated. all good stuff :)

Posted: Thu May 20, 2004 5:59 pm
by McGruff
hawleyjr wrote:Dave interesting concept. I'd love to see any code examples you have.

-James
If dave will excuse me butting in, I think I'm using a similar system - maybe this will give you some ideas.

With a file naming convention, meta data can be dynamically included based on (for example) the module name and the module command (passed via GET).

The array below specifies two tests to be carried out on an 'id' key. 'req_exists' = true means the key must exist and 'req_val' = true means it is required to validate.

A class, or rather bunch of classes, can iterate through the lists of tests for each key described in the meta data array.

Code: Select all

<?php

$meta = array();

$meta['id']['req_exists'] = true;
$meta['id']['req_val'] = true;
$meta['id']['tests'][0]['class'] = 'IsNumeric';
$meta['id']['tests'][0]['script'] = 'lib/validation/isnumeric.php';
$meta['id']['tests'][0]['args'] = '';
$meta['id']['tests'][0]['message'] = 'Aaaargh!'; // optional custom message which overides the default in the IsNumeric class

$meta['id']['tests'][1]['class'] = 'InRange';
$meta['id']['tests'][1]['script'] = 'lib/validation/inrange.php';
$meta['id']['tests'][1]['args'] = array('min'=>4, 'max'=>50);

return $meta;

?>
In between unavoidable bouts of employment, I'm trying to finish off a "Firewall" class which acts as a proxy for GPC input.