XSLTools

Annotated docs/in-page-updates.html

178:7e7d9dbcec62
2005-07-22 paulb [project @ 2005-07-22 18:26:38 by paulb] Tidied up the function names and added some API documentation. Added child-element and child-attribute functions for coherent references to potentially non-existent nodes in the form data.
paulb@176 1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
paulb@176 2
<html xmlns="http://www.w3.org/1999/xhtml">
paulb@176 3
<head>
paulb@176 4
  <meta content="text/html;charset=ISO-8859-1" http-equiv="Content-Type" />
paulb@176 5
  <title>Creating Applications: In-Page Updates</title>
paulb@176 6
  <meta name="generator"
paulb@176 7
 content="amaya 8.1a, see http://www.w3.org/Amaya/" />
paulb@176 8
  <link href="styles.css" rel="stylesheet" type="text/css" />
paulb@176 9
</head>
paulb@176 10
<body>
paulb@176 11
<h1>Creating Applications: In-Page Updates</h1>
paulb@176 12
<p>One fashionable avenue in Web application design has been that of
paulb@176 13
updating Web pages in applications without having to refresh the entire
paulb@176 14
page every time an action is performed. Together with some JavaScript
paulb@176 15
support in the browser, XSLForms also provides some functionality for
paulb@176 16
such "in-page" or "live" updates.</p>
paulb@176 17
<p>Consider the addition of a comment field to our application. Here is
paulb@176 18
how the HTML code might look:</p>
paulb@176 19
<pre>&lt;div template:element="item"&gt;<br />  &lt;p&gt;<br />    Some item: &lt;input template:attribute="value" name="{template:this-attribute()}" type="text" value="{$this-value}" /&gt;<br />    &lt;input name="remove={template:this-element()}" type="submit" value="Remove" /&gt;<br />  &lt;/p&gt;<br />  &lt;p&gt;<br />    Item type:<br />    &lt;select template:element="type" name="{template:list-attribute('type-enum', 'value')}" multiple="multiple"&gt;<br />      &lt;option template:element="type-enum" template:expr="@value-is-set" template:expr-attr="selected"<br />        template:value="@value" value="{@value}" /&gt;<br />    &lt;/select&gt;<br />  &lt;/p&gt;<br />  <span
paulb@176 20
 style="font-weight: bold;">&lt;p template:element="options"&gt;</span><br
paulb@176 21
 style="font-weight: bold;" /><span style="font-weight: bold;">    &lt;span </span><span
paulb@176 22
 style="font-weight: bold;">template:element="comment"&gt;</span><span
paulb@176 23
 style="font-weight: bold;">Comment:</span><br
paulb@176 24
 style="font-weight: bold;" /><span style="font-weight: bold;">      &lt;textarea template:attribute="value" name="{template:this-attribute()}" cols="40" rows="3"&gt;</span><br
paulb@176 25
 style="font-weight: bold;" /><span style="font-weight: bold;">        &lt;span template:value="$this-value" template:effect="replace"&gt;Some comment&lt;/span&gt;</span><br
paulb@176 26
 style="font-weight: bold;" /><span style="font-weight: bold;">      &lt;/textarea&gt;<br />    &lt;/span&gt;<br
paulb@176 27
 style="font-weight: bold;" /></span><span style="font-weight: bold;">  &lt;/p&gt;</span><br />  &lt;p&gt;<br />    Itself containing more items:<br />  &lt;/p&gt;<br />  &lt;p template:element="subitem"&gt;<br />    Sub-item: &lt;input template:attribute="subvalue" name="{template:this-attribute()}" type="text" value="{$this-value}" /&gt;<br />    &lt;input name="remove2={template:this-element()}" type="submit" value="Remove" /&gt;<br />  &lt;/p&gt;<br />  &lt;p&gt;<br />    &lt;input name="add2={template:this-element()}" type="submit" value="Add subitem" /&gt;<br />  &lt;/p&gt;<br />&lt;/div&gt;</pre>
paulb@176 28
<p>The newly-added&nbsp;<code>textarea</code> field will not be
paulb@176 29
presented in the application in its current state; this is due to the
paulb@176 30
lack of any <code>options</code> or <code>comment</code> elements
paulb@176 31
manipulated by the
paulb@176 32
application, and such template changes are actually quite safe to make.
paulb@176 33
So, we must now do some&nbsp;additional work to add such <code>options</code>
paulb@176 34
and <code>comment</code>
paulb@176 35
elements&nbsp;in our application.</p>
paulb@176 36
<p>One approach is to extend our transformation which adds the
paulb@176 37
different type values so that these new elements are
paulb@176 38
introduced as well. In the Web resource, we can make the following
paulb@176 39
change:</p>
paulb@176 40
<pre>    transform_resources = {<br />        "types" : ["structure_multivalue_types.xsl", "structure_comments.xsl"]<br />        }</pre>
paulb@176 41
<p>What this does is to state that when we carry out the&nbsp;<code>types</code>
paulb@176 42
transformation, two stylesheets are employed, one before the other,
paulb@176 43
such that the type values are first added using the first stylesheet
paulb@176 44
(and the additional reference document containing the type values) and
paulb@176 45
that the comments are then added using the second stylesheet.</p>
paulb@176 46
<p>This new stylesheet works according to the following principles:</p>
paulb@176 47
<ol>
paulb@176 48
  <li>Descend into the form data structure, copying all elements,
