Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Container Components #12

Closed
TheSeamau5 opened this issue Jun 10, 2015 · 6 comments
Closed

Container Components #12

TheSeamau5 opened this issue Jun 10, 2015 · 6 comments

Comments

@TheSeamau5
Copy link

In this gist, I've implemented a swipeable pages component. The idea of this is that you have a list of pages that can be cycled by dragging a mouse or swiping on the touch screen.

The thing about this component is that it is not about the container itself but about how to render the children.

Concretely, my implementation goes as follows:

type alias Container a = 
  { pages : List a 
  , ...
  }

type Action = ...

update : Action -> Container a -> Container a 

view : (a -> Html) -> Address Action -> Container a -> Html 

The main idea is to have you container type parametrized on the type of the children (which could end up being a union type if you want different components of different types to inter-mingle). Then, in the view, you pass an additional function of type a -> Html that can display a single child. This allows the view to be completely generic and not have to worry about weird synchronization problems (you guarantee that if you have 5 elements in the model that your code will apply to all 5 models with a good use of List.map or List.indexedMap).

I believe this to be general for most use cases of container components.

If this is the case, this would be a fine addition to the elm-architecture-tutorial because everyone wants to know "how do I make tabs?", "how do I make carousels?", "how do I make grids?", etc... And this could help answer all those questions.

@TheSeamau5
Copy link
Author

A different approach worth considering is that of having a layout step.

Consider the case of a container who can lay out its children. (i.e. the positions and dimensions of the children are dictated by the container).

If the positions and dimensions of the children are included in its state, this could be problematic because you can easily go out of sync as these values depend on the position and dimensions of the parent and all of these values reside in the same object.

One solution would involve the following extensible type

type alias Layout a = 
  { a | position : Vector 
      , size : Vector 
  }

-- type alias Vector = { x : Float , y : Float }

Now consider this example child component :

type alias State = { color : Color }

type Action = ...

update : Action -> State -> State

view : Address Action -> Layout State -> Html

and this example parent component :

type alias State = 
  { children : List Child.State -- the above component state
  , ...
  }

type Action = Child Int Child.Action | NoOp

update : Action -> State -> State 

layoutChild : Layout State -> Int ->  Child.State -> Layout Child.State 
-- to be used in conjunction with List.indexedMap

view : Address Action -> Layout State -> Html

Where the layoutChild function would be applied somewhere in the view function and would be responsible for determining the position and/or dimensions of the child.

I have yet to determine the limitations of this approach but here's an example gist demonstrating the approach : https://gist.github.com/TheSeamau5/002593199af89552a1bd

@amitaibu
Copy link

amitaibu commented Sep 6, 2015

For what its worth, I would love to see the docs about best practices to structure parent - children relations.

@sindikat
Copy link

This is a fantastic idea! So, the container itself is generic, but the components may be dropped in. So it can be a container of three selection lists, or a container of three buttons, or a container of three very complex forms. 👍 for including into Elm Architecture Tutorial.

@rgrempel
Copy link

The holy grail would be "a generic container for a selection list, a button and a complex form" ... which either requires one or another kind of extension to the type system, or requires some way of converging the types (for the container) so that what the container sees is three things that have the same type.

For the latter, what may work is some kind of intermediate type that can be constructed from the various child types. The trivial implementation is a union type, but it could be more complex than that.

@thSoft
Copy link

thSoft commented Sep 17, 2015

The basic ideas are outlined here: https://groups.google.com/d/msg/elm-discuss/xrmWjVobMcA/M0t8Xz3pCAAJ
@evancz I think these use cases (master-detail) are so common and the solution (maintaining state in the parent and passing it as props to the child) is so fundamental that it would be great to have another example discussing it.

@evancz
Copy link
Owner

evancz commented Sep 4, 2016

Here's the beginning of advice on this kind of stuff: http://guide.elm-lang.org/reuse/

We will have more resources coming in the next few months, but that is the gist. If you are thinking about components, if you are thinking about parents and children and communication, something has already gone wrong.

Also, this community uses forums like elm-discuss and the Elm slack for discussions like this. Issues are for tracking concrete problems and work, not for discussions.

@evancz evancz closed this as completed Sep 4, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants