An interested reader asked "How do you scroll a repeat?" so that it's content doesn't visually spill onto other controls. The question was specific to the Workplace Forms product, but the answer is reasonably generic.
One answer is that when you put things below a table (the XFDL element that contains and presents an XForms repeat), don't use absolute positioning. Use relative positioning. Use an itemlocation that puts the content "below" the table so that as the table grows, the content below it automatically shifts down.
The above suggestion is useful if you are allowed to the let the content grow arbitrarily. However, if you are trying to match the appearance of a paper form, then the table/repeat must fit into a prescribed space and location. So, you ask, how do I limit the size of the table and allow movement to the extra data?
Well, the first response is to ask if you are sure that's what you want. There are no scrollbars on paper, so if you try to print your form, you will not be able to see all of the table content. You may actually want to limit the table size to some maximum number of rows. It is very easy to make the insert trigger (button) become non-relevant when a maximum number of rows is reached. The easiest way is to add a
ref attribute to the insert trigger and use an XPath predicate to make the
ref evaluate to empty nodeset when a maximum number of rows is reached. This will cause the insert trigger button to become invisible or inactive (depending on how you style non-relevance) when the maximum is reached. Here is an example:
<xf:trigger ref="item[3 >= last()]"> <xf:label>Insert <xf:insert ev:event="DOMActivate" nodeset="../item" at="index('repeat-cart')+1" position="before"/></xf:trigger>
Relative to the post on Nov. 3, two things happened. The
ref was added to the trigger, and the
nodeset of the insert was tweaked. The XPath predicate in the
ref is evaluated for each 'item' element, and if the item elements belong to a collection of more than 3 items, then the 'last' item in the collection will have a position greater than three, so the XPath predicate returns false-- for each item. This is a handy trick because the ref then doesn't select any item element and the trigger behaves as if it is not relevant.
However, when the total number of item elements is three or lower, then the trigger
ref does bind to the first item and therefore behaves as if it is a relevant control. However, that first item now because the default context node for evaluating XPath expressions within the trigger. Since the insert is within the trigger, we have to adjust its nodeset with a leading
../ so that we get to the parent of the item elements. Then, the full expression
../item can select all item elements as was originally intended.
Finally, let's assume you don't care about the printing problem and so you really do want to have a 10 row table fit into the space of three rows with scrolling. Well, an XForms repeat just repeats things, it doesn't decide whether or not to grow a scrollbar. But, you can use an XPath predicate on your XForms repeat to control how many nodes it is showing. In fact, we highly recommend that you do use such predicates to keep repeat tables down to a reasonable size for efficiency. There's no point in creating 200 rows when the user can only really see 10 or 20 at a time!
To do repeat scrolling, you should create an instance data variable that can hold an index of your current location within a larger dataset. You could have a second variable to control the size of the table, or you could just pick a constant. I will pick 10 here. You then adjust your repeat nodeset as follows:
<xf:repeat nodeset="item[position() >= instance('temps')/curpos and position() < instance('temps')/curpos + 10]"> ...</xf:repeat>
Now, you just need scroll up and scroll down triggers (buttons) that add or subtract 10 from the curpos variable using a setvalue action. Of course, you should also use the above trick to make those triggers become non-relevant when doing so would cause the curpos variable to go out of bounds (less than 1 for the scroll up trigger, and greater than count(item) for the scroll down trigger).[Read More]