paulb@176 49
attributes and text that the stylesheet is not programmed to recognise.</li>
paulb@176 50
  <li>When encountering an&nbsp;<code>item</code> element (which the
paulb@176 51
stylesheet is programmed to recognise), do the following:<br />
paulb@176 52
    <ol>
paulb@176 53
      <li>Copy the&nbsp;element "skeleton" and its attributes so that
paulb@176 54
the&nbsp;<code>value</code> attribute is retained.</li>
paulb@176 55
      <li>Produce a new <code>options</code> element and process it.</li>
paulb@176 56
    </ol>
paulb@176 57
  </li>
paulb@176 58
  <li>When processing a new <code>options</code> element, do the
paulb@176 59
following:<br />
paulb@176 60
    <ol>
paulb@176 61
      <li>Inside this new <code>options</code> element, investigate
paulb@176 62
the values associated with the&nbsp;<code>type</code> element.</li>
paulb@176 63
      <li>If any of the selected type values is "Personal", make a new <code>comment</code>
paulb@176 64
element, then&nbsp;add&nbsp;any attributes that may be found on existing
paulb@176 65
        <code>comment</code> elements within the current <code>type</code>
paulb@176 66
element.</li>
paulb@176 67
    </ol>
paulb@176 68
  </li>
paulb@176 69
</ol>
paulb@176 70
<p>Since this stylesheet is used after the type value transformation,
paulb@176 71
we may (and even must) take advantage of the results of that
paulb@176 72
transformation, including noting that selected values on <code>type-enum</code>
paulb@176 73
elements are marked with the <code>value-is-set</code> attribute.</p>
paulb@176 74
<p>The stylesheet source code can be found in&nbsp;<code>examples/Common/VerySimple/Resources/structure_comments.xsl</code>.</p>
paulb@176 75
<h2>Limitations and Enhancements</h2>
paulb@176 76
<p>Whilst the above modifications adds a comment field for each item
paulb@176 77
with a type of "Personal", and whilst the comment field will appear and
paulb@176 78
disappear for items as their type changes, such updates only take place
paulb@176 79
when items and subitems are added and removed. We could add an update
paulb@176 80
button to the page which performs an explicit refresh of the page
paulb@176 81
without adding or removing anything, and for the sake of usability, we
paulb@176 82
probably should add such a button (just below the&nbsp;<code>Add item</code>
paulb@176 83
button):</p>
paulb@176 84
<pre>&lt;p&gt;<br />  &lt;input name="update" type="submit" value="Update" /&gt;<br />&lt;/p&gt;</pre>
paulb@176 85
<p>However, we could also add an in-page update to make each comments
paulb@176 86
field appear and disappear as soon as we have changed the type of an
paulb@176 87
item.</p>
paulb@176 88
<h3>Template Changes</h3>
paulb@176 89
<p>We must first define a region of the template where a comment fields
paulb@176 90
can be added and removed, regardless of whether such a field existed
paulb@176 91
there before. The above template code needs modifying slightly to
paulb@176 92
permit this:</p>
paulb@176 93
<pre>  <span style="font-weight: bold;">&lt;p template:element="options" template:id="comment-node" id="{template:this-element()}"&gt;</span><br
paulb@176 94
 style="font-weight: bold;" /><span style="font-weight: bold;">    &lt;span template:element="comment"&gt;</span>Comment:<br />      &lt;textarea template:attribute="value" name="{template:this-attribute()}" cols="40" rows="3"&gt;<br />        &lt;span template:value="$this-value" template:effect="replace"&gt;Some comment&lt;/span&gt;<br />      &lt;/textarea&gt;<br />    <span
paulb@176 95
 style="font-weight: bold;">&lt;/span&gt;</span><br />  &lt;/p&gt;</pre>
paulb@176 96
<p>Here, we have added this region definition to the paragraph
paulb@176 97
surrounding the comment field, annotating the paragraph with the
paulb@176 98
following attributes:</p>
paulb@176 99
<ul>
paulb@176 100
  <li>The&nbsp;<code>template:id</code> attribute is used to define a
paulb@176 101
template fragment used only to prepare the updated part of the Web
paulb@176 102
page. Here we define the fragment or region as being just this
paulb@176 103
paragraph.</li>
paulb@176 104
  <li>The standard HTML&nbsp;<code>id</code> attribute is used to
