template.md 6.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
# $.template

`$.template()` renders HTML templates with JavaScript mixed inside them.

Example:

```html
<script type="text/html">Your platform is <%= navigator.userAgent %></script>
<script>
  $('body').template()
</script>
```

renders all `script[type="text/html"]` as [lodash templates](https://lodash.com/docs/#template).
This displays `Your platform is ...` and shows the userAgent just below the script tag.

- Anything inside `<% ... %>` is executed as Javascript.
- Anything inside `<%= ... %>` is evaluated and rendered in-place.

The template can use all global variables. You can pass additional variables
using as `.template({var1: value, var2: value, ...})`. For example:

23
<!-- render:html -->
24
```html
25
<script type="text/html" class="example">
26 27 28 29 30
  <% list.forEach(function(item) { %>
    <div><%= item %></div>
  <% }) %>
</script>
<script>
31
  $('script.example').template({list: ['a', 'b', 'c']})
32 33 34 35 36 37
</script>
```

To re-render the template, run `.template(data)` again with different data.


38
## $.template animation
39

40 41 42 43 44 45 46 47 48
When using `type="text/html"`, templates are re-rendered. To *update* existing
elements, use `data-engine="vdom"` instead. This only changes attributes or
elements that need change. This allows us to animate attributes via CSS.

You need to include [morphdom](https://github.com/patrick-steele-idem/morphdom)
for this to work.

For example, this shows a circle in SVG bouncing around smoothly.

49
<!-- render:html -->
50 51 52 53
```html
<style>
  circle { transition: all 1s ease; }
</style>
54 55 56
<script src="../../ui/morphdom/dist/morphdom-umd.min.js"></script>
<script type="text/html" data-engine="vdom" class="bouncing-ball">
  <svg width="500" height="50">
57 58 59 60 61
    <circle cx="<%= x %>" cy="<%= y %>" r="5" fill="red"/>
  </svg>
</script>
<script>
  setInterval(function() {
62 63 64
    var x = Math.random() * 500
    var y = Math.random() * 50
    $('.bouncing-ball').template({x: x, y: y})    // Update the template to animate
65 66 67 68 69 70 71 72 73 74 75 76 77 78
  }, 1000)
</script>
```

You can also specify a `data-engine` via an option. For example:

```js
$('script.animate').template(data, {engine: 'vdom'})
```


## $.template targets

To re-use the template or render the same template on a different DOM node,
79 80 81
run `.template(data, {target: selector})`. This allows you to declare templates
once and apply them across the body. For example:

82 83 84 85 86 87 88 89 90 91 92 93
<!-- render:html -->
```html
<div class="panel1 bg-primary text-white px-3"></div>
<div class="panel2 bg-success text-white px-3"></div>
<script type="text/html" class="targeted">
  The same template is rendered in <%- heading %>
</script>
<script>
$('script.targeted')
    .template({heading: 'panel 1'}, {target: '.panel1'})
    .template({heading: 'panel 2'}, {target: '.panel2'})
</script>
94 95
```

96 97
The target can also be specified via a `data-target=".panel1"` on the script
template. This is the same as specifying `{target: '.panel'}`. For example:
98 99

```html
100 101
<script class="chart" data-target=".panel1">...</script>
<script class="chart" data-target=".panel2">...</script>
102 103 104 105 106
```


## $.template append

107 108
To append instead of replacing, use `data-append="true"`. Every time `.template`
is called, it appends rather than replaces. For example:
109

110 111 112 113 114 115
<!-- render:html -->
```html
<script type="text/html" class="list" data-append="true">
  <li>New item #<%- n %> appended</li>
</script>
<script>
116
$('script.list')
117 118 119
  .template({n: 1})
  .template({n: 2})
</script>
120 121
```

122 123
You can also specify this as `.template(data, {append: true})`. You can also
append to an [existing target](#template-targets). For example:
124

125
<!-- render:html -->
126
```html
127
<ul class="existing-list">
128 129 130
  <li>Existing item</li>
  <!-- Every time .template() is called, the result is added as a list item here -->
</ul>
131 132 133 134 135
<script>
$('script.list')
    .template({n: 1}, {append: true, target: '.existing-list'})
    .template({n: 2}, {append: true, target: '.existing-list'})
</script>
136 137
```

138

139
## $.template external source
140

141
Template containers can have an `src=` attribute that loads the template from a file:
142

143
<!-- render:html -->
144
```html
145
<script type="text/html" src="template.html" class="source"></script>
146
<script>
147
  $('script.source').template()
148 149
</script>
```
150

151 152
If the `src=` URL returns a HTTP error, the HTML *inside* the script is rendered
as a template. The template can use:
153 154

- all data passed by the `$().template()` function, and
155
- an [xhr](http://api.jquery.com/Types/#jqXHR) object - which has error details.
156 157 158

For example:

159
<!-- render:html -->
160
```html
161 162
<script type="text/html" src="missing.html" class="missing">
  Template returned HTTP error code: <%= xhr.status %>.
163 164 165
  Data is <%= data %>
</script>
<script>
166
  $('script.missing').template({data: [1, 2, 3]})
167 168 169
</script>
```

170 171
## $.template selector

172
`$(...).template()` renders all `script[type="text/html"]` nodes in or under the
173 174 175
selected node. Use `data-selector=` attribute to change the selector. For
example:

176
<!-- render:html -->
177
```html
178 179 180
<section data-selector=".render">
  <script type="text/html" class="no-render">This will not render</script>
  <script type="text/html" class="render">This will render</script>
181 182
</section>
<script>
183
  $('section[data-selector]').template()
184 185 186
</script>
```

187
You can also use the `selector: ...` option. For example:
188

189
<!-- render:html -->
190
```html
191 192 193
<div class="selector-target"></div>
<script type="text/html" class="try no-render">This will not render</script>
<script type="text/html" class="try render">This will render</script>
194
<script>
195
  $('script.try').template({}, {selector: '.render', target: '.selector-target'})
196 197 198
</script>
```

199 200 201 202 203 204 205 206 207

## $.template events

- `template` is fired on the source when the template is rendered. Attributes:
    - `templatedata`: the passed data
    - `target`: the target nodes rendered, as a jQuery object

For example:

208 209 210 211 212 213 214 215 216 217
<!-- render:html -->
```html
<script type="text/html" class="event">
  <pre>Event e.templatedata = <span class="data">filled by event handler</span></pre>
</script>
<script>
$('script.event')
  .on('template', function(e) {       // When the template is rendered,
    $(e.target).find('.data')         // find the <pre> tag inside target nodes
      .html(JSON.stringify(e.templatedata)) // and enter the template data
218
  })
219 220
  .template({x: 1})                   // Trigger template AFTER .on('template')
</script>
221
```