miso
Copyright(C) 2016-2026 David M. Johnson
LicenseBSD3-style (see the file LICENSE)
MaintainerDavid M. Johnson <code@dmj.io>
Stabilityexperimental
Portabilitynon-portable
Safe HaskellSafe-Inferred
LanguageHaskell2010

Miso.Binding

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

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:

  • --> — parent→child
  • <-- — child→parent
  • <--> — bidirectional (Parent precedence on mount)

For van Laarhoven Lens':

  • ---> — parent→child
  • <--- — child→parent
  • <---> — bidirectional (Parent precedence on mount)

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.

Constructors

Child 
Parent 

Instances

Instances details
Show Precedence Source # 
Instance details

Defined in Miso.Binding

Eq Precedence Source # 
Instance details

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 a -> Lens model a -> Binding parent model infixl 0 Source #

Constructs a unidirectional Binding that propagates a field from the child model back into the parent model. Changes to the parent field are not reflected into the child.

Uses the miso Lens representation. For van Laarhoven lenses use <---.

Since: 1.9.0.0

(-->) :: Lens parent a -> Lens model a -> Binding parent model infixr 0 Source #

Constructs a unidirectional Binding that propagates a field from the parent model into the child model. Changes to the child field are not reflected back to the parent.

Uses the miso Lens representation. For van Laarhoven lenses use --->.

Since: 1.9.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

(<---) :: Lens' parent field -> Lens' child field -> Binding parent child infixl 0 Source #

Constructs a unidirectional Binding that propagates a field from the child model back into the parent model. Changes to the parent field are not reflected into the child.

Uses the van Laarhoven Lens' representation. For miso lenses use <--.

Since: 1.9.0.0

(--->) :: Lens' parent field -> Lens' child field -> Binding parent child infixr 0 Source #

Constructs a unidirectional Binding that propagates a field from the parent model into the child model. Changes to the child field are not reflected back to the parent.

Uses the van Laarhoven Lens' representation. For miso lenses use -->.

Since: 1.9.0.0