tapestry-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From tapestry-...@jakarta.apache.org
Subject [Jakarta Tapestry Wiki] New: WhyNotContexts
Date Sun, 19 Dec 2004 13:54:23 GMT
   Date: 2004-12-19T05:54:23
   Editor: MikaelCluseau <nwrk@nwrk.dyndns.org>
   Wiki: Jakarta Tapestry Wiki
   Page: WhyNotContexts
   URL: http://wiki.apache.org/jakarta-tapestry/WhyNotContexts

   no comment

New Page:

Mikaƫl Cluseau

= Introduction =

The goal of this document is to provide a solution to 
the problem highlighted by the following sample, 
without changing a line of it :

'''Problem.page''' {{{
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE page-specification PUBLIC
  "-//Apache Software Foundation//Tapestry 
Specification 3.0//EN"
<!-- generated by Spindle, http://spindle.sourceforge.net -->
<page-specification class="org.apache.tapestry.html.BasePage">
    <property-specification name="fieldNames"
    <property-specification name="fieldName" 
    <property-specification name="value" 

    <bean name="required" class="org.apache.tapestry.valid.StringValidator">
        <set-property name="required" expression="true"/>

    <bean name="delegate" 


''' Problem.html''' {{{
<html jwcid="@Shell" title="Home">
<body jwcid="@Body">
<form jwcid="@Form" action="#" delegate="ognl:beans.delegate">
    <table border="0">
        <tr jwcid="@Foreach" source="ognl:fieldNames" 
            <td style="text-align: right;">
                <span jwcid="label@FieldLabel" 
                     Field name
                <input jwcid="field@ValidField"
    <input type="submit" jwcid="@Submit"/>

== The problem ==

The problem is that is you enter something in the first 
field ({{{f1}}}) and not in {{{f2}}} and {{{f3}}}, you will see that {{{f1}}} 
and {{{f3}}} field labels are in red, and {{{f2}}} and {{{f3}}} are decorated.

Analyze the generated component hierarchy :

  * Shell > Body > Form > Foreach
    * label$1 (label "f1")
    * field$1(field "f1")
    * label$2 (label "f2")
    * field$2 (field "f2")
    * label$3 (label "f3")
    * field$3 (field "f3")

I've volontary began at "label$1" and "field$1" to avoid 
naming ambiguity.

Obviously, this is because FieldLabel gets its field by 
calling {{{getComponent("field")}}}, which returns the last 
component called field that have been reached: after 
the rewind phase, it is {{{field$3}}}, which is empty, so 
{{{label$1}}} sets itself in red; {{{label$2}}} gets {{{field$1}}} so 
doesn't sets itself in red; {{{label$3}}} gets {{{field$2}}} so 
sets itself in red. Even this last case is false at the 
semantic level.

== A non-intuitive solution ==

Knowing the problem, a solution can be found on the 
Howard's blog (see [http://howardlewisship.com/blog/2004/12/back-from-shoppingcom-defer-component.html
Howard's blog]). He creates a components named {{{Defer}}} ; this component renders a block
in a buffer 
then, on its ouput, its body and the buffer. This way, 
the block is actually rendered before the field and 
then the getComponent("field") returns the expected 
component. You'll see that it works if you download my 
sample project ([TODO: URL]), but it is not very 
intuitive even at the code level: we need to put the 
label's {{{td}}} into the {{{Defer}}} and the field's {{{td}}} into the 
{{{Block}}} because otherwise the rendering is not done as it 
appears in the template (since {{{Defer}}} renders it after 
its body).

= Contexts =

== Principles ==

A context as I understand it here is a set of 
attribute-value elements and of subcontexts. It also 
specify value search in a nearest-match way: the search 
is recursive, until it finds the attribute or exhaust 
the root-context.

== Why use them ? ==

Mainly because the humain brain work with contexts, 
highlighting parts of its mind as needed. Concequently, 
the developper expects that the references to field are 
bound to the corresponding label ; I mean, the one 
within the same loop.

Using contexts to store the right reference to a 
component is a way to make templates more intuitive to 
the developper because the underlying model will 
correspond to the template's intuitive view.

== Why is it resolving our problem ? ==

It will solve our problem if the Foreach creates new 
contexts for each iteration because, then, instances of 
field will be bound to the current loop's context, and 
thus the getComponent("field") call will return this 
instance even if it is after the label in the template 
(and in the render sequence).

The tree would be :

  * {context: root}
    * Shell > Body > Form > Foreach
    * {context: Foreach@loop$1}
      * label ($1)
      * field ($1)
    * {context: Foreach@loop$2}
      * label ($2)
      * field ($2)
    * {context: Foreach@loop$3}
      * label ($3)
      * field ($3)

I put "$X" in parenthesis because I want to highlight the 
fact that now we don't event care of the instance we're 
accessing, we already know that it is the right one. 
The naming-wall of the context allows (structural) 
coherency between the template's component naming and 
the instance at the tree level.

== How to do it ? ==

We could do it quite easily if we register each 
component's instance within its container with its 
unique name and with its name suffixed by "$X" in the 
page. The main problem I see is that we may need to 
create the document's tree before processing the 
parameter binding.

Howard, I may try to do it whenever I catch some time 
and after Tapestry 3.1 has gone to the high gear...

To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org

View raw message