1

If I have a grandparent, a child component, and a grandchild component, can the grandparent request the state of the child? I've tried using "request" like here but the types don't match up when you're requesting the state of a child that also has a child of its own. The example in the guide works fine when I'm requesting the state of a child that does not have children.

The error is:

Could not match type

  Query

with type

  Coproduct (Coproduct Query (ChildF AnswerSlot Query)) Query
sportanova
  • 125
  • 3
  • 8

1 Answers1

1

Yes, definitely. You're probably just missing a left in the query to the child - that's required as the child's query algebra will be of the form Coproduct f (ChildF p f') with it having its own child.

Correspondingly, you can query the grandchild from the grandparent too, by using right and constructing a ChildF with the appropriate values for the grandchild.

I've put together a contrived example of querying both child and grandchild that will hopefully make things clearer:

module Main where

import Prelude

import Data.Functor.Coproduct (Coproduct, left, right)
import Data.Maybe (Maybe(..), fromMaybe)

import Debug.Trace (traceA) -- from purescript-debug

import Halogen as H
import Halogen.HTML as HH

--------------------------------------------------------------------------------

type GrandState = Unit
data GrandQuery a = AskGrandChild (String -> a)

grandchild :: forall g. H.Component GrandState GrandQuery g
grandchild = H.component { render, eval }
  where
  render :: GrandState -> H.ComponentHTML GrandQuery
  render _ = HH.div_ []
  eval :: GrandQuery ~> H.ComponentDSL GrandState GrandQuery g
  eval (AskGrandChild k) = pure $ k "Hello from grandchild"

--------------------------------------------------------------------------------

type ChildState = Unit
data ChildQuery a = AskChild (String -> a)
type GrandSlot = Unit

type ChildState' g = H.ParentState ChildState GrandState ChildQuery GrandQuery g GrandSlot
type ChildQuery' = Coproduct ChildQuery (H.ChildF GrandSlot GrandQuery)

child :: forall g. Functor g => H.Component (ChildState' g) ChildQuery' g
child = H.parentComponent { render, eval, peek: Nothing }
  where
  render :: ChildState -> H.ParentHTML GrandState ChildQuery GrandQuery g GrandSlot
  render _ = HH.slot unit \_ -> { component: grandchild, initialState: unit }
  eval :: ChildQuery ~> H.ParentDSL ChildState GrandState ChildQuery GrandQuery g GrandSlot
  eval (AskChild k) = pure $ k "Hello from child"

--------------------------------------------------------------------------------

type ParentState = Unit
data ParentQuery a = Something a
type ChildSlot = Unit

type ParentState' g = H.ParentState ParentState (ChildState' g) ParentQuery ChildQuery' g ChildSlot
type ParentQuery' = Coproduct ParentQuery (H.ChildF ChildSlot ChildQuery')

parent :: forall g. Functor g => H.Component (ParentState' g) ParentQuery' g
parent = H.parentComponent { render, eval, peek: Nothing }
  where
  render :: ParentState -> H.ParentHTML (ChildState' g) ParentQuery ChildQuery' g ChildSlot
  render _ = HH.slot unit \_ -> { component: child, initialState: H.parentState unit }
  eval :: ParentQuery ~> H.ParentDSL ParentState (ChildState' g) ParentQuery ChildQuery' g ChildSlot
  eval (Something next) = do

    -- note the `left` here
    childAnswer <- H.query unit $ left $ H.request AskChild
    traceA $ fromMaybe "child not found" $ childAnswer

    grandAnswer <- H.query unit $ right $ H.ChildF unit $ H.request AskGrandChild
    traceA $ fromMaybe "grandchild not found" $ grandAnswer

    pure next
gb.
  • 4,629
  • 1
  • 20
  • 19
  • Ah such a simple thing - thanks! I need to take the time to understand how the query algebra works. Right now I'm just cargo culting.. – sportanova Jul 16 '16 at 01:32
  • I worked out an example where the grandparent has multiple types of children - would that be a relatively simple change as well to request their state? Here's an example https://gist.github.com/sportanova/e779fef9f27dbbe1097a064d231c7316 – sportanova Jul 16 '16 at 01:33
  • Yep, you need to use `query'` for that so a `ChildPath` can be specified: https://gist.github.com/garyb/73cb5d0c586eb29b319d5859b3747638 – gb. Jul 16 '16 at 11:20