Forum OpenACS Q&A: "template:multirow create" for customizable fields

I'm trying to create a multirow to show some user custom fields. These fields' names will vary in each case depending on how the administrator defines them. I've tried with this code but it doesn't work:

set custom_field_list [db_list custom_fields "select field_name from
user_custom_fields"]

template::multirow create user_custom [join $custom_field_list " "]
Something similar happens when I try to get values for these fields from a form with ad_page_contract. As I don't know the fields' names I tried:
set field_list [db_list custom_fields "select field_name from
user_custom_fields"]

set form_variables ""
foreach field $field_list {
    append form_variables "$field:optional 
"
}

ad_page_contract {
} {
    $form_variables
}
But it doesn't work. Can somebody help me?
Esti,

You can't do template::multirow create the way you do, because the [join] command delivers all the column names as one argument (i.e., as one Tcl string).

You can either say something like:

eval "template::multirow create user_custom [join $custom_field_list " "]"

Or you can say

template::multirow create user_custom
foreach field $custom_field_list {
    template::multirow extend user_custom $field
}

With ad_page_contract, the whole intent of introducing ad_page_contract was to ensure that you explicitly enumerated all the variables you wanted, so you don't risk accidentally overriding some local variable that you happened to be using in the script, or other nasty business like that.

Instead, we introduced the :array feature, where you can get all the variables you want, but within a limited area of potential damage.

If you name your form variables

custom_vars.some_var
custom_vars.other_var
custom_vars.third_var

You can have an ad_page_contract saying:

ad_page_contract { ... } {
    custom_vars:array
}

And then you can access the values

$custom_vars(some_var)
$custom_vars(other_var)
$custom_vars(third_var)

If you want it to be a bit more strict, you can write a -validate block which checks against the query.

Hope this helps.

Thanks a lot Lars. May I ask another question? How can I now show the values for these fields in the associated adp? I mean, I don't know the names of these fields, nor how many they are, so the value for each one is @user_custom.????@
Hm. Perhaps you're screwed there.

I mean, you could always write some Tcl code in <% ... %> to do what you need to do. Not very pretty, but it'd work.

Other than that, I don't have any good ideas. The templating system wasn't designed for generic data structures, and you're trying to squeeze something out of it that it wasn't designed for.

Anybody else?

In your initial question you should be able to do


set form_variables ""
foreach field $field_list {
    append form_variables "$field:optional 
"
}

ad_page_contract {
} $form_variables
I am not sure if that is applicable to your problem, but maybe you could structure it this way: create one row in the multirow for each field_name/value pair plus a number that identifies the row that this pair actually belongs to, then you can use the <group> tag in the adp file to group the actual rows together, without knowing the field names before.

So the tcl file would contain something like this:

template::multirow create user_custom custom_row field_name value

set row_counter 0
loop_through_rows {
  loop_through_fields_of_one_row {
    template::multirow append user_custom $row_counter $field_name $value
  }
  incr row_counter
}

and the .adp file that:
<multiple name=user_custom>
<group column=custom_row>
@user_custom.field_name@: @user_custom.value@
</group>
<hr>
</multiple>
This will be ugly because each row will be separated by a hr tag only, but it could be easily formatted in a table too.
Thank you all for your help. Tilmann, I kind of made it with your suggestion. I guess I chose something a bit complicated to start with the templating system.
Thanks again!