Search code examples
xpagesxpages-extlib

xp:repeat inside xe:dataView


I am currently having some trouble using a xp:repeat inside a xe:dataView.

Scenario: I'm using a xe:dataview which repeats some objects (same type) and shows them inside a form, but some of the objects contain more fields than others. So I have to create the fields and there valuebinding dynamic with an xp:repeat.

My Problem: I cant use the var="rowvar" of my dataView to calculate the value="" of my repeat control. But I need a reference on my obj inside the current row to calculate the fields.

Here a Simple Version of my Code(in my real scenario the obj is a Java Model Object):

<xe:dataView
    id="dataView1"
    var="rowvar"
    indexVar="objindex">
        <xe:this.value<![CDATA[#{javascript:[{fields:["field01","field02"]},{fields:["field01"]}]}]]></xe:this.value>
    <xp:this.facets>
        <xp:panel
            xp:key="summary">
            <xp:repeat
                value="#{javascript:do some stuff with rowvar}" or value="#{rowvar.fields}"
                var="field"
                indexVar="index"
                id="repeat1"
                repeatControls="true"
                rows="30">
                <xp:panel>
                    <xp:inputText
                        id="inputText1">
                        <xp:this.value><![CDATA[${javascript:
                                 var fieldName = "field0" + index;
                                 return '#{obj.' + fieldName + '}';}]]>
                        </xp:this.value>
                    </xp:inputText>
                </xp:panel>
            </xp:repeat>
        </xp:panel>
    </xp:this.facets>
</xe:dataView>

As soon as I try to use the rowvar inside the value="#{}" of my repeat control I get a [Reference] 'rowvar' not found error. If I remove the repeatControls="true" I can't Access the index var inside my computed value binding any more... anyone got a solution on that?


Solution

  • Not surprisingly, it's something Tim Tripcony has explained http://avatar.red-pill.mobi/tim/blog.nsf/d6plinks/TTRY-9CD3JN. The DataView, like a Panel, is "cleaning up" after itself. So when it restores the view after a partial refresh, it's removing all the requestScope pointers to the variable rowvar.

    Because it's the value property of an editable control, it will be needed in ApplyRequestValues phase at the very earliest.

    It may be possible to use Tony McGuckin's XSnippet http://openntf.org/XSnippets.nsf/snippet.xsp?id=xrpl-isphase-api. That will allow you to identify the phases and compute the code at a phase after the requestScope variable has been set (so is not null), but before your code needs it. (Caveat: I've not tested to see whether the requestScope variable is set before it's needed.)

    repeatControls="true" removes the repeat, so your code can no longer use rowvar.

    Update

    Now that I test the kind of thing you're trying, I realise it's failing on page load not in partial refresh. Again, it's a timing thing.

    With repeatControls="true", you are telling the XPage to load x rows in the "Page Load" event bound to the first x elements. So it will set index, the indexVar of the repeat, because it's iterating over the data to create x rows.

    But the Data Table has (and can only have) dynamic binding. So during the "Page Load" event all the component tree is creating is a template for what to load into a given row. It hasn't looked at the underlying data for the Data Table. It will only iterate over that during the Render Response phase. So rowvar, the indexVar of the Data Table has not been set. There is no concept of a "row", there is just an abstract template for what will need to be loaded into each row during Render Response.

    From a Java point of view, think of it like trying to get a value of a property from a Class (the template for each object created from that Class) rather than getting the value of the property from an instance of the Class.

    The only way round that will be to change the Data Table to a Repeat Control and set repeatControls="true" on both the outer and inner repeat. Then everything will get built at Page Load, rather than the repeat at Page Load and the Data Table during Render Response.