Delphi Clinic C++Builder Gate Training & Consultancy Delphi Notes Weblog Dr.Bob's Webshop
Dr.Bob's Delphi Notes Dr.Bob's Delphi Clinics Dr.Bob's Delphi Courseware Manuals
 Dr.Bob Examines... #20
See Also: other Dr.Bob Examines columns or Delphi articles

Kylix & Delphi WebBroker Multi-Valued Input Fields
When using Delphi's WebBroker Technology to produce web server applications, we can use HTML forms to obtain user input, which is transferred from the browser to the web server application itself (using the GET or POST protocol). With single-value input fields on a HTML form, we can use the Values property of QueryFields (GET) or ContentFields (POST) to get their value. Sometimes, however, we need to use multivalue input fields (like a multi-select listbox), see below:
  <form action="eBob42.exe" method="post">
  Delphi Version:
  <select name="Delphi" multiple>
    <option value="D1"> Delphi 1
    <option value="D2"> Delphi 2
    <option value="D3"> Delphi 3
    <option value="D4"> Delphi 4
    <option value="D5"> Delphi 5
    <option value="D6"> Delphi 6
  </select><br>
  <input type="reset" value="Reset Query">
  <input type="submit" value="Submit">
</form>
For the above example, ContentFields.Values property still only returns the first value for Delphi, and not the rest! The ContentFields property is of type TStringList, which means I can use the Values property to search for the value of specific strings (i.e. "Delphi") and get their value:
  procedure TWebModule1.WebModule1WebActionItem1Action(Sender: TObject;
    Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
  begin
    Response.Content := 'Delphi = ' +
      Request.ContentFields.Values['Delphi'];
  end;
As you can see from the listing above, I use the Request.ContentFields to search for (all of) the values of the Delphi input field, and put them in the Response.Content field. Unfortunately, we only get one value (the first) of the Delphi field. Only "D1" is returned, and not "D5" or "D6":
  Delphi=D1
The property Values of a TStrings or TStringList object only returns the first match for Delphi, and never even indicates that more matches exist.

Multi-Valued Input Fields
Are the second and thirs values present in the Request object in the first place? Well, the ContentFields can not only be accessed through the Values property, but also through their Strings properties. These are of the form "Name=Value", like "Delphi=D1", "Delphi=D5" and Delphi=D6". Knowing that, it's easy to loop through the ContentFields and print the items that start with Delphi=

  procedure TWebModule1.WebModule1WebActionItem1Action(Sender: TObject;
    Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
  var
    Str: String;
    i: Integer;
  begin
    Str := '';
    for i:=0 to
      Pred(Request.ContentFields.Count) do
      if Pos('Delphi=',Request.ContentFields.Strings[i]) = 1 then
        Str := Str + Request.ContentFields.Strings[i] + '&';
    Response.Content :=
      Copy(Str,1,Length(Str)-1)
  end;
This time, we can report all possible values for the Delphi field (including fieldnames):
  Delphi=D1&Delphi=D5&Delphi=D6
Although we have now found a way to obtain all values for the Delphi name, I want to continue a little bit and end with a solution which is more flexible (and that can also be used outside the WebBroker domain).

Collecting Values
A colleague of mine, Micha Somers, found it more convenient to walk through the entire list of ContentFields and produce another StringList that only contained those field values for a specified fieldname. This lead to the following routine, which has the additional benefit that it can be called with the ContentFields but also with the QueryFields as argument:

  procedure GetStringsValues(AStrings: TStrings;
    AKey: String; AValueList: TStringList);
  var
    FieldValue: String;
    i, match: Integer;
  begin
    AKey := AKey + '=';
    for i:=0 to Pred(AStrings.Count) do
    begin
      FieldValue := AStrings.Strings[i];
      if Pos(AKey, FieldValue) = 1 then
      begin
        match := Pos('=', FieldValue);
        if match > 0 then
          AValueList.Add(Copy(FieldValue,
           match+1, Length(FieldValue)-match))
      end
    end
  end;
Note that I could also have used the Names property to compare the AKey with Names[i]. Name only contains the key names. And also note that I could not have used Values[i] to obtain the value easily, because Values - as we saw earlier - is indexed with a string (the name), and not with an integer.


This webpage © 2001-2010 by Bob Swart (aka Dr.Bob - www.drbob42.com). All Rights Reserved.