Elements with an [up-keep]
attribute will be persisted during
fragment updates.
Common use cases for [up-keep]
include:
<video>
, <audio>
) that should retain their playback state during updates.The element must have a derivable target selector so Unpoly can find its position within new content.
Emits the up:fragment:keep
event.
A common use case is to preserve the playback state of media elements:
<article>
<p>Content</p>
<audio id="player" up-keep src="song.mp3"></audio>
</article>
When targeting the <article>
fragment, the <audio>
element and
its playback state will be the same before and after the update. All other elements (like the <p>
)
will be updated with new content.
Unpoly will only keep an existing element if:
[up-keep]
attributeThe element has multiple methods to veto against being kept:
[up-keep=false]
attribute on the new element version.[id]
or [up-id]
attribute so its derived target no longer matches the existing element.up:fragment:keep
event that is emitted on the existing element.up:fragment:keep
event that is passed to an [up-on-keep]
callback on the element.You can also choose to render without keeping elements:
[up-keep]
elements by setting an [up-use-keep=false]
attribute.[up-keep]
elements by passing an { useKeep: false }
option.Let's say we want only keep an <audio up-keep>
element as long as it plays
the same song (as identified by the tag's src
attribute).
On the client we can achieve this by listening to an up:keep:fragment
event
and preventing it if the src
attribute of the old and new element differ:
up.on('up:fragment:keep', 'audio', function(event) {
if (element.getAttribute('src') !== event.newElement.getAttribute('src')) {
event.preventDefault()
}
})
Even when keeping elements, you may reconcile its data object with the data from the new element that was discarded.
Let's say you want to display a map within an element. The center of the map
is encoded using an [up-data]
attribute:
<div id='map' up-keep up-data='{ "lat": 50.86, "lng": 7.40 }'></div>
We can initialize the map using a compiler like this:
up.compiler('#map', function(element, data) {
var map = new google.maps.Map(element)
map.setCenter(data)
})
While we want to preserve the map during page loads, we do want to pick up
a new center coordinate when the containing fragment is updated. We can do so by
listening to an up:fragment:keep
event and observing event.newData
:
up.compiler('#map', function(element, data) {
var map = new google.maps.Map(element)
map.setCenter(data)
map.addEventListener('up:fragment:keep', function(event) { // mark-line
map.setCenter(event.newData) // mark-line
}) // mark-line
})
Tip
Instead of keeping an element and update its data you may also preserve an element's data through reloads.
[up-keep]
attribute is only supported for elements within the <body>
.<audio up-keep>
or <video up-keep>
element is a direct child of the <body>
,
it will lose its playback state during a fragment update. To preserve its playback
state, insert a container element between the <body>
and the media element.Code to run before an existing element is kept during a page update.
Calling event.preventDefault()
will prevent the element from being kept.
It will then be swapped with newFragment
.
The code may use the variables event
(of type up:fragment:keep
),
this
(the old fragment), newFragment
and newData
.