Forum OpenACS Q&A: Re: double deference in template

Posted by Gustaf Neumann on
As hsin wrote, he asked for the double substitution (first replace in the template the attribute names, then evaluate the multirow with the passed in datasource). As written above, this is more tricky, and used as well in OpenACS for e.g. the list templates. I would not recommend this for beginners, but here it goes:

First, one has to protect in the template content with "noparse", which should not be substituted in the first substitution step. The attribute names and labels are passed via @value_var@ and @label_var@.

    <noparse><multiple name="datasrc"></noparse>
       <option value="@datasrc.@value_var@@">
We assume that the template above is e.g. saved in the global www directory. When we define a function "adp_double_subst", we can provide a .tcl page with a multirow as follows.
db_multirow table table_query {
  select object_id, title from acs_objects order by object_id desc limit 10

set html [adp_double_subst /www/select-widget {&datasrc "table" value_var object_id label_var title}]

ns_return 200 text/plain $html
Finally, the proc adp_double_subst is defined below. As mentioned, not for beginners, but maybe it helps to understand the problem better, and maybe someone has usage for this code.

all the best

ad_proc adp_double_subst {__src __args} {
    This proc is in its interface similar to template::adp_include,
    but it handles double de-references of ADP variables and returns
    the resulting HTML.
} {
    set __file [template::util::url_to_file $__src]
    set __code [template::adp_compile -file $__file.adp]

    # Handle passed-in argument lists, by turning argument list into
    # local variables. So be careful with local variable names to
    # avoid unwanted interactions with the imported ones.
    foreach {__key __value} $__args {
        if {[string match "&*" $__key]} {    
            # names starting with "&" flag call by reference
            if {"&" ne $__key } {
                set __name [string range $__key 1 end]
            } else {
                set __name $__value
            upvar \#[adp_level] $__value $__name \
                $__value:rowcount $__name:rowcount \
                $__value:columns  $__name:columns

            # upvar :rowcount and :columns just in case it is a multirow
            if { [info exists $__name:rowcount] } {
                for { set __i 0 } { $__i <= [set $__name:rowcount] } { incr __i } {
                    upvar \#[adp_level] $__value:$__i $__name:$__i
        } else {
	    # var names not starting with a "&" => normal args (no reference)
            set $__key $__value
    # Evaluate the template code
    set __template [template::adp_eval __code]

    # Now we have plain template, with the first evaluation level
    # removed. Perform the standard template compilation and
    # evaluation and return the resulting HTML.
    set __code [template::adp_compile -string $__template]
    lappend ::template::parse_level [expr {[info level] -1}]
    set __html [template::adp_eval __code]
    template::util::lpop ::template::parse_level
    return $__html