[elm-discuss] Re: Communicating from parent to child and child to parent
Hi Rex, I hope I interpret your setup correctly, but it looks like the flow is more or less: - user clicks a button inside child - this triggers child's update function - child's update function stores updates child model (with a message Click) - the parent can then access the new function by accessing the child's model What I do not understand is: you mention an UpdateButton message that the parent responds to, But what triggers this message? Typically, the parent does not know or care about child model contents or child model updates. The parent receives child messages, but parent does not read child messages. Parent simply passes the messages on to the child's update function, and stores the updated child model. This separation guarantees that you can modify code in your child component (e.g. change the child model, add new message types etc), and any parent will continue to work properly. No need to check or change code in any other component that imports the child. If any parent 'looks inside' the model or the messages of the child, then this guarantee breaks down. The discussion here (or at least my interest in this) is: How do I communicate a message from a child to parent, while at the same time maintaining the integrity of the child's model (so no peeking by parents into child model)? -- 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 elm-discuss+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
[elm-discuss] Re: Communicating from parent to child and child to parent
I hope I interpret your setup correctly, but it looks like the flow is more or less: - user clicks a button inside child - this triggers child's update function - child's update function stores updates child model (with a message Click) - the parent can then access the new function by accessing the child's model What I do not understand is: you mention an UpdateButton message that the parent responds to, But what triggers this message? Typically, the parent does not know or care about child model contents or child model updates. The parent receives child messages, but parent does not read child messages. Parent simply passes the messages on the child's update function, and stores the updated child model. This separation guarantees that you can modify code in your child component (e.g. change the child model, add new message types etc), and any parent will continue to work properly. No need to check or change code in any other component that imports the child. If any parent 'looks inside' the model or the messages of the child, then this guarantee breaks down. The discussion here (or at least my interest in this) is: How do I communicate a message from a child to parent, while at the same time maintaining the integrity of the child's model (so no peeking by parents into child model)? -- 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 elm-discuss+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
[elm-discuss] Re: Communicating from parent to child and child to parent
Hi Everyone! I'm confused about why this needs to be so complex? For example, let's say you have a button child that needs to to communicate its state to its parent. You could create a `currentMsg` property on the child button model like this: type alias ButtonModel = { currentMsg : Msg } Then when the child button is clicked, capture the current message on that same child model: update message childModel = case message of Click -> { childModel | currentMsg = message } The parent has a reference to that child button in its model: type alias ParentModel = { button : Button.ButtonModel } Then in the parent's `update` function, there might be an `UpdateButton` message that updates the child button's state and does something based on the value of `button.currentMsg` if parentModel.button.currentMsg == Click then -- do something useful This is how I've handled all my child-to-parent communication in the last few apps I've built. Can someone tell me if this is a bad idea or if there's a crucial part of the problem I'm not understanding? Is there a use case where this would not work? -- 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 elm-discuss+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [elm-discuss] Re: Communicating from parent to child and child to parent
In my app, I changed the standard update signature from: msg -> model -> ( model, Cmd msg ) to: msg -> model -> ( Maybe model, List msg, List notification ) Here was the reasoning for each of the changes: 1. Returning Maybe model: Laziness in view generation depends on not needlessly changing the data being passed to a view function. Originally, I was handling this by checking the results of sub-model updates for equality before updating the containing model. That approach, however, can run afoul of the fact that Elm doesn't like to compare functions for equality, so if your sub-model happens to contains a function, the equality comparison can result in JavaScript assertions. (Or at least it could in 0.16.) [*] So, instead, it seemed better to let update functions signal that they didn't change the model and maybe provided a good way to do that. 2. Lists of messages rather than a single command: This made the no command case easier to write — [] — and the batch function just wraps the list anyway. 3. Lists of notifications: This third parameter provides a way to pass information back up the hierarchy. For example, I have a notification that adds an error to a globally managed error list. Lower-level update functions can just observe that something went wrong, not update the model, and report the error up to the level where they are being collected. But this mechanism also allows the login logic to return a "LoggedIn userid" notification to the main app state manager. I've contemplated merging the commands and the notifications to get things down from three to two but they do behave rather differently. Commands get annotated with additional routing as they move up the hierarchy and are expected to flow out to the app logic to interact with the outside world. In contrast, notifications are destined for upper levels within the model update process and can absorbed, transformed, or passed on as appropriate. The passed on part is important. Where a command will get mapped so that it's result comes back to the sender, a notification isn't expected to come back anywhere and hence doesn't need mapping unless we have to change notification types. This approach has only been in place for a while so I'm not ready to give a definitive report, but it has seemed to clean up a lot of ad hoc logic. Mark [*] I've thought about whether Elm should fallback to essentially creation-defined equality — i.e.., values are equal if and only if they are the same JavaScript object — or offer an operator providing this test, but doing so would mean that various compiler optimizations could change the meaning of programs, so it's probably not a good idea. -- 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 elm-discuss+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [elm-discuss] Re: Communicating from parent to child and child to parent
On Jun 28, 2016, at 6:12 AM, Wouter In t Veltwrote: > > My specific use case: I have a list of children with a number of internal > messages (e.g. updates on each child). One of the functions I need to > implement is 'RemoveMeFromList', which is a button on each child. This > message type can only be handled by the parent, through removing child from > list and no longer rendering it in view. This is a place where presentation (view) hierarchy and data (model) hierarchy mix uncomfortably. Removal from the list of children has little to do with the child unless there are other updates that accompany the removal that only the child understands. It is purely an update to the parent. This is different from the child needing a way to express "I've run out of money". That is based on an update to information local to the child. What muddles this up is that the remove button is often presented as part of the presentation of the child and, in The Elm Architecture, we are trained to think of the presentation as being built by a view function from model to HTML and hence if the presentation contains a removal button then remove must be a message destined for the model. The Elm 0.16 architecture tutorial handled this by providing a separate address to which the remove message could be delivered. The Elm 0.17 documentation at present is silent on the subject. There have been proposals for how to deal with this in an Elm 0.16 style but they haven't been officially endorsed and result in view functions with a return type of Html parentMsg as opposed to Html ChildMsg which is a little ugly. There are also suggestions to use extra return values from the update function (as the essays linked to in this thread do) but those result in the child update function containing entries that basically just serve to route the remove message up to the parent thereby contaminating the update function with a complexity that previously only affected the view function. I've still been on Elm 0.16 because I've been waiting for key support, but I've been looking at 0.17 and one thing that does have me worried is that in getting rid of addresses may have increased coupling between the view hierarchy — driven by UX design concerns — and the model hierarchy which should be driven by data consistency concerns. While the default handling in the past for addresses led to a tight correspondence between the hierarchies, one could always work around it by providing an address along with a model (or as part of a model) wherever appropriate and it didn't feel too unnatural. One could probably do something similar by using routing functions(*) in much the same way as addresses in 0.16 but they feel like a fight against the intended use pattern. But all of those judgments are suspended pending more complete documentation for these cases for 0.17. Mark (*) view : (msg -> rootMsg) -> model -> Html rootMsg This could just use the standard Elm 0.17 routing instead (or in its implementation) but it stresses that the route isn't driven by the presentation but is rather information describing how to get messages to the relevant portion of the model. To make it work well with lazy HTML, it really needs to be based on embedding the route into the model and only computing it at initialization time for that piece of the model. -- 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 elm-discuss+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
[elm-discuss] Re: Communicating from parent to child and child to parent
The kind of message you describe in your example is definitely something that should be owned by the parent. It has more to do with the parent component than the child. It could definitely be moved to the child with a name change though. "Retire" or something like that. The motivation of having the OutMsg on the child in general is to allow reuse of the child components. Take a "card" component, for example: you might have multiple components with varying content, but all producing the same message. You might also be using the component in multiple places. In that case, you would have to define the OutMsg on the child anyway, since otherwise you'd have a conflict between returning ParentA.InMsg and ParentB.InMsg. There are multiple ways to structure this, but my experience tells me that the child should own all messages it consumes and produces. On Tuesday, June 28, 2016 at 5:12:23 AM UTC-5, Wouter In t Velt wrote: > > Thanks for sharing. The additional OutMsg from the update function was a > real eye-opener for me. > I have no experience (yet) in scaling this. > > One thing I find somewhat odd in your (second) example is that you define > the OutMsg type in the Child: > Wouldn't it be more logical to always define/ manage Message types in the > component that actually handles these Messages and has an update function > for this? > > In your example, the parent is the Owner of the OutMsg: the parent has > separate update function(s) for dealing with each of the OutMsg types. > To prevent circular import references (parent importing child, and child > importing parent), one would need to separate out parent and child into > separate files (as in the - not 0.17 yet - example of the Players in the > Elm docs). > > That way, any child component of parent can import the OutMsg type (maybe > ParentPublicMsg would be a more appropriate name). Then the parent exposes > this type for any child that wishes to send out such a message. When you > then expand OutMsg with, say AskForMoreAllowance, you add it to the > parent-owned type + to the parent's update function. Children can be > updated to respond to the new OutMsg type, but better still: any child > component which is not updated will continue to work. > > My specific use case: I have a list of children with a number of internal > messages (e.g. updates on each child). One of the functions I need to > implement is 'RemoveMeFromList', which is a button on each child. This > message type can only be handled by the parent, through removing child from > list and no longer rendering it in view. > -- 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 elm-discuss+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
[elm-discuss] Re: Communicating from parent to child and child to parent
Thanks for sharing. The additional OutMsg from the update function was a real eye-opener for me. I have no experience (yet) in scaling this. One thing I find somewhat odd in your (second) example is that you define the OutMsg type in the Child: Wouldn't it be more logical to always define/ manage Message types in the component that actually handles these Messages and has an update function for this? In your example, the parent is the Owner of the OutMsg: the parent has separate update function(s) for dealing with each of the OutMsg types. To prevent circular import references (parent importing child, and child importing parent), one would need to separate out parent and child into separate files (as in the - not 0.17 yet - example of the Players in the Elm docs). That way, any child component of parent can import the OutMsg type (maybe ParentPublicMsg would be a more appropriate name). Then the parent exposes this type for any child that wishes to send out such a message. When you then expand OutMsg with, say AskForMoreAllowance, you add it to the parent-owned type + to the parent's update function. Children can be updated to respond to the new OutMsg type, but better still: any child component which is not updated will continue to work. My specific use case: I have a list of children with a number of internal messages (e.g. updates on each child). One of the functions I need to implement is 'RemoveMeFromList', which is a button on each child. This message type can only be handled by the parent, through removing child from list and no longer rendering it in view. -- 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 elm-discuss+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.