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><div template:element="item"><br /> <p><br /> Some item: <input template:attribute="value" name="{template:this-attribute()}" type="text" value="{$this-value}" /><br /> <input name="remove={template:this-element()}" type="submit" value="Remove" /><br /> </p><br /> <p><br /> Item type:<br /> <select template:element="type" name="{template:list-attribute('type-enum', 'value')}" multiple="multiple"><br /> <option template:element="type-enum" template:expr="@value-is-set" template:expr-attr="selected"<br /> template:value="@value" value="{@value}" /><br /> </select><br /> </p><br /> <span |
paulb@176 | 20 | style="font-weight: bold;"><p template:element="options"></span><br |
paulb@176 | 21 | style="font-weight: bold;" /><span style="font-weight: bold;"> <span </span><span |
paulb@176 | 22 | style="font-weight: bold;">template:element="comment"></span><span |
paulb@176 | 23 | style="font-weight: bold;">Comment:</span><br |
paulb@176 | 24 | style="font-weight: bold;" /><span style="font-weight: bold;"> <textarea template:attribute="value" name="{template:this-attribute()}" cols="40" rows="3"></span><br |
paulb@176 | 25 | style="font-weight: bold;" /><span style="font-weight: bold;"> <span template:value="$this-value" template:effect="replace">Some comment</span></span><br |
paulb@176 | 26 | style="font-weight: bold;" /><span style="font-weight: bold;"> </textarea><br /> </span><br |
paulb@176 | 27 | style="font-weight: bold;" /></span><span style="font-weight: bold;"> </p></span><br /> <p><br /> Itself containing more items:<br /> </p><br /> <p template:element="subitem"><br /> Sub-item: <input template:attribute="subvalue" name="{template:this-attribute()}" type="text" value="{$this-value}" /><br /> <input name="remove2={template:this-element()}" type="submit" value="Remove" /><br /> </p><br /> <p><br /> <input name="add2={template:this-element()}" type="submit" value="Add subitem" /><br /> </p><br /></div></pre> |
paulb@176 | 28 | <p>The newly-added <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 additional work to add such <code>options</code> |
paulb@176 | 34 | and <code>comment</code> |
paulb@176 | 35 | elements 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 <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 <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 element "skeleton" and its attributes so that |
paulb@176 | 54 | the <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 <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 add 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 <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 <code>Add item</code> |
paulb@176 | 83 | button):</p> |
paulb@176 | 84 | <pre><p><br /> <input name="update" type="submit" value="Update" /><br /></p></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;"><p template:element="options" template:id="comment-node" id="{template:this-element()}"></span><br |
paulb@176 | 94 | style="font-weight: bold;" /><span style="font-weight: bold;"> <span template:element="comment"></span>Comment:<br /> <textarea template:attribute="value" name="{template:this-attribute()}" cols="40" rows="3"><br /> <span template:value="$this-value" template:effect="replace">Some comment</span><br /> </textarea><br /> <span |
paulb@176 | 95 | style="font-weight: bold;"></span></span><br /> </p></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 <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 <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 <code>comment</code> |
paulb@176 | 109 | element resides.</li> |
paulb@176 | 110 | </ul> |
paulb@176 | 111 | <p>Another change has been to put the <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 <code>comment</code> element in the form |
paulb@176 | 114 | data could have prevented the <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><head><br /> <title>Example</title><br /> <span |
paulb@176 | 123 | style="font-weight: bold;"><script type="text/javascript" src="scripts/sarissa.js"> </script></span><br |
paulb@176 | 124 | style="font-weight: bold;" /><span style="font-weight: bold;"> <script type="text/javascript" src="scripts/XSLForms.js"> </script></span><br /></head></pre> |
paulb@176 | 125 | <p>These special script files can be found in <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> <p><br /> Item type:<br /> <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 /> '{template:other-elements(../options)}', '{template:other-attributes('value', ../options/comment)}',<br /> '/structure/item/options')"</span>><br /> <option template:element="type-enum" template:expr="@value-is-set" template:expr-attr="selected"<br /> template:value="@value" value="{@value}" /><br /> </select><br /> </p></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 <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 <code>type</code> element and its <code>type-enum</code> |
paulb@176 | 143 | elements' <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 <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 <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 <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 <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. </li> |
paulb@176 | 161 | </ol> |
paulb@176 | 162 | </body> |
paulb@176 | 163 | </html> |