Laminar v17.1.0, News & Stickers
New Airstream features: splitting Vars, and zooming into Vars without an owner.
Laminar is a Scala.js library for building web application interfaces and managing UI state. Learn more in a few short examples or one long video.
Releases
News
Scala.js & Laminar in Healthcare
The HeartAI team are using Scala.js and Laminar to develop their Critical Care Informatics System for CALHN, a major health network in South Australia. A key feature of this system, ICU ward and bed dashboards, support critical care workers with high-quality health information about ICU patients. "Scala.js and Laminar have provided a scalable way to build robust applications in the complex health domain." – says Lukah Dykes, Managing Director at HeartAI.
Laminar Stickers
In case you missed it, I'm mailing out free Laminar stickers as a thank you to people who have, in one way or another, contributed to Laminar or the ecosystem. Sign up here.

New Airstream Features
Splitting Var-s
You could always split a Signal[Collection[A]] into N individual Signal[A], but now you can also directly split a Var[Collection[A]] into N individual Var[A] that are linked to the original Var[Collection[A]].
For example, in the example below, the user's name in both userVar and usersVar is updated when you type the new name into the input text box.
case class User(id: String, name: String)
val usersVar = Var[List[User]](???)
div(
usersVar.split(_.id)((userId, initial, userVar) => {
div(
s"User ${userId}: ",
input(
value <-- userVar.signal.map(_.name),
onInput.mapToValue --> { newName =>
userVar.update(_.copy(name = newName))
}
)
)
})
)
Previously in this situation, you would have needed to update usersVar manually by finding the user with id == userId and updating the list with the new user at that index. Now this is done behind the scenes just by updating userVar.
Also, in addition to split, you can also use splitMutate on Vars that contain mutable collections. As the name implies, it works the same as regular Var.split, except that when you update userVar, it would mutate the collection in usersVar instead of creating a copy of it as is usually done with immutable collections. This may be more efficient when working with very large mutable collections.
Zoom into a Var without needing an Owner
Airstream has had the zoom method to create derived vars for a while now: Var.zoom(a => b)((a, b) => a)(implicit owner). Unfortunately, that method required an Owner, which made using it rather annoying.
Recently, @KitLangton has figured out that this Owner isn't really needed, and so we now have a new zoomLazy(a => b)((a, b) => a) method that does not require an Owner, and otherwise works pretty much the same. One catch is that your zoomIn (a => b) function is now called lazily, so it shouldn't have side effects. In practice that shouldn't be a problem because this function typically just selects some field from an object.
This small change should help a lot with ergonomics of local state management.
We use the zoomLazy name to stay binary-compatible with 17.0.0 in this release, but in the next major release, zoomLazy will be renamed to zoom, and the old zoom will be renamed to zoomStrict and deprecated.
Small stuff
- New:
.notalias to the.invertoperator on observables of booleans - The
Splittabletrait has two new methods:foreachandfindUpdate. Migration: if you have custom instances ofSplittablefor non-standard collection types, make sure to review the default implementations of those methods for efficiency.
Waypoint bug fix
- Waypoint upgraded to URL-DSL 6.0.2:
- Fixed a case with
listParamwhere matching failed if no query parameters were provided in the URL, whereas it should have matched asNil. Thanks, @arturaz!
- Fixed a case with
Thank you
Laminar development is kindly supported by my sponsors, and I am very grateful to be able to work on all this.
DIAMOND sponsor:
GOLD sponsors:
