Handling Multiple Item HTML Select Inputs with 4D 6.5


ACI - Documentation Français English German ACI Technical Notes ACI Technical Notes, By Subject Back Previous Next Find

Handling Multiple Item HTML Select Inputs with 4D 6.5

By Eric Saltzen, 4D, Inc. Technical Support

Technical Note 01-8

Technical Notes for Technical Notes for 01-02 February 2001

Introduction


In an HTML form, a SELECT input allows the user to make a selection from a list of choices. The addition of the MULTIPLE keyword to this tag allows more than one entry to be selected from the list of choices (usually by holding down Control or Shift while selecting elements in the browser). Optionally, a SIZE attribute can be used to set the size of the list box used to present the choices to the user. For more information refer to your favorite online or printed HTML reference on forms.

When multiple items are selected on this type of form element, they will each be passed to the web server with the same name. The decoding method has to be smart enough to recognize multiple values associated with the same name.

657MultipleItemSelect


657MultipleItemSelect is a sample database (available in both Mac and PC format) that shows how to properly handle Multiple Item HTML Select submissions. If you examine its Database Properties, you will find that 657MultipleItemSelect is set to Publish Database at Startup on Port 80, Start without Context, and has a default HTML Root and Home Page set. Also, "Use 4DVAR Comments instead of Brackets" is checked. The database contains five methods: On Web Connection, AcceptForm01, DecodeURLText, HexToDec, and ProcessMultipleItemSelect. There are four HTML pages which were created by hand: getform.html, index.html, postform.html and results.shtml. The file index.html simply contains two links: one to getform.html which is a test form submitted via the GET method, and one to postform.html which is a test form submitted via the POST method. Lastly, the file results.html is used to echo the results of either form test back to the web browser. In this database I am not storing the submitted values in the database, but it should be clear how to accomplish that by studying the methods.

Regarding the two different methods of submitting forms to a web server: the GET method places the entries on the form after the form ACTION URL for parsing by the web server, the POST method places the entries on the form after the HTTP header in a separate block. The GET method lends itself to database queries and the like, because a page that is reached from a GET form submit can be bookmarked successfully (the terms of the search will be present in the bookmarked URL). However, there is a browser implementation-specific limit on the allowed length of URLs that restricts the amount of data that can be passed in this manner (approximately 4K for some browsers). The POST method allows greater amounts of data to be submitted from an HTML form, and has the advantage that the data will be passed transparently to the web server without the end user seeing it in the web browser's location/address bar. Of course, the page that is returned as a result of a POST form submission will in all likelihood be impossible to bookmark — the form data that was passed to the web server will be lost since it is not contained in the URL.

On Web Connection


  ` Database Method - On Web Connection
  ` Eric Saltzen, December 2000
  ` 4D, Inc. Technical Support
  ` The purpose of this routine is to collect the results of a POST method HTML
  `   form  submission (from "postform.html") including a multiple item select.
C_TEXT($1;$2;$3;$4;$5;$6)  ` required for compilability
C_TEXT(gameSystems;Experienced)
C_INTEGER($i)

