Unpoly lets you attach structured data to an element, to be consumed by a compiler or event handler.
You may use HTML5 [data-*]
attributes
to attach simple string values:
<span class='user' data-age='18' data-name='Bob'>Bob</span>
An object with all data attributes will be passed to your compilers as a second argument:
up.compiler('.user', function(element, data) { // mark-phrase "data"
console.log(data.age) // => "18"
console.log(data.name) // => "Bob"
})
Important
Data attributes always have string values. In the example above
data.age
is a string.
Data attributes with multiple, dash-separated words in their name can be accessed with camelCase
keys:
<span class='user' data-first-name='Alice' data-last-name='Anderson'>Alice</span>
up.compiler('.user', function(element, data) {
console.log(data.firstName) // => "Alice"
console.log(data.lastName) // => "Anderson"
})
[up-data]
HTML5 data attributes cannot express structured data, like an array or object. Also their values are always strings.
For a more powerful alternative you can set the [up-data]
attribute to any
JSON value:
<div class='google-map' up-data='[
{ "lat": 48.36, "lng": 10.99, "title": "Friedberg" },
{ "lat": 48.75, "lng": 11.45, "title": "Ingolstadt" }
]'></div>
The JSON will be parsed and passed to your compiler function as a second argument:
up.compiler('.google-map', function(element, pins) {
var map = new google.maps.Map(element)
for (let pin of pins) {
var position = new google.maps.LatLng(pin.lat, pin.lng)
new google.maps.Marker({ position, map, title: pin.title })
}
})
Note how [up-data]
allows us to a attach a multitude of value types, like arrays (pins
), objects (pin
) and numbers (ping.lat
).
The topmost expression may be any JSON-serializable value, like an object:
<span class='user' up-data='{ "name": "Bob", "age": 18 }'>Bob</span>
up.compiler('.user', function(element, data) {
console.log(data.name) // => "Bob"
console.log(data.age) // => 18
})
If [up-data]
is a JSON object, any HTML5 data attributes will be merged into the parsed value:
<span class='user' data-name='Bob' up-data='{ "age": 18 }'>Bob</span>
up.compiler('.user', function(element, data) {
console.log(data.name) // => "Bob" from [data-name]
console.log(data.age) // => 18 from [up-data]
})
Your compilers and event handlers may access any HTML attribute
via the standard Element#getAttribute()
method.
Unpoly provides convenience functions to read an element attribute and cast it to a particular type:
up.element.booleanAttr(element, attr)
up.element.numberAttr(element, attr)
up.element.jsonAttr(element, attr)
Here is an example where we use arbitrary HTML attributes to attach data to our element:
<span class='user' name='Bob' age='18'>Bob</span>
up.compiler('.user', function(element) {
console.log(element.getAttribute('name')) // => "Bob"
console.log(up.element.numberAttr(element, 'age')) // => 18
})
Any attached data will also be passed to event handler registered with up.on()
.
For instance, this element has attached data in its [up-data]
attribute:
<span class='user' up-data='{ "age": 18, "name": "Bob" }'>Bob</span>
The data will be passed to your event handler as a third argument:
up.on('click', '.user', function(event, element, data) {
console.log("This is %o who is %o years old", data.name, data.age)
})
Use up.data(element)
to retrieve an object with the given element's data.
When reloading or validating an element,
you may keep an existing data object by passing it as a { data }
option.
As a shortcut may also pass { keepData: true }
.
In the example below, data.counter
is increased by 1
for every compiler pass,
regardless of what the server renders into [up-data]
:
up.compiler('.element', function(element, data) {
data.counter ??= 1 // set initial state
console.log('Counter is', data.counter) // logs 1, 2, 3, ...
data.counter++
element.addEventListener('click', function() {
up.reload(element, { data })
})
})
To keep an entire element, you may also use [up-keep]
.
The up:fragment:keep
event lets you inspect the old and new element
with its old and new data. You may then decide whether to keep the existing element,
swap it with the new version, or just update its data.