Last modified on 14 July 2010, at 13:12

XForms/Incremental Model Loading

MotivationEdit

You have a large model and you want to incrementally load different portions of the model when they are needed. This is frequently done when you have a multi-part form and each tab needs additional data. Loading only the data for the initial tab keeps your form load times fast and avoids unnecessarily locking shared data resources.

MethodEdit

We will create a model with three separate instances, one for a list of people, one for a list of places and one for a list of things. The people will automatically be loaded into the form when the form loads. We will create triggers that will incrementally load the other portions of the model when they are needed. Each trigger will use a submission event that does a separate HTTP get to incrementally load data into a separate instance in the model.

Here is the empty place-holder instance in the model for the places and the submission to get the places data.

<xf:instance id="places">
    <null/>
</xf:instance>
<xf:submission id="get-places" method="get" action="places.xml"
    replace="instance" instance="places"/>

Here is the trigger (button) that gets the new model.

<xf:submit submission="get-places">
    <xf:label>Load Places</xf:label>
</xf:submit>

Screen ImageEdit

The following are the before and after screen images. The before screen image is when the form initially loads. The after image is after the user has pressed the two triggers for loading the places and things.

Before Model Fully Loaded
After Model Fully Loaded

The above example is designed to be very easy to see how data is loaded when an event is triggered. In practice each tab in a multi-tab form may have some data that is only needed if the users click on that tab. This is a perfect use of dynamic model loading. The example below illustrates this best-practice.

Note event log does not reload model data

Load XForms ApplicationEdit

Example with triggers that manually load incremental data: Load XForms Application

Example with tab-selection events that incrementally load data Load XForms Application

Note that in this example the event log shows that the data is only loaded once regardless of how many times the tab is selected.

Avoiding ReloadsEdit

The following is an example of how to use conditional actions to check if a instance in the model already has its data loaded into the form:

<xf:case id="places-case">
     <xf:action ev:event="xforms-select" if="not(instance('places')/place)">
         <xf:send submission="get-places"/>
     </xf:action>
     <h2>Places</h2>
</xf:case>

The if attribute of the xf:action checks to see if there is at least one place in the places instance. If there is not at least one "place" the submission event is fired.

Sample CodeEdit

<html
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xf="http://www.w3.org/2002/xforms"
    xmlns:ev="http://www.w3.org/2001/xml-events">
  <head>
    <title>Incremental Model Loading</title>
    <style type="text/css">body {font-family: Helvetica, Arial, sans-serif;</style>
    <xf:model>
      <!-- unconditionally loaded when the form loads -->
      <xf:instance id="people" src="people.xml">
          <null/>
      </xf:instance>
 
       <xf:instance id="places">
        <null/>
      </xf:instance>
      <xf:submission id="get-places" method="get" action="places.xml"
        replace="instance" instance="places"/>
 
       <xf:instance id="things">
        <null/>
      </xf:instance>
      <xf:submission id="get-things" method="get" action="things.xml"
        instance="things" replace="instance"/>
 
    </xf:model>
  </head>
 
  <body>        
    <h1>Incremental Model Loading</h1>
    <p>Not all parts of the model need to be loaded into a form when it is first loaded.  For
    large models, different sections can be loaded as they are needed.</p>
 
    <h2>People</h2>
      <xf:group ref="instance('people')">
         <xf:repeat nodeset="person">
           <xf:output ref="name"/><br/>
        </xf:repeat>
      </xf:group>
 
      <h2>Places</h2>
      <xf:group ref="instance('places')">
         <xf:repeat nodeset="place">
            <xf:output ref="name"/><br/>
        </xf:repeat>
        <xf:submit submission="get-places">
            <xf:label>Load Places</xf:label>
          </xf:submit>
      </xf:group>
 
      <h2>Things</h2>
      <xf:group ref="instance('things')">
         <xf:repeat nodeset="item">
            <xf:output ref="name"/><br/>
         </xf:repeat>
         <xf:submit submission="get-things">
            <xf:label>Load Things</xf:label>
          </xf:submit>
     </xf:group>
 
  </body>
</html>

XML Instance SamplesEdit

[people.xml] [places.xml] [things.xml]