Hi Jason,
Thanks for starting the sample. You have two distinct data sets. Did you
mean that either could be used as the prototype for the *same* repeat or
two different repeats? If two different repeats, then I still don't see
how you're generating a problem. If the same repeat, then I still don't
see why it isn't the same and likely *worse* to take a snapshot of data on
startup to use for insertions.
Regarding the statement that 1.1 fixes repeats, but they're only toys in
1.0, I am responding that in *1.0* I can construct repeats to arbitrary
depth, they can become empty, and they can become non-empty again through
an insertion *even at arbitrary depth*. I can make the repeat enforce a
minimum of one row as a rule, so that if you delete the last row, it
simply empties itself, and I can do so with a single action (i.e. the
action sequence does not need to be tailored to the data schema).
Remember that link I sent in prior email? It contains a description of
the things you can do to achieve this. Here it is again:
http://www.idealliance.org/proceedings/xml05/ship/74/XFormsAndXFDL_Boyer.HTML#d0e1785
To follow my own request, here is an example. Suppose you want a repeat
that starts empty (like an empty shopping cart):
<!-- Initial instance data contains the prototypical node as the last
element -->
<xf:instance xmlns="">
<cart>
<item>
<name/>
...
<cart>
</xf:instance>
...
<!-- repeat omits the prototypical node -->
<xf:repeat nodeset="item[position()!=last()]" id="repeat-cart">
...
</xf:repeat>
<!-- Add new row after any current row, but do it in a way that can
also handle zero rows. -->
<xf:trigger>
<xf:label>Insert</xf:label>
<xf:insert ev:event="DOMActivate" nodeset="item"
at="index('repeat-cart')+1" position="before"/>
</xf:trigger>
<!-- Delete a row from the repeat. If only the prototypical data remains
then the nodeset becomes empty and the action has no effect. -->
<xf:trigger>
<xf:label>Delete</xf:label>
<xf:delete ev:event="DOMActivate" nodeset="item[position()!=last()]"
at="index('repeat-cart')"/>
</xf:trigger>
Finally, because it seems to be such a sticking point, let me show you
what can be done in XForms 1.0 if *insert* also has no effect on empty
nodeset. The prior argument that we don't know where to insert should be
good enough, and consistency with the no-effect behavior of delete (the
utility of which is shown above) should also be good enough, but it turns
out that we actually *need* this aspect of insert to drive another use
case for repeats. Suppose that instead of a zero row repeat, you want a
repeat that stays at one row. If the user hits delete for that row, then
the row stays, but the data is cleared from it. Further suppose that you
want a general method, and not something that requires you to write a
bunch of setvalue actions tailored to the data (which doesn't work in the
nested repeat case anyway). In other words, suppose you want to be able
to accomplish this feat with a *constant* number of actions regardless of
the shape of the data:
<xf:trigger>
<xf:label>Delete</xf:label>
<xf:action ev:event="DOMActivate">
<xf:delete nodeset="item[position()!=last()]"
at="index('repeat-cart')"/>
<xf:insert nodeset="item[last()=1]" at="1" position="before"/>
</xf:action>
</xf:trigger>
The delete action only deletes the last row of data that the repeat is
actually showing. The insert follows that up with a nodeset that resolves
to empty unless the only data left is the prototypical data. If there is
anything more, the insert has no effect. But when only the prototype is
left over, we make a new copy of it, which presents a single empty row of
data to the user.
The neat thing is that this method works even if the repeat contains
repeats. The last row we are deleting may contain repeats with multiple
rows. Those are deleted and then the insert puts in new prototypical data
in which the inner repeats only have one row. No 'if', no 'while', no
actions that have to know the structure of the data. Just two actions.
Just XForms 1.0.
John M. Boyer, Ph.D.
STSM: Workplace Forms Architect and Researcher
Co-Chair, W3C Forms Working Group
Workplace, Portal and Collaboration Software
IBM Victoria Software Lab
E-Mail: boyerj@ca.ibm.com http://www.ibm.com/software/
Blog: http://www.ibm.com/developerworks/blogs/page/JohnBoyer
Jason <jeacott@hardlight.com.au>
11/04/2006 02:03 AM
Please respond to
jeacott@hardlight.com.au
To
John Boyer/CanWest/IBM@IBMCA
cc
www-forms <www-forms@w3.org>
Subject
Re: repeats
John Boyer wrote:
>
> Hi Jason,
>
> Sorry, but the stuff you are writing is really hard to respond to. It's
> just a stream of thoughts that makes huge assumptions every few
> sentences that I understand certain things you haven't said.
sorry.
> For example, you say that great care would needed to be taken when
> dealing with newly loaded data sets that might be subtly different than
> prior ones in the form. It escapes me how this point manages to
> substantiate the complaint about the processor not taking a snapshot of
> instance data on initialization. In fact, you are exactly describing
> one of the things that was broken about the old method.
this is just because suddenly you need 2 matching instances. 1 acting as
prototype, and 1 containing working data. This was never a problem
previously because it wasn't possible. My issue here is that in many
cases the new regime is not required, so why not allow both options to
coexist. that way simple forms stay really simple.
if for example you had 2 distinct sets of data like this
set 1
-----------
<data>
<somenodeA/>
<somenodeB someatt="true"/>
</data>
-----------
set 2
-----------
<data>
<somenodeA/>
<somenodeB/>
</data>
-----------
these could both conceivably be managed by the same xform, including
repeats. but in the new 1.1 scenario I'll need 2 distinct prototype
instances.
this is a simple fictitious example but there could easily be real
reasons for doing this sort of thing. So when I load set1 I'd really
need to be loading its matching prototype too, and then saving them
together etc, and inventing ways to ensure they were matching pairs.
Thats why I suggested that it might be difficult to manage. And as I
said, I havent thought about it much, it was just something I thought
could cause problems.
> In XForms 1.0, the <instance> element contains or references the initial
> instance data, and the snapshot was taken during model-construct. If an
> instance replacement submission brought in new data over which a
> repeat/insert should operate, but there was no matching data in the
> initial instance data, then insert would just fail.
thats true.
> This conversation would therefore really benefit from some exact use
> cases with example markup because your claim that XForms repeats are now
> just for toy forms is not just hyperbole, it's just plain wrong.
I claimed this for 1.0 - I acknowledged that its fixed with 1.1
> The new design even of XForms 1.0 allows one to actually create
arbitrarily
> deeply nested repeats, not just one level, and it allows one to do so in
> a way that survives a save/reload (e.g. submit data to server and come
> back tomorrow to finish purchase order).
I'm not sure how this works - maybe I'm reading the wrong docs.
xforms 1.0?
http://www.w3.org/TR/2006/REC-xforms-20060314/slice9.html#action-insert
only has 'position' & 'at'
so if our user removes all her items from the shopping list - how do you
start over? This is where my issue lies, so now all the forms I have
that use this scenario (pretty much all of them) are broken and cannot
be repaired as far as I can tell with 1.0 alone. If you have a way I'd
dearly love to hear it.
I could always create nested repeats without problem. I think I tried to
indicate that I still dont think its possible to produce arbitrarily
deep on-the-fly child nodes and track them automagically with the view
to create dynamic trees. I also dont think its possible to create one
view that can display arbitrary data without that view requiring
modification each time.
> And I still don't understand why you believe that insert on empty
> nodeset should do something. Even if you did have a prototype available
> (i.e. pretend the above language faults did not exist), when the nodeset
> resolves to empty, where should the node be inserted?
The processor knows where to look to determine that the nodesetcount is
zero, so wouldn't it add the insert where it finds the zero count? or
where a bind states it should be? If that parent is also missing THEN
you could reasonably decide to do nothing. This seems like sensible and
predictable behaviour - you could even put a switch on the insert to
allow chasing back to the first recognisable ancestor, even if its the
root node and then rebuild the node to be inserted and all the
intervening ones. I dont know if that would be useful or not, but I dont
see that its not possible.
In the interests of keeping this short - I accept your points re switch
etc - I was just suggesting some things that I found awkward that seem
only to make creating forms more cumbersome I wasn't suggesting any
priorities at all.
I do truly appreciate your efforts, especially in responding to my
previous stream of consciousness response.
Cheers
Jason.