| Copyright | (C) 2016-2026 David M. Johnson |
|---|---|
| License | BSD3-style (see the file LICENSE) |
| Maintainer | David M. Johnson <code@dmj.io> |
| Stability | experimental |
| Portability | non-portable |
| Safe Haskell | Safe-Inferred |
| Language | Haskell2010 |
Miso.Binding
Contents
Description
Data Bindings
Miso.Binding provides an experimental mechanism for synchronizing
model fields between a parent and child Component using
Lens-based bindings. Rather than coordinating state
through explicit message passing, a Binding declares a directed or
bidirectional edge between two model fields. When the runtime detects
that a bound field has changed, it propagates the new value to the
connected component automatically.
Note: This feature is experimental. For production inter-component
communication, prefer asynchronous messaging via broadcast or
Miso.PubSub.
How It Works
A Binding encodes a directed edge in the component graph. Each
edge is described by a pair of lenses — one projecting into the parent
model and one into the child model — that must share a common field
type. After each update cycle the runtime reads the source field
through its lens and writes it into the destination model through the
other lens, according to the edge direction.
Example
Suppose a parent component tracks a user's name, and a child component independently maintains a display name. Declaring a bidirectional binding keeps both fields in sync automatically:
{-# LANGUAGE TemplateHaskell #-}
import Miso
import Miso.Binding
import Miso.Lens.TH (makeLenses)
import Miso.String (MisoString)
data ParentModel = ParentModel { _userName :: MisoString } deriving Eq
data ChildModel = ChildModel { _displayName :: MisoString } deriving Eq
makeLenses ''ParentModel
makeLenses ''ChildModel
-- Declare the child Component with a bidirectional Binding.
-- Changes to either field will be reflected in the other.
childComp :: Component ParentModel () ChildModel ChildAction
childComp = (component initialChild updateChild viewChild)
{ bindings = [ userName <--> displayName ] }
On mount, the parent field takes precedence by default (see Precedence).
To invert that behaviour, use instead.<<-->
See the miso-reactive project for extended examples.
Synopsis
- data Binding parent child
- = ParentToChild (parent -> field) (field -> child -> child)
- | ChildToParent (field -> parent -> parent) (child -> field)
- | Bidirectional Precedence (parent -> field) (field -> parent -> parent) (child -> field) (field -> child -> child)
- data Precedence
- (<-->) :: Lens parent field -> Lens child field -> Binding parent child
- (<<-->) :: Lens parent field -> Lens child field -> Binding parent child
- (<-->>) :: Lens parent field -> Lens child field -> Binding parent child
- (<--) :: Lens parent a -> Lens model a -> Binding parent model
- (-->) :: Lens parent a -> Lens model a -> Binding parent model
- (<--->) :: Lens' parent field -> Lens' child field -> Binding parent child
- (<<--->) :: Lens' parent field -> Lens' child field -> Binding parent child
- (<--->>) :: Lens' parent field -> Lens' child field -> Binding parent child
- (<---) :: Lens' parent field -> Lens' child field -> Binding parent child
- (--->) :: Lens' parent field -> Lens' child field -> Binding parent child
Types
data Binding parent child Source #
A Binding encodes a directed or bidirectional synchronization edge
between a field in a parent model and a field in a child model. The
field is projected via a pair of lenses that must share a common type.
After each update cycle the runtime evaluates all bindings registered
in a Component and propagates field values along each edge according
to its direction. On initial mount the Precedence value determines
which side wins when both fields carry different values.
Construct bindings using the operator combinators rather than the data
constructors directly. For miso Lens:
For van Laarhoven Lens':
Since: 1.9.0.0
Constructors
| ParentToChild (parent -> field) (field -> child -> child) | |
| ChildToParent (field -> parent -> parent) (child -> field) | |
| Bidirectional Precedence (parent -> field) (field -> parent -> parent) (child -> field) (field -> child -> child) |
data Precedence Source #
Determines which side of a Bidirectional binding wins when parent
and child fields carry different values at Component mount time.
After the initial mount both sides are kept in sync, so Precedence
only affects the very first reconciliation.
Instances
| Show Precedence Source # | |
Defined in Miso.Binding Methods showsPrec :: Int -> Precedence -> ShowS # show :: Precedence -> String # showList :: [Precedence] -> ShowS # | |
| Eq Precedence Source # | |
Defined in Miso.Binding | |
Combinators
(<-->) :: Lens parent field -> Lens child field -> Binding parent child infix 0 Source #
Constructs a bidirectional Binding between a parent field and a
child field using the miso Lens representation. Changes
to either field are propagated to the other after each update cycle.
On Component mount, the parent field takes Precedence over the
child field. Use to invert this and let the child win, or
<--> to state the parent precedence explicitly.<<-->
For van Laarhoven lenses use .<--->
Since: 1.9.0.0
(<<-->) :: Lens parent field -> Lens child field -> Binding parent child Source #
Like but sets <-->Precedence to Child, so the child
field overwrites the parent field on Component mount. Use this
when the child component owns the authoritative initial value for
the shared field.
Since: 1.10.0.0
(<-->>) :: Lens parent field -> Lens child field -> Binding parent child Source #
Like but explicitly sets <-->Precedence to Parent, so
the parent field overwrites the child field on Component mount.
This is the default behaviour of use this combinator
when you want to be explicit about the precedence.<-->
Since: 1.10.0.0
(<--->) :: Lens' parent field -> Lens' child field -> Binding parent child infix 0 Source #
Constructs a bidirectional Binding between a parent field and a
child field using the van Laarhoven Lens' representation.
Changes to either field are propagated to the other after each update
cycle.
On Component mount, the parent field takes Precedence over the
child field. Use to invert this and let the child win, or
<<---> to state the parent <--->>Precedence explicitly.
For miso lenses use .<-->
Since: 1.9.0.0
(<<--->) :: Lens' parent field -> Lens' child field -> Binding parent child Source #
Like but sets <--->Precedence to Child, so the child
field overwrites the parent field on Component mount. Use this
when the child component owns the authoritative initial value for
the shared field.
Since: 1.10.0.0
(<--->>) :: Lens' parent field -> Lens' child field -> Binding parent child Source #
Like but explicitly sets <--->Precedence to Parent, so
the parent field overwrites the child field on Component mount.
This is the default behaviour of ; use this combinator
when you want to be explicit about the <--->Precedence.
Since: 1.10.0.0