Josh,

The code snippet you wrote is just the standard architecture. This is what 
I would expect.. 

But, if I'm understanding your previous messages correctly, it sounds like 
you're suggesting that nested components should "message" (such as with 
OutMsg in the brian hicks article you recommended 
<https://www.brianthicks.com/post/2016/06/23/candy-and-allowances-parent-child-communication-in-elm/>)
 
to their direct parent when requesting data. If that's correct, I think 
you're going to run into some problems. 

I'm assuming your child component might message something like this:

module Child exposing(..)

-- model... 

type Msg
  = ResourceRequested
  | ResourceLoading
  | ResourceFailed
  
type OutMsg
  = *GiveMeResourceById String*
  
update : Msg -> Model -> ( Model, Cmd Msg, Maybe OutMsg )
update msg model =
    case msg of
        ResourceRequested ->
            ( model, Cmd.none, Just *GiveMeResourceById "2353253"* )

Great, *GiveMeResourceById* has been passed upwards to the parent. We know 
the Parent will need to pass a Parent.OutMsg upwards to the grandparent, 
but unfortunately, we can't simply wrap the Child.OutMsg in a Parent.OutMsg 
as we normally would since we'd lose all context of the child's request - 
The Grandparent would receive a generic Parent.OutMsg and wonder "what do I 
do with this?".


module Parent exposing (..)

import Child

type OutMsg
  = *ChildOutMsg Child.OutMsg*  -- wait! this won't work

update : Msg -> Model -> ( Model, Cmd Msg, Maybe OutMsg )


Instead, rather than wrapping the child's OutMsg, the parent would likely 
return a brand new local OutMsg that communicates the child's original 
intent, and value:

module Parent exposing (..)

import Child

type Msg
  = ChildMsg Child.Msg

type OutMsg
  = GiveChildResourceById String

update : Msg -> Model -> ( Model, Cmd Msg, Maybe OutMsg )
update msg model =
    case msg of
        ChildMsg submsg ->
          let
            (childModel, childCmd, childOutMsg) = 
                Child.update submsg model.childModel
          in
            ( { model | childModel = childModel }, Cmd.map ChildMsg 
loginCmd, convertChildOutMsg childOutMsg )

convertChildOutMsg : Maybe Child.OutMsg -> Maybe Parent.OutMsg
convertChildOutMsg msg = 
  case msg of 
    Just Child.GiveMeResourceById id -> 
      Just GiveChildResourceById id
    Nothing -> 
       Nothing


This process will be repeated between child and parent until we reach the 
root. Great... so the root has now processed the request and is ready to 
return data. How does it do that? The original suggestion of passing values 
down using the TEA no longer works, since the OutMsgs were not wrapped on 
the way up... there is nothing to unwrap on the way down. 


case msg of
...
  Apple msg ->
    { model | apple = Apple.update(msg) } -- handwavy, you want to catch 
`Cmd` as well
  Api msg ->
    { model | api = Api.update(msg) } -- ditto, deal with Cmd like in 
Keyboard.extra


The components msgs must be generated and converted from parent context to 
child context each downward step. If you expand this to multiple child 
components each making multiple api requests, you're going to quickly have 
OutMsg explosion - Each child's OutMsg involved in api request will be 
duplicated in its parent, and its parent.. all the way up to the root.

Here is a hicks article that also briefly touches on this point..
https://www.brianthicks.com/post/2016/07/05/duplicate-message-or-update-contexts-in-elm-components/

Anyways, this is getting somewhat away from the issue that I'm having with 
Authentication. I think I'll open a new thread with a more direct question.

Thanks again for the suggestions Josh.


On Tuesday, July 5, 2016 at 8:46:13 PM UTC-4, Josh Adams wrote:
>
> If it then needs to proxy requests through its direct parent - the 
>> AdminComponent - the AdminComponent will contain message like:
>>
>> type Msg
>>    = LoadAppleComponentApples
>>    | AppleComponentApplesLoading
>>    | AppleComponentApplesFailure Error
>>    | AppleComponentApplesSuccess Data
>>    ... etc etc for each Component type
>>
>> Is this still on par with what you're suggesting?
>>
>
> Aha, no.  See the README for Keyboard.Extra - 
> http://package.elm-lang.org/packages/ohanhi/keyboard-extra/1.0.1
>
> A typical TEA would see something like a single tag for a given component 
> in the parent, and routing messages through to it.  So in general I would 
> expect to see something like:
>
> case msg of
> ...
>   Apple msg ->
>     { model | apple = Apple.update(msg) } -- handwavy, you want to catch 
> `Cmd` as well
>   Api msg ->
>     { model | api = Api.update(msg) } -- ditto, deal with Cmd like in 
> Keyboard.extra
>
> Then I could see the API supporting `LoadApples` or some such, and getting 
> that message up to the Root by saying `AskForApples`.  The root would proxy 
> to the API, and it would use the messages it knows about re: telling 
> AppleComponent about new data - presumably it got its data from somewhere 
> upstream.
>
> I might be in vehement agreement with you here - I think you're worried 
> about incidental complexity and I'm worried about coupling.  I *really* 
> want someone else to pipe in because I fear I might be sending you on a 
> wild goose chase, but I've spent a lot of time thinking about these things 
> without yet having built something of decent size in Elm (lots and lots and 
> lots of toys though!).  In general, though, the idea of a component knowing 
> about the backend API sends chills up my spine.
>
>

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to