XForms/Incremental Model Loading

From Wikibooks, open books for an open world
Jump to navigation Jump to search

Motivation[edit | edit source]

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.

Method[edit | edit source]

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 Image[edit | edit source]

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 Application[edit | edit source]

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 Reloads[edit | edit source]

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 Code[edit | edit source]

<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 Samples[edit | edit source]

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