Actions

Actions often cause a change to the data. A good example of such an action is insert, that inserts new elements or attributes into a data structure.

After an insert, the system has to restore stasis, and goes through a number of steps to do that: rebuild: possibly updating internal data structures, recalculate: recalculating dependent values, revalidate: checking changed values for validity, refresh: updating the user interface.

At each step of restoring stasis an event is dispatched. Although seldom needed, these events allow applications to do extra steps if necessary.

Doing extra processing during these stages requires care, because, by definition, the system is not yet up to date. In particular, changing values during these stages necessitates you manually doing an extra recalculate afterwards, since the system may not be aware of the changes you have made. It also means for instance that we can't keep an index of how many events received, and use that to index into a list of events received.

So what we do, is start off with the test instance containing elements for the expected events, except the very last (refresh):

<test pass="" res="" req="insert"/>
<test pass="" res="" req="rebuild"/>
<test pass="" res="" req="recalculate"/>
<test pass="" res="" req="revalidate"/>

then on xforms-ready, we use insert to add the missing element. With no further parameters, an insert on a list just duplicates the last element, so we need to update the req attribute:

<action ev:event="xforms-ready">
   <insert ref="test"/>
   <setvalue ref="test[last()]/@req">refresh</setvalue>
</action>

Then we catch all the events we are expecting, and store them at the locations they should be in if the events come in in the right order:

<action ev:event="xforms-insert">
   <setvalue ref="test[1]/@res">insert</setvalue>
</action>
<action ev:event="xforms-rebuild">
   <setvalue
   ref="test[@res='insert']/following-sibling::test[1]/@res[.='']">rebuild</setvalue>
</action>
<action ev:event="xforms-recalculate">
   <setvalue 
   ref="test[@res='rebuild']/following-sibling::test[1]/@res[.='']">recalculate</setvalue>
</action>
<action ev:event="xforms-revalidate">
   <setvalue
   ref="test[@res='recalculate']/following-sibling::test[1]/@res[.='']">revalidate</setvalue>
</action>
<action ev:event="xforms-refresh">
   <setvalue
   ref="test[@res='revalidate']/following-sibling::test[1]/@res[.='']">refresh</setvalue>
   <recalculate/>
</action>

A setvalue such as

<setvalue
  ref="test[@res='rebuild']/following-sibling::test[1]/@res[.='']">recalculate</setvalue>

selects the test element after the one whose res attribute is rebuild, and sets the value of its res attribute only if it has not already been set. Therefore, if the rebuild event has not yet been received, we won't record the recalculate.