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.