Case of 
   : ($1="/4DCGI/Form01")  ` process special form #01 - video game system select
      ARRAY TEXT(atGameSystems;0)
      $itemsFound:=ProcessMultipleItemSelect ("GameSystems";$2;->atGameSystems)
         ` PREPARE TO SEND ECHO OF RESULTS BACK TO BROWSER
      gameSystems:=Char(1)  ` indicates a text var containing HTML code
      For ($i;1;$itemsFound)  ` transform array results into a block of HTML
         gameSystems:=gameSystems+Mac to ISO(DecodeURLText (atGameSystems{$i}))+"<br>"
      End for 
      If (Experienced#"Yes")  ` set text that will be displayed between "Is" and "Experienced" in results.shtml
         Experienced:="not "
      Else 
         Experienced:=""
      End if 
      SEND HTML FILE("results.shtml")  ` echo back user web entries
         ` additional form handler cases can be inserted here
End case 

AcceptForm01

  ` Project Method - AcceptForm
  ` Eric Saltzen, December 2000
  ` 4D, Inc. Technical Support
  ` The purpose of this routine is to collect the results of a GET method HTML
  `    form submission (from "getform.html") including a multiple item select.
C_TEXT($1;Name;Experienced)  ` required for compilability
ARRAY TEXT(atName;0)
ARRAY TEXT(atExperienced;0)
ARRAY TEXT(atGameSystems;0)

$itemsFound:=ProcessMultipleItemSelect ("Name";$1;->atName)
If ($itemsFound>0)
   Name:=atName{1}  ` this is not a multiple select, just take first value found
End if 
$itemsFound:=ProcessMultipleItemSelect ("Experienced";$1;->atExperienced)
If ($itemsFound>0)
   Experienced:=atExperienced{1}  ` this is not a multiple select, just take first value found
End if 
$itemsFound:=ProcessMultipleItemSelect ("GameSystems";$1;->atGameSystems)
   ` PREPARE TO SEND ECHO OF RESULTS BACK TO BROWSER
gameSystems:=Char(1)  ` indicates a text var containing HTML code
For ($i;1;$itemsFound)  ` transform array results into a block of HTML
   gameSystems:=gameSystems+Mac to ISO(atGameSystems{$i})+"<br>"
End for 
If (Experienced#"Yes")  ` set text that will be displayed between "Is" and "Experienced" in results.shtml
   Experienced:="not "
Else 
   Experienced:=""
End if 
SEND HTML FILE("results.shtml")  ` echo back user web entries
      ` additional form handler cases can be inserted here

DecodeURLText

  ` Project Method - DecodeURLText
  ` Eric Saltzen, December 2000
  ` 4D, Inc. Technical Support
  ` The purpose of this routine is to convert a string from URL Character Encoding
  `    into plain text. This is necessary because data coming from a web browser as
  `    the result of a form submission must be written using only the displayable
  `    characters in the US-ASCII character set. If any unsafe, reserved, or non-
  `    printable characters occur they must be encoded in a special form.
  ` URL Character Encoding consists of a percent sign followed by two hexadecimal
  `    digits corresponding to the value of the character in ASCII. Form submits
  `    also use the plus symbol in place of any spaces in the data (literal % or +
  `    characters in the form data, if they occur, will be encoded as %25 and %2B).
  `For more information see:
  `    URL-encoding is defined in RFC 2396, section 2.4 
  `    http://www.cis.ohio-state.edu/htbin/rfc/rfc2396.html
  `
  `    URL Encoding Explained
  `    http://blooberry.com/indexdot/html/topics/urlencoding.htm
  `
  ` This routine expects one text parameter and returns the decoded text
  ` $1 - URL Encoded text

C_TEXT($0;$1;$encodedText;$decodedText)
C_INTEGER($i)

$decodedText:=""
$encodedText:=Replace string($1;"+";" ")  ` first things first, replace + chars with spaces
For ($i;1;Length($encodedText))  ` now we search for % encoded chars and convert
   If ($encodedText[[$i]]#"%")  ` not a percent symbol?
      $decodedText:=$decodedText+$encodedText[[$i]]  ` pass it through unchanged
    Else   ` grab 2 chars after % and pass to HexToDec utility function, get Char. from code
      $decodedText:=$decodedText+Char(HexToDec ($encodedText[[$i+1]]+$encodedText[[$i+2]]))
      $i:=$i+2  ` skip over the chars that have just been decoded (%XX)
   End if 
End for 
$0:=ISO to Mac($decodedText)  ` necessary because we are processing raw browser output

HexToDec

  ` Project Method - HexToDec
  ` Eric Saltzen, December 2000
  ` 4D, Inc. Technical Support
  ` The purpose of this routine is to convert a string of hexadecimal digits in the
  `    form of a text variable into the equivalent decimal, integer representation.
  ` A maximum of 8 hex digits are accepted due to the fact that anything larger
  `    could not be held in a LONGINT variable which maxes out at 2^31-1 or
  `    7FFFFFFF hexadecimal. Also, negative numbers are not considered here.
  ` This routine expects one text paramater and returns a number
  ` $1 - Hexidecimal String (up to 8 hex digits)

C_LONGINT($0;$result)
C_TEXT($1)
C_STRING(8;$hexValue)
C_INTEGER($i;$digit)

