This are all examples collected in a single page, they are also present on respective directive pages. This page is used mostly for CI.
This document has tests embedded in examples, to run them, press:
Fragment Updating #
Explanation: on click link issues a request to a server, and then is replaced with a new link from a response.
Use only part of the response #
Server returns more HTML than we need - maybe a full template is rendered, maybe something else is going on - and we need to use just a part of it.
Triggering Requests #
Usually requests are triggered on natural interrupts: submit on forms and clicks elsewhere, but sometimes you want more, like triggering on being seen or hovered:
Before/After Request #
This example demostrates how you can interfere with request using
Collecting Data #
ts-data with three keys
(a, b, c) and then child
a adds another entry with key
b, drops existing
c value and adds another
(so it overrides
c value). And then sends a
request to a backend. Click link to see what data was sent.
Form With Data #
Form can be a bit tricky to collect data correctly, particularly weird thing is when you have a few submit buttons. The following form has:
- a text input
- a hidden input
- additional data in
- two submit buttons
When you click one of the buttons, you can observe that only that button was included in the data &emdash; which is what you need to decide which action to take.
Click a button to replace me with form data.
Targeting Other Elements #
Default behavior is to replace element, which issues the request (in this
ts-target sets another element as a
target for the request.
I'm waiting... Do it!
Targeting Parents #
This is very common pattern - when a button needs to update an element around
parent will search upwards for a suitable
Wanna read text behind me? Do it!
Relative Targeting (advanced)#
Most twinspark commands and extensions operate directly on the current
target element. However, some of them might require a pair of elements
(e.g. a command that copies data from one input to another). This means
supplying a TwinSpark selector as an argument. To point directly to
the current target element, use the
Click here or here
to copy the value here:
Click one of these buttons to rename it with the value above: or
Another useful target is the element that created the event. The simplest
way to access it is to create a twinspark extension that sets
Changing URL #
Clicking on each of those links in turn will cause URL to change and add a new entry in browser's history.
It's really irritating when you click a link and nothing happens for some
time. Luckily TwinSpark makes it really easy: it adds attribute
aria-busy="true" to an origin element.
Those are simple examples of using actions, see their source for details.
Hey! I'm here!
Remove with timeout
wait (waiting for an event to happen)
Remove after transition
Demo of multiple actions
This is going to be removed
And this only after transition
An advanced example showing how to use actions (in particular
req) in conjunction with
It adds a handler to
sortupdate event, which is raised by
html5sortable, and then triggers a POST request to a backend
to store a new order.
🙂Smile 😇Halo 😁Beam 🤣ROFL
Here you'll see sorted names.
Doing something when element is almost visible makes it possible to implement lazy loading and various analytical events
You'll probably see this text after around 5 seconds or so. Click "Reset" to see loader again.
This sentence will log some message when it becomes invisible (moves out of browser viewport, and, actually, on load as well).
Click Outside #
Popups, modals, menus and some other elements can make use of
happened outside. It could be done with markup and underlying element,
but why bother if you have straightforward trigger.
This trigger is ideally used with modifier
once, since you're
probably going to remove that modal you calling it on - using
will clean up your listeners so you won't get memory leaks.
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
Element 1 Element 2
Element 1 Element 2
Multiple Fragments #
First element is updated through regular flow with
Second element uses
Third element uses
The latter has a form
[replace strategy]: [selector-in-document] <= [selector-in-response].
Also waiting here.
Here all spans trigger request on
visible, so click "Reset" to
see more requests. See sources and debug panel to see how requests are
combined in a single one.
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.
- Inputs have an
idattribute - so that morphing algorithm can find them reliably.
- POST body contains
<input type="submit">'s value - this way backend distinguish submission and validation.
keyupupdates form on every character input and it feels natural - morph algorithm skips currently focused element so that state is intact.
Solve this problem with odd numbers
On Removal (advanced)#
It is useful to do something when node is removed (especially if that's some child or even non-related node triggering that removal). It's possible, but not recommended to use often since performance characteristics of the code are not well understood.
When this paragraph is removed by clicking button, it will resurrect itself.
Pipelining Actions (advanced)#
Actions pipe their return values into next action as
the source of the next example to see how it works.
<script> in response (advanced)#
innerHTML to a value which contains
that for you, check it out.
Autocomplete is interesting because it executes many things at once. Just look at the source, the interesting part is trigger modifiers - it does something only if user typed something (rather than just navigated field with cursor keys) and then stopped for 100 ms.
When autocomplete triggers a time-consuming operation (e.g. full-text search),
the implementation above triggers numerous requests if the user types slow
enough. If requests finish at different durations, an older request can
override the latest. To avoid this, we need to abort the XHR using
Progress Bar #
Smooth progress bar with updates from a server
If you look at source, there is a button targeting parent
When you click it, server responds with a new markup, which will make a
request to a server again in 500 ms thanks to
Interesting part of that response is
div id="pb1", which is
actually progress bar. Each new response from the server uses the same id, so
settling kicks in, and makes
.bar-item transition work.
Filtering on ecommerce sites is a complex task. On one side you want it to be crawlable by Google, on the other if a user selected two filters one by one you'd like to see products, filtered by both. Naïve implementation will filter only one of them if a pause between clicks was short enough. It seems like the best way is form, full of links (so that Google/no-js envs can still use it), which toggle checkboxes when JS is enabled and auto-submit form.
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.
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.