The Submission method

Mark Birbeck's picture

The submission 'method' indicates the operation to be performed. Although this will often be a simple mapping to an HTTP method, it needn't be. For example, the following code sets up a submission declaration that when called will push data up to a server, using an HTTP PUT:

<xf:submission action="http://www.example.org/customer/3.xml" method="put" />

However, the following submission declaration differs only in that the file: protocol is used, yet it has a completely different effect--instead of sending data over the network using the HTTP protocol, the data is simply saved to a local file:

<xf:submission action="file:///my-files/customers/customer/3.xml" method="put" />

In other words the submission method is more than just an HTTP method.

(For more on the file: protocol, see Manipulating local files.)

Abstract methods

The best way to understand the submission method therefore is as a request to the XForms processor to do something, but without having to be protocol-specific about what you want doing. This ability to specify what you want to do in a high-level way is very powerful. For example, say we would like to create a form that uses both of the URLs we had above--the customer on the server, and one on our local drive. The easiest way to achieve this would be for our form to use relative paths, and then if we run the form from our disk it saves the information to the local file, and if we run the form from the server it sends the data to the server. In terms of specifying the location it's easy; we just use relative paths as we might do for an image or stylesheet in HTML. But the method would normally be more of a problem, since the action to 'save a file' is completely different to the action to 'send data to a server using HTTP'. However, since the submission method is merely a request to the XForms processor to do something in a protocol-independent way, then the following mark-up will work in both of our scenarios--server and local drive alike:

<xf:submission action="customers/customer/3.xml" method="put" />

In short, the exact meaning of 'put' will be determined by the context in which it is being used, and it might even mean 'send an email':

<xf:submission action="mailto:accounts@example.org" method="put" />

Setting the submission method

We saw above that the submission method is usually specified using the method attribute; this is true in both XForms 1.0 and XForms 1.1, However, in XForms 1.1 the submission method can also be set using the method child element, which will override the method attribute if both are specified.

(Note that there is no default value for the submission method so either an attribute or element will be needed.)

The element technique allows us to set the submission method at run-time which is a particularly useful way of reusing one submission declaration for a number of different purposes, as we often want to do when building RESTful applications.

For example, in our earlier examples we had some customer information stored at:

customers/customer/3.xml

In a RESTful application we might allow this data to be updated with a 'put' or removed completely with a 'delete'. With XForms 1.0 we'd have to have two separate submission declarations:

<xf:submission id="sub-put" action="customers/customer/3.xml" method="put" />

<xf:submission id="sub-delete" action="customers/customer/3.xml" method="delete" />

However, in XForms 1.1 we can reuse one submission declaration for both tasks, as follows:

<xf:submission id="sub-customer" action="customers/customer/3.xml">
  <xf:method value="method" />
</xf:submission>

Now that this submission declaration has been created, it can be used in any number of ways. For example, the submission method need not be set until the user chooses an action:

<xf:trigger>
  <xf:label>Save</xf:label>
  <xf:action ev:event="DOMActivate">
    <xf:setvalue ref="method">put</xf:setvalue>
    <xf:send submission="sub-customer" />
  </xf:action>
</xf:trigger>

<xf:trigger>
  <xf:label>Delete</xf:label>
  <xf:action ev:event="DOMActivate">
    <xf:setvalue ref="method">delete</xf:setvalue>
    <xf:send submission="sub-customer" />
  </xf:action>
</xf:trigger>

Alternatively, if we want to keep things more encapsulated, we might put this functionality into the submission declaration itself:

<xf:submission id="sub-customer" action="customers/customer/3.xml">
  <xf:method value="method" />
  <xf:action ev:event="my-save">
    <xf:setvalue ref="method">put</xf:setvalue>
    <xf:send submission="sub-customer" />
  </xf:action>
  <xf:action ev:event="my-delete">
    <xf:setvalue ref="method">delete</xf:setvalue>
    <xf:send submission="sub-customer" />
  </xf:action>
</xf:submission>

This provides us with a convenient way of centralising any interaction with the customer into one place, which is particularly useful for keeping code up-to-date, or for managing processes that need to run when another has completed (or failed). To use this submission declaration the triggers we saw earlier would need to change to:

<xf:trigger>
  <xf:label>Save</xf:label>
  <xf:action ev:event="DOMActivate">
    <xf:dispatch name="my-save" target="sub-customer" />
  </xf:action>
</xf:trigger>

<xf:trigger>
  <xf:label>Delete</xf:label>
  <xf:action ev:event="DOMActivate">
    <xf:dispatch name="my-delete" target="sub-customer" />
  </xf:action>
</xf:trigger>

This makes the purpose of the code easier to see and read, and consequently easier to maintain.