XForms spec proposal: add event fired when new repeat instance is created


So @ln, @martijnr, what more do we need to do here to push a spec out for add/remove repeat instance event? [other than me keeping my mouth shut. :slight_smile: ] Not sure we necessarily need a call, but I'm certainly available if y'all think it'd help.

I believe the example in the XForms 1.1 spec is entirely unhelpful and the cause of the confusion.

IBM has a clear example, simplified (by me) as this:

<repeat nodeset="expenses/row">
    <setvalue event="odk-new-repeat" ref="/data/other/location" value="context()/detail" /> 

So this use case for context() is exactly as:

Now suddenly, the description of context() in the W3C spec makes sense to me:

In the example above the Single Node Binding (= ref) is outside the repeat and therefore not relative to the repeat context node.

So, I think we can continue to choose to not cater to this use case for now, and proceed with our plan. And we can add context() when we feel it is necessary.

A less happy realization after understanding ref vs. nodeset better is that I think we're doing ref values for elements inside a repeat (in the body) incorrectly. I think these should always have a relative path instead of an absolute path (as in XForms spec). Maybe not worth correcting as this point (and a much less serious deviation than the one that was recently corrected in pyxform).

Only <setlocation> is asynchronous, right, or am I misunderstanding? The other events+actions seem synchronous (and predictable). I think it will be quite intuitive for form designers to avoid issues with <setlocation>.

1 Like

I'm on board. I still think this event should have a custom name because it won't be as broad as the W3C XForms one, agreed? I'll give a bit for others (@Xiphware) to chime in but if all that is sounding reasonable, I will write this up in as much detail as I can including when the event is dispatched relative to calculate evaluation, context rules, etc.

Yes, that's sounding right. I think that was in fact the case that was tripping me up and that led me to cross out all that stuff in red above. It all adds up now, thanks. I agree that this is a wrong we can live with.

Yes agreed. I actually cannot figure out if a repeat is supposed to trigger the W3C xforms-insert event.

In W3C XForms, repeat instances can only be added by triggering the insert action. That could be by using a trigger control, responding to some event, whatever. On the other hand, in ODK XForms, repeats are added by client pixie dust. I suppose one could say that the insert action is implicit and that there is no explicit definition of what should trigger it (preferably a confusing dialog).

Oh, and in ODK XForms, trigger is ?!?!?!:exploding_head:(or more generously, a specialized case of the W3C XForms one).

1 Like

Ah right, that makes sense. Thanks! So I am still in favor of odk-new-repeat then.

Yes, we don't talk about that ;).

1 Like

As promised, here is a more formal spec proposal to summarize our discussion:

The odk-new-repeat event is dispatched when a new instance of a repeat is added to the primary instance and before recomputation of calculates, constraints, etc. Actions triggered by odk-new-repeat must be nested in the repeat form control.

Unlike W3C XForms' xforms-insert:

  • it is narrowly for repeats (ODK XForms currently has no notion of inserting arbitrary nodes)
  • its handlers must be nested in the corresponding repeat control (W3C XForms identifies the added nodes and the insert position in event context information so handlers can go anywhere)
  • it is dispatched separately for each repeat instance (in W3C XForms, a single insert action may insert multiple nodes)

I was going to also write up some text to describe that the event attribute on actions can specify multiple events but now I'm not so sure about it. Does the following which I showed here make sense?

   <repeat nodeset="/data/friends">
      <setvalue event="odk-new-repeat odk-instance-first-load" ref="age" value="../../my_age + 2" />
      <input ref="/data/friends/age">
           <label>Update age</label>

That is, should a handler for odk-instance-first-load be allowed to be nested in a repeat control? The ODK XForms spec currently says no: "Action elements triggered by initialization events go in the model as siblings of bind nodes. Action elements triggered by control-specific events are nested in that control block."

It's not a problem for pyxform or other form builders to generate two separate setvalue events, certainly. But it does feel unfortunate.

Am I understanding correctly that it's by requiring that the action be nested in the control that the evaluation context is the new repeat instance? If we did allow top-level handlers, we'd have to say that the evaluation context for the ref is the new repeat and we'd have to add something like "relative expressions for ref are only allowed in nested handlers." That does not seem very elegant. I believe that's what Dimagi did with the jr-insert event.

In W3C XForms, my understanding is that handlers of xforms-insert can be siblings of binds. In that case, the evaluation context would be the primary instanceโ€™s single child. However, one could use the index() function or the event properties that the context is augmented with in the single node binding expression (the ref).

1 Like

Thanks for the great writeup! :star_struck:

All seems workable to me, but I'd probably want to re-read it all again in the light of the day (1am presently) to make sure there arent any potential gotchas we've missed...

1 Like

Thanks a lot @LN!

Yes, I think that's okay.

Yes, indeed. Good idea to use the index() function to circumvent the Single Node Binding limitation of <setvalue>. So we'd have to add one of these <setvalue> elements for all default (defined in XForm) repeat instances (and add id attributes in the model?). I don't think it's worth it. The rationale is to avoid the deviation of our own ODK XForms spec only, right?

In your XForm snippet we have ref="age" and ref="/data/friends/age". As discussed, the first is likely the only correct ref, but so far we're only using the second (due to pyxform). So in this case, let's use the consistently incorrect /data/friends/age. (Tbh, it also avoids having to bring back relative ref support in Enketo, though would be open to that if it deemed worthwhile ;)).

(PS. am away for next 10 days so apologies in advance for late responses)

1 Like

All looks good to me. Just want to double-check that all this will properly fire (potentially multiple times) when you first open a form and the repeat_count expression is evaluated for the very first time, eg

    <bind calculate="count( /indefinite-repeat/person )" nodeset="/indefinite-repeat/count" type="string"/>
    <bind calculate="if ( /indefinite-repeat/count  = 0 or /indefinite-repeat/person[position()= /indefinite-repeat/count ]/choice != 'a',  /indefinite-repeat/count  + 1,  /indefinite-repeat/count )" nodeset="/indefinite-repeat/person_count" readonly="true()" type="string"/>
    <repeat jr:count=" /indefinite-repeat/person_count " nodeset="/indefinite-repeat/person">

ie it requires multiple passes thru binding calculations to get the final repeat count. I assume the existing mechanism for populating the additional repeat nodesets already handles this, so it's a given, but that's the best conceivable gothca I could come up with... :grin:


You could have populated //person/choice with value 'a' via setvalue triggered by odk-new-repeat to really mess with our heads. :crazy_face:

I think your example should be fine as far as I can see (as long as setvalue doesn't create an infinite repeat-count-update loop, which would be a form design issue).

1 Like

Actually the example was courtesy @ln, not one of my devious machinations ... :slightly_smiling_face:

indefinite-repeat.xlsx (6.5 KB)


Thanks so much, all. I will attempt to have a spec PR soon.

That's a great thing to call out, thank you.

:scream: :scream: :scream:

Let us all deviously machinate together.