paulb@176 105
define which part of the active Web page will be replaced when
paulb@176 106
performing an in-page update. This attribute needs to have a unique
paulb@176 107
value, but the easiest basis for such a value is a selector-style
paulb@176 108
reference to the <code>options</code> element within which the&nbsp;<code>comment</code>
paulb@176 109
element resides.</li>
paulb@176 110
</ul>
paulb@176 111
<p>Another change has been to put the&nbsp;<code>template:element</code>
paulb@176 112
annotation inside the above fragment or region annotations. Had we not
paulb@176 113
done this, the lack of a&nbsp;<code>comment</code> element in the form
paulb@176 114
data could have prevented the&nbsp;<code>id</code> attribute from
paulb@176 115
appearing in the Web page, this preventing any hope of an in-page
paulb@176 116
update since there would be no way of knowing where such an update
paulb@176 117
should be applied.</p>
paulb@176 118
<h3>Adding JavaScript</h3>
paulb@176 119
<p>Since we rely on JavaScript support in the browser, the following
paulb@176 120
references to scripts must also be added to the template, as shown in
paulb@176 121
the following excerpt:</p>
paulb@176 122
<pre>&lt;head&gt;<br />  &lt;title&gt;Example&lt;/title&gt;<br />  <span
paulb@176 123
 style="font-weight: bold;">&lt;script type="text/javascript" src="scripts/sarissa.js"&gt; &lt;/script&gt;</span><br
paulb@176 124
 style="font-weight: bold;" /><span style="font-weight: bold;">  &lt;script type="text/javascript" src="scripts/XSLForms.js"&gt; &lt;/script&gt;</span><br />&lt;/head&gt;</pre>
paulb@176 125
<p>These special script files can be found in&nbsp;<code>examples/Common/VerySimple/Resources/scripts</code>.</p>
paulb@176 126
<p>Now we can concentrate on adding the event which triggers an in-page
paulb@176 127
update. Since it is the type values that cause each comment field to be
paulb@176 128
added or removed, we add an event attribute on the form field
paulb@176 129
responsible for displaying the type values:</p>
paulb@176 130
<pre>  &lt;p&gt;<br />    Item type:<br />    &lt;select template:element="type" name="{template:list-attribute('type-enum', 'value')}" multiple="multiple"<br />      <span
paulb@176 131
 style="font-weight: bold;">onchange="requestUpdate('{$application-url}comments', '{template:list-attribute('type-enum', 'value')}',<br />     &nbsp;'{template:other-elements(../options)}', '{template:other-attributes('value', ../options/comment)}',<br />      '/structure/item/options')"</span>&gt;<br />      &lt;option template:element="type-enum" template:expr="@value-is-set" template:expr-attr="selected"<br />        template:value="@value" value="{@value}" /&gt;<br />    &lt;/select&gt;<br />  &lt;/p&gt;</pre>
paulb@176 132
<p>This complicated string calls a special update request JavaScript
paulb@176 133
function which triggers the in-page update, and it specifies the
paulb@176 134
following things:</p>
paulb@176 135
<ol>
paulb@176 136
  <li>The URL which will serve the in-page update requested by this
paulb@176 137
field. We use a special variable called&nbsp;<code>application-url</code>
paulb@176 138
which will need to be provided to the template when generating the Web
paulb@176 139
page.</li>
paulb@176 140
  <li>The fields which are going to be used in the processing of the
paulb@176 141
update. Since the presence of the comment field depends on a
paulb@176 142
specific&nbsp;<code>type</code> element and its&nbsp;<code>type-enum</code>
paulb@176 143
elements'&nbsp;<code>value</code> attributes, we specify the names of
paulb@176 144
the fields which yield these values.</li>
paulb@176 145
  <li>The region which is to be updated. Here, we recall that we
paulb@176 146
defined the region using a special reference to the <code>options</code>
paulb@176 147
element holding&nbsp;<code>comment</code> element. Thus, we use a
paulb@176 148
special value which also refers to that element from the context of
paulb@176 149
the&nbsp;<code>type</code> element.</li>
paulb@176 150
  <li>Even when the types are changed, it may be the case that an
paulb@176 151
exposed comment field does not disappear (for example, if we already
paulb@176 152
have "Personal" selected but select "Important" in addition), and so we
paulb@176 153
need to provide the details of the field which holds the value of the
paulb@176 154
comment text. We find such details by referencing the&nbsp;<code>comment</code>
paulb@176 155
element from the <code>type</code> element and stating that we want the
paulb@176 156
    <code>value</code> attribute on that&nbsp;<code>comment</code>
paulb@176 157
element.</li>
paulb@176 158
  <li>Finally, we need to provide some context to the application to
paulb@176 159
tell it something about where in the complete form data structure the
paulb@176 160
updated information resides.&nbsp;</li>
paulb@176 161
</ol>
paulb@176 162
</body>
paulb@176 163
</html>