okay, yes thanks, that is what I meant (I was thinking of the example
where the key was a string), thanks for the clarification.

On Tue, Oct 19, 2010 at 2:29 PM, Blake Sullivan
<[email protected]> wrote:
>  If keyPassThru is true, I think that the id will be the stringified version
> of the key.
>
> -- Blake
>
> On 10/19/10 1:23 PM, Andrew Robinson (JIRA) wrote:
>>
>>     [
>> https://issues.apache.org/jira/browse/TRINIDAD-1940?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12922705#action_12922705
>> ]
>>
>> Andrew Robinson commented on TRINIDAD-1940:
>> -------------------------------------------
>>
>> Okay, I'd like to tweak the design. A problem I found is that
>> CollectionModel produces object row keys, not string, and a Map may not have
>> a ID-friendly string key.
>>
>> I'd like to also add a new attribute on the tr:forEach tag -- keyPassThru
>> which is a boolean property that defaults to false. If true, the key from
>> the collection model row key or the map would be used in the ID directly,
>> without translation, using the toString() function. If false, the default,
>> the forEach loop would create a token to represent the key (auto
>> incrementing integer).
>>
>> As a result, I'd like to add two properties onto the varStatus, key and
>> id. The former, key, would be the raw key from the model or collection
>> model. The latter, id, would be the value used to suffix onto the component
>> IDs. If keyPassThru is set to true, the key and ID would be the same.
>>
>> Example:
>> <tr:forEach var="item" items="#{bean.collectionModel}" keyPassThru="true"
>> varStatus="vs">
>>   <tr:outputText value="This is true: #{vs.key eq vs.id}" />
>> </tr:forEach>
>>
>> <tr:forEach var="item" items="#{bean.collectionModel}" varStatus="vs">
>>   <tr:outputText value="This is false: #{vs.key eq vs.id}" />
>> </tr:forEach>
>>
>> This also allows the code to use smaller ID suffixes and the keys could be
>> non-ID friendly with this change.
>>
>>> Problems with the tr:forEach
>>> ----------------------------
>>>
>>>                 Key: TRINIDAD-1940
>>>                 URL: https://issues.apache.org/jira/browse/TRINIDAD-1940
>>>             Project: MyFaces Trinidad
>>>          Issue Type: Bug
>>>          Components: Components
>>>    Affects Versions: 2.0.0.3-core
>>>            Reporter: Andrew Robinson
>>>            Assignee: Andrew Robinson
>>>
>>> The tr:forEach tag has issues when trying to use component references and
>>> trying to keep the component state in sync with the items in a list. It also
>>> does not support Maps like the c:forEach tag does.
>>> I seek to improve the forEach tag in Trinidad, and propose that JSF/JSTL
>>> does something similar so that user's can really use the for each tag
>>> without issues. Some of the for each problems are described in my blog:
>>>
>>> http://drewdev.blogspot.com/2008/08/cforeach-with-jsf-could-ruin-your-day.html
>>> I propose to address each of the issues with the JSP tag.
>>> First, reliable component references:
>>> <tr:forEach var="item" items="#{myBean.items}">
>>>   <tr:panelGroupLayout id="pgl1" layout="horizontal">
>>>     <tr:inputText id="it1" label="Enter value:" value="#{item.text}"
>>> autoSubmit="true" />
>>>     <tr:outputText id="ot1" value="Value is: #{item.text}"
>>> partialTriggers="it1" />
>>>   </tr:panelGroupLayout>
>>> </tr:forEach>
>>> The problem is that the author intended the output text component to
>>> partially updated by the sibling input text when it changed value, but that
>>> is not the result. Instead, the partial triggers is always "it1", but the
>>> generated input text components are "ot1", "ot1j_id_1" and "ot1j_id_2". The
>>> result is that the output text components all partially update only when the
>>> first input text is changed.
>>> Another problem is that the indexed value expressions and the var status
>>> map that is put into the variable mapper by the for each loop is static.
>>>  Take the following example:
>>> <tr:panelGroupLayout id="pgl1" layout="scroll">
>>>   <tr:forEach var="item" items="#{myBean.items}" varStatus="vs">
>>>     <tr:outputText id="ot1" value="This is the last item in the list:
>>> #{vs.last}. Item #{item.text}." />
>>>   </tr:forEach>
>>> </tr:panelGroupLayout>
>>> Say during the first pass, the items in the list are A, B and C and the
>>> page would look like this:
>>> This is the last item in the list: false. Item A.
>>> This is the last item in the list: false. Item B.
>>> This is the last item in the list: true. Item C.
>>> Now, consider what the output would be if someone added an object D to
>>> the end of the list during invoke application:
>>> This is the last item in the list: false. Item A.
>>> This is the last item in the list: false. Item B.
>>> This is the last item in the list: true. Item C.
>>> This is the last item in the list: true. Item D.
>>> Notice that both C and D think they are the last. The reason is that the
>>> UIComponentClassicTagBase will find the components generated for A, B and C
>>> during the findComponent call. It will only create a new component for D.
>>> When D is created, it will pick up the new variable status map created by
>>> the for each tag in its value expressions. Because when three earlier
>>> components were build, C was the last item, and the variable status map in
>>> their value expressions did not reflect any changes. D gets the correct
>>> values since it was just created.
>>> -----------------
>>> I propose to reduce any work required by page developers to implement the
>>> for each loop with re-ordering support (avoid having to use immediate EL in
>>> the ID attribute) and fix the issues above.
>>> The proposal is that Trinidad Tag based components (those components
>>> created by UIXComponentELTag) will be able to have key-based IDs
>>> automatically generated as a result of being in a for each tag. So consider
>>> this example:
>>> <tr:forEach var="item" items="#{bean.items}" varStatus="vs">
>>>   <tr:inputText id="it1" value="#{item.value}" partialSubmit="true" />
>>>   <tr:outputText id="ot1" value="Value is: #{item.value}"
>>>     partialTriggers="it1_${vs.key}" />
>>> </tr:forEach>
>>> In this code, the IDs of the components would automatically pick up the
>>> item key. The item key would be stored on the var status. For List this key
>>> would simply be the index, for Map it would be the map key and
>>> CollectionModel would use the row key. UIXComponentELTag could check to see
>>> if a parent tag desires to alter the component IDs, which in this case, the
>>> for each would. With that set, the tags would alter the component IDs to
>>> append the key. For example, "_" + key would be appended to each component
>>> ID (it1 would become it1_A if the key were "A").
>>> The for each tag would set the key into the variable mapper so that,
>>> instead of indexes, the key would be used to evaluate the EL with the
>>> limitation that the key would be the index for List, in which the current
>>> behavior would be retained of the component state staying with the index
>>> rather than with the object.
>>> Due to the fact that the JSP does not perform any component reordering,
>>> the org.apache.myfaces.trinidad.change.ReorderChildrenComponentChange
>>> component change class can be use to alter the component order and also
>>> notify the component change manager of the reordering. This would require
>>> users that wish to reorder the items in the list to ensure to both re-order
>>> the list as well as reorder the components by applying a component change.
>>> Changes to UIXComponentELTag
>>> Due to the fact that UIComponentClassicTagBase is a JSF class that we
>>> cannot modify, in order to fix the tr:forEach bugs, we need to work with
>>> what we can change. We will want to follow this up with proposed changes to
>>> the JSF and potentially the JSTL specifications to be able to make this type
>>> of functionality standard.
>>> Since UIXComponentELTag extends UIComponentClassicTagBase, it can call
>>> protected methods to alter the ID of the tag. With the altering of the tag
>>> ID, the UIComponentClassicTagBase will produce different component IDs. In
>>> order to pull this off, there needs to be a defined contract between the for
>>> each tag and the Trinidad component tags. This contract could be done with
>>> static methods on UIXComponentELTag:
>>> Proposed methods to be added to UIXComponentELTag
>>> /**
>>>  * Push a component ID suffix onto the page context to append to
>>> component IDs generated by {...@link UIXComponentELTag}.
>>>  * This will append the suffix on all components up to a and including
>>> the text naming container.
>>>  * @param pageContext the JSP page context
>>>  * @param suffix the suffix to append to component IDs
>>>  */
>>> public static void pushComponentIdSuffix(PageContext pageContext, String
>>> suffix)
>>> {
>>>   ...
>>> }
>>> /**
>>>  * Pop the last component ID suffix added to the page context.
>>>  * @see #pushComponentIdSuffix(PageContext, String)
>>>  * @param pageContext the JSP page context
>>>  */
>>> public static void popComponentIdSuffix(PageContext pageContext)
>>> {
>>>   ...
>>> }
>>> The ForEachTag would then call these methods before and after the body
>>> processing respectively. The idea would be that if a UIXComponentELTag
>>> created a naming container, it would clear any suffixes for children of the
>>> naming container. This is because the IDs would already be unique in the
>>> naming container, and there would be no reason to modify them, and it would
>>> also stop these changes from affecting any IDs inside of included pages. The
>>> push/pop method would be used to support a stack usage. This way, if nested
>>> for each tags are present, multiple suffixes would be added to ensure that
>>> the IDs in one for each tag would conflict with another's.
>>> As this would be a documented behavior, users could leverage this API to
>>> ensure that their component references (like the partialTriggers attribute)
>>> point to the correct component.
>>> Changes to ForEachTag
>>> The for each tag, with this proposal, would need to be modified to call
>>> the new methods of UIXComponentELTag in doStartTag and doAfterBody
>>> functions.
>>> The tag will need to change to provide dynamic value expressions for the
>>> var status and the var so that changes to the items will not break EL. This
>>> would involve using the key as a reference instead of an index for non list
>>> based items. The var status would need point to a component tree based
>>> attribute that could be updated in each request. For example, this would
>>> allow new items to be added, and the last attribute to correctly reflect
>>> that new state.
>>> The for each tag would be change to support Map and CollectionModel as
>>> well, and adding the key as a valid attribute on the varStatus object.
>>> Optionally skip this for List and array
>>> If we did not implement the ID suffixing for List (and arrays), existing
>>> applications would not be affected. This is one consideration to have to
>>> ensure that backwards compatibility is maintained. Another alternative is to
>>> use a web.xml configuration parameter and only introduce the ID suffixing
>>> when the web XML parameter has enabled it for lists and arrays.
>
>

Reply via email to