ts-swap
Controls how HTML is going to be inserted into your page. Should be set on an origin element. Can be one of the following keywords:
Strategy | Description |
---|---|
replace | (default) replace target element with an incoming element |
inner | replaces target's children with an incoming element |
prepend | inserts incoming element as a first child of the target |
append | inserts incoming element as a last child of the target |
beforebegin | inserts incoming element before target |
afterend | inserts incoming element after target |
morph | morphs incoming element into target (see lower) |
morph-all | same as morph , but does not skip document.activeElement when changing elements |
skip | just skip that response, sometimes useful for operations with side-effects |
Settling
With the exception of morph
, morph-all
(see further) and skip
strategies,
TwinSpark will try to “settle” all elements with an id
attribute.
New elements with an id
will be inserted with ts-insert
class, which is then
removed. Existing elements will be inserted with an old values in settle
attibutes (by default this is class
, style
, width
and height
), and then
given new values shortly afterwards.
This makes transitions work: same element changes from old to new values, which triggers transitions.
Morph
Morph is a complex algorithm, and it could take tens of ms on complex layouts, but it could be really useful at times.
Main idea is to keep elements with id
in place, only updating their
attributes, so that all the browser state (focus, transitions, animations,
playing state of videos and audios) is kept intact. This makes doing form
validation and various animations easy.
Every new element with an id
attribute is insert with a ts-insert
class. It
is removed after a short timeout, so you can add some transitions on that. Same
with elements being removed, they are given ts-remove
class, so you can
transition to that.
Original idea is from idiomorph.
TwinSpark has a somewhat smaller implementation, see code for details (search
for Morph
).
Examples
Multiple Children #
If you look how endless scrolling is implemented in HTML, it's usually a long
list of elements inside some other element - so you have to deal with several
elements being appended to a parent. For this and similar use cases there is
a modifier children
in ts-req-selector
.
Demo
Element 1 Element 2
<p class="list2">
<span class="chip">Element 1</span>
<span class="chip">Element 2</span>
<button class="btn"
ts-req="/children"
ts-req-selector="children .list"
ts-target="sibling .chip:last-of-type"
ts-swap="morph">Morph last</button>
</p>
Dynamic Form Validation (advanced)#
Form validation is a common task, and TwinSpark allows to consolidate
validation logic on the server. Surprisingly, it could be difficult, but
ts-swap="morph"
strategy allows us to just return whole new form
with errors and not mess up with focus.
Important bits
- Inputs have an
id
attribute - so that morphing algorithm can find them reliably. - POST body contains
<input type="submit">
's value - this way backend distinguish submission and validation. keyup
updates form on every character input and it feels natural - morph algorithm skips currently focused element so that state is intact.
Demo
Solve this problem with odd numbers
Animated Pagination #
Morphing gives you ability to add animations and transitions during HTML replacement. This example uses zero lines of custom JS, just some styles to add transitions.
Demo
Morphing Video #
This is a hard problem to solve with other algorithms (notably, morphdom gets
it wrong). HTML structure is changed a lot, and element with an
id
is deep (enough) inside that structure, but Youtube video
still plays after change.