$hexValue:=$1  ` here 4D will truncate contents of $1 if it is more than 8 chars long
$result:=0
For ($i;Length($1);1;-1)  ` start with least significant (rightmost) digit and work backwards
   Case of   ` it might be quicker to calculate numeric digits via their ASCII offsets
   : ($hexValue[[$i]]="1")  ` but for simplicity's sake we'll just use a big case statement
      $digit:=1
   : ($hexValue[[$i]]="2")
      $digit:=2
   : ($hexValue[[$i]]="3")
       $digit:=3
   : ($hexValue[[$i]]="4")
      $digit:=4
   : ($hexValue[[$i]]="5")
      $digit:=5
   : ($hexValue[[$i]]="6")
      $digit:=6
   : ($hexValue[[$i]]="7")
      $digit:=7
   : ($hexValue[[$i]]="8")
      $digit:=8
   : ($hexValue[[$i]]="9")
      $digit:=9
   : ($hexValue[[$i]]="A")  ` 4D char. comparisons aren't case sensitive, no need to check for "a"
       $digit:=10
   : ($hexValue[[$i]]="B")
      $digit:=11
   : ($hexValue[[$i]]="C")
       $digit:=12
   : ($hexValue[[$i]]="D")
      $digit:=13
   : ($hexValue[[$i]]="E")
       $digit:=14
   : ($hexValue[[$i]]="F")
      $digit:=15
    Else 
      $digit:=0
    End case 
   $result:=$result+($digit*(16^(Length($1)-$i)))  ` the magic formula ('^' is the power function)
End for 
$0:=$result

ProcessMultipleItemSelect


  ` Project Method - ProcessMultipleItemSelect
  ` Eric Saltzen, December 2000
  ` 4D, Inc. Technical Support
  ` The purpose of this routine is to collect the values of multiple selects 
  `    submitted thru an HTML input form into an array of results. It can be used
  `    either from On Web Connection in the case of a POST method HTML form
  `    called via a /4DCGI form action, -or- from any 4D method in the case
  `    of a GET method HTML form called via a /4DACTION form action.
  ` Note that in the case of a GET method HTML form, 4D's built in form
  `    processing function will not operate on regular (non-multiple) inputs;
  `    however, this routine can be called on all types of inputs - it will simply
  `    return an array with a single entry in the case of non-multiples.
  ` Last but not least it will be necessary to call the companion method
  `    DecodeURLText on the results returned from this method when processing
  `    a POST method HTML form to transform %XX codes into ASCII.
  ` This routine expects three paramaters and returns the number of items found
  ` $1 - HTML name of the input to search for
  ` $2 - input text to parse for multiple item selects
  `     (normally: the HTTP Header in $2 for POST, or the URL in $1 for GET)
  ` $3 - pointer to an empty text array to hold the results

C_INTEGER($0;$beginAt;$ampAt;$endAt;$vlElem)
C_TEXT($1;$2;$selectName;$inputText;)
C_POINTER($3)

$selectName:=$1+"="  ` standard syntax is INPUTNAME=blahblah
$inputText:=$2  `reassign for manipulation

If (Size of array($3->)#0)
   $0:=-1  ` ERROR passed a non-empty array for results
Else 
   $beginAt:=-1  ` initialize loop exit flag
   While ($beginAt#0)  ` as long as we find more input values, keep looking
      $beginAt:=Position($selectName;$inputText)  ` find the next input assignment in text
      If ($beginAt#0)  ` got one
         $inputText:=Substring($inputText;$beginAt+Length($selectName))  ` chop off preceding text
         $ampAt:=Position("&";$inputText)  ` look for an ampersand which is input separator
         $endAt:=Length($inputText)+1  ` first, assume we are at the end of the header text
          If (($ampAt#0) & ($ampAt<$endAt))  ` but if we found an ampersand earlier, use that...
             $endAt:=$ampAt
         End if 
         $vlElem:=Size of array($3->)+1
         INSERT ELEMENT($3->;$vlElem)  ` append an element to our array of results and
         $3->{$vlElem}:=Substring($inputText;1;$endAt-1)  ` assign the string we isolated into it
      End if 
   End while 
   $0:=Size of array($3->)  ` return a count  the number of values found
End if 

Summary


This Tech Note and accompanying sample database gives 4D methods that can process multiple items HTML selects, placing the results into arrays for processing. I hope they will be of use to you in your web-enabled database projects.

A Note Regarding 4th Dimension 6.7


Originally I had planned to do another version of this Tech Note for 4th Dimension 6.7. However, with the addition of the GET WEB FORM VARIABLES command in v6.7 the processing of multiple item selects becomes trivial. So if all the above code seems a bit like overkill for you just to handle a standard HTML form element, I recommend you upgrade to 4th Dimension version 6.7 immediately!


ACI - Documentation Français English German ACI Technical Notes ACI Technical Notes, By Subject Back Previous Next Find