Code Monkey home page Code Monkey logo

elm-architecture-tutorial's People

Contributors

callmenorm avatar chrisbolin avatar cifer-y avatar dey-dey avatar evancz avatar franklinchen avatar hiteshjasani avatar hossameldeen avatar jasalo avatar jon-f-wood avatar jvoigtlaender avatar jwmerrill avatar knuton avatar lazamar avatar lgdean avatar phenomeno avatar process-bot avatar rgscherf avatar sircharleswatson avatar svenheden avatar thomasweiser avatar vpeurala avatar zimmi48 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

elm-architecture-tutorial's Issues

Could not find package elm-lang/core

I follow the instructions:

git clone https://github.com/evancz/elm-architecture-tutorial.git
cd elm-architecture-tutorial
elm-reactor

The dev server runs and the home page loads fine. But when I go to an example, I see an error. For instance, http://localhost:8000/examples/01-button.elm shows the following:

Could not find package elm-lang/core.

Maybe your elm-stuff/ directory has been corrupted? You can usually fix stuff
like this by deleting elm-stuff/ and rebuilding your project.

I tried deleting elm-stuff and running elm-reactor again with the same result.

offline support

right now after donwloading the repo some additional stuff has to been downloaded for each example. Otherwise you will get a message like this

failed with 'FailedConnectionException2 "package.elm-lang.org" 80 False getAddrInfo: does not exist (Temporary failure in name resolution)' when sending request to
    <http://package.elm-lang.org/all-packages?elm-package-version=0.5.1&since=2015-09-11%2019%3A00%3A04.716736%20UTC>

Maybe an idea to download this all at once somehow? I wonder why each example needs to download code again actually.

Potential issue with multiple Ticks in example 8?

(First of all, I can't seem to be able to run example 8 since I've updated to 0.16, so had to disable DanDanDan/Easing).

In any case, I am looking at update function and to me it seems that there's is a potential problem with how Spin action is checked. And if state is Nothing, a Tick action is sent, but model is not updated. Is it possible that multiple Spins arrive before the first Tick?

I've tried to simulate this by sending Spin' from onClick, which in turn sends 2 Spins:

update msg model =
  case msg of
    Spin' ->
      ( model, Effects.batch [Effects.task (Task.succeed Spin), Effects.task (Task.succeed Spin)] )
    ...

Now each square turns all 180 degrees. Should not there be a special PreSpin state? Or maybe we can get current time instantaneously somehow?

`elm-package install` didn't install any package

Hi, I try to run examples follow the tutorial:

  1. cd examples/1
  2. elm-reactor

The server started listening on 8000 successfully, when i visit http://localhost:8000/Main.elm, i got this message:

your elm-package.json file says you depend on package evancz/start-app,
but it looks like it is not properly installed. Try running 'elm-package install'.

So I run elm-package install in examples/1, I got

Packages configured successfully!

It only add a directory elm-stuff/, and nothing installed in elm-stuff/packages, and refresh the page still got "Try running 'elm-package install'".

So, what's the problem? thanks

Debugger not available from example 1 onwards - missing file

Similar a bit to #34, but this command fails to render any output for me as early as example 1.

http://localhost:8000/Main.elm?debug

giving a console error of "Failed to load resource: the server responded with a status of 500 (Internal Server Error) .... http://localhost:8000/_reactor/debug.js

This command renders the counter markup...

http://localhost:8000/Main.elm

but this is probably not the experience intended for new elm explorers like me :)

Ubuntu 14.04 LTS, node (via nvm) === iojs3.3, npm install -g elm

I cannot find module 'Counter'.

Hi,
I'm running into this problem when loading "1-counter-pair.elm"


 I cannot find module 'Counter'.

Module 'Main' is trying to import it.

Potential problems could be:
  * Misspelled the module name
  * Need to add a source directory or new dependency to elm-package.json

Any idea ?

Elm Tutorial (fist project setup)

Is there anywhere official Elm tutorial?
Something more hands-on than http://guide.elm-lang.org/index.html?

What I'm looking for is something like:

  1. Install elm from here: http://elm-lang.org/install
  2. mkdir hello-world
  3. generate new project?
  4. crate file Main.elm
  5. write: http://elm-lang.org/examples/hello-html in the file
  6. run the file somehow

I was expecting something like this on: http://elm-lang.org/get-started but there is too much stuff there and the best things I've found while skimming were to clone examples and I don't want to do that.

If I've missed this kind of tutorial I would appreciate if you can point it out to me :)

One child depends on another within parent.

Suppose I have 2 components. They are implemented exactly the same. However the contents of the 2nd depends on the content of the 1st. The component consists of a <select> tag, an <input> tag, a <button>. User enters a string into <input>, presses the button, and the string appears in the <select>. What does it mean for the 2nd component to depend on the 1st?

Suppose the 1st component, on the left pane, denotes people. Suppose the 2nd component, on the right pane, denotes preferred actions per person. Suppose there are 2 people, "Wife" and "Husband". Suppose "Wife" prefers "Bach" and "Mozart", while "Husband" prefers "Stravinsky" and "Rachmaninoff".

At the beginning of program, the <select> tags are blank. I add "Wife" to the people pane, then add "Bach" and "Mozart" to the action pane. Now, here's the problem! If I add "Husband" and select it, the 2nd <select> tag should become empty, so that I can add "Stravinsky" and "Rachmaninoff". And every time I switch between "Wife" and "Husband" in the left pane, the list of option in the right pane should change, depending which person I've chosen.

These 2 components are implemented exactly the same with the exception of this dependency. So their are akin to Counters, while the parent GUI component, that contains both of them, is akin to CounterPair. But Elm Architecture Tutorial doesn't consider, if one counter somehow depends on another. For example, if pressing + on one counter would somehow influence the number on another counter, and this change would be preserved throughout the run.

So, for the example above, the actual data might be type alias Model = { players : List String, actions : Dict String (List String) }, where actions might be something like Dict.fromList [("Wife", ["Bach", "Mozart"]), ("Husband", ["Stravinsky", "Rachmaninoff"])].

But child models can only be something like type alias Model = { options : List String, selected : Maybe Int, inputField : String }. Children may not know about the full data about all players and actions, they are only given list of options from their parents somehow.

Not only children must receive data from parents, they also send data back to parents somehow. When left pane switches person from "Wife" to "Husband", parents must somehow know about this, so that it can send a list of new actions to the right pane.

This question arose in Elm Architecture: State vs Model @ elm-discuss, where you can find more ideas and discussions on the topic. The canonical solution (maybe in forms of one counter depending on another) would be a great thing to have in the Elm Architecture Tutorial, as I am not the only one, who came up with the question.

Example 5 does not show any gifs on Iceweasel (Firefox) 31.8 Linux

Description

When viewing the demo at http://evancz.github.io/elm-architecture-tutorial/examples/5.html
there are no gifs shown in Firefox. I tried clicking the button multiple times, nothing happens.

UPDATE: I tried disabling my browser add-ons, but that didn't have any effect.
UPDATE 2: I tried the project locally on my machine and it I can confirm that the view function is run and that a new URL is given each time I click the button. The problem is actually that none of the background styles are applied to the element.
UPDATE 3: PR #22 should fix this problem.

My setup

OS: Debian Jessie 64-bit
Browser: Iceweasel (Firefox) 31.8.0
Active add-ons: Adblock Edge 2.1.9, Ghostery 5.4.6, Youtube All HTML5 3.0.0

Debugging clues

The div-container for the images is empty

This container never changes, I tried clicking the button multiple times.

Empty div

No javascript errors

No javascript errors

The giphy API is loaded successfully

API loaded successfully

DOM side effects are difficult (focus, scrollTop...)

Hi,

I understand the beauty of the ELM model but in practice it seems to me complicated to perform certain tasks, like giving the focus to an input just after insertion in the DOM.

In React one would just plug that effect in componentDidMount or componentDidUpdate and it is very easy and idiomatic.

I've found that the TodoMVC ELM example gives focus to the text input on todo edit and use a port to do the side-effect:

port focus : Signal String
port focus =
    let needsFocus act =
            case act of
              EditingTask id bool -> bool
              _ -> False

        toSelector act =
            case act of
              EditingTask id _ -> "#todo-" ++ toString id
              _ -> ""
    in
        actions.signal
          |> Signal.filter needsFocus (EditingTask 0 True)
          |> Signal.map toSelector
todomvc.ports.focus.subscribe(function(selector) {
    setTimeout(function() {
        var nodes = document.querySelectorAll(selector);
        if (nodes.length === 1 && document.activeElement !== nodes[0]) {
            nodes[0].focus()
        }
    }, 50);
});

However I think this solution is much complicated compared to react, and not very good :)

The usage of a CSS selector like #todo-id to me breaks a bit the ability to nest things. Using an id-based selector means we are using a global namespace. Using class-based selector means we can't easily mount twice the same component with the same class in the page.
If ELM is really nestable, I should be able to render the same app in 2 different containers in the page and the dom effects should be targeted to the appropriate app automatically.

Also the port makes use of setTimeout. I guess it is because we have to make sure we don't run the effect before the dom node is inserted, but this random 50 value comes from nowhere and could even lead to weird effect concurrency issues on real-world applications.

Same kind of problem: give scroll position to an element, or to load an external library... These are very common needs but the port system does not seem enough for me to solve that elegantly.

So, is there a better way to perform this kind of DOM effect?
I understand that exposing the dom node after mount like React does somehow breaks the functional purity model of ELM.

Any idea?

Spanish (ES) version of the tutorial

Hi, I saw the Japanese version of the README and just translated the whole tutorial to Spanish, in case you're interested in adding it as well.

It's right now in my fork, but I can send you a PR if you prefer that way.

Great tutorial by the way, to all people involved. :)

Mentioning ports in the tutorial.

I am very new to Elm and have been stuck for some time on performing an http request. Maybe I am handling StartApp.start wrong or something, but as far as I have experienced you have to do the following in your Main.elm or where ever to actually have your effects performed:

port tasks: Signal (Task.Task Effects.Never ())
port tasks =
  app.tasks

Unfortunately this is noted nowhere in the Elm Architecture Tutorial and very difficult to guess from the Interops section at elm-lang.org. I only found it by browsing the source code for the example. It is possible that I did not read carefully enough, but a quick "hey, don't forget to set up a port for your effects to be actually performed" or something along the lines.

Thanks
Ben

bind: failed (Permission denied (WSAEACCESS))

This happens when the default port 8000 is already taken by another program. In the spirit of friendlier messages elm-reactor should say something like "Default port 8000 is already taken please try another port with 'elm-reactor -p 80801".

Start one server for all examples?

I thought i could be smart and start the server from the examples directory, so i can just browse to the individual examples. However the dependencies of program can not be found (even if stuff had been downloaded before). For example 1:

Error when searching for modules imported by module 'Main':
    Could not find module 'Counter'

Potential problems could be:
  * Misspelled the module name
  * Need to add a source directory or new dependency to elm-package.json

Also when example 2 tries to download stuff:

Downloading elm-lang/core
elm-make: elm-lang-core-5204441: rename: unsatisified constraints (Directory not empty)

Example 2: invalid assertions

Example 2 assumes and asserts that the Counter example 1 "encapsulated all implementation details" and provides an init, an update and a view function.

Example 1 doesn't provide an init function, neither in the explanatory text nor in the actual code

"Error: Unable to find a set of packages that will work with your constraints."

(Fresh install of elm-platform 0.16.0 on OSX 10.11.1 via the pkg installer.)

Trying to navigate to the url served by elm-reactor or trying to elm package install fails with this error:

danneu ~/Code/Elm/elm-architecture-tutorial/examples/1 master!
$ elm package install

Error: Unable to find a set of packages that will work with your constraints.

I'll keep digging to make sure it's not an issue with my environment.

thoughts on modularity, real re-use, app-wide coordination

Hi Elm community,

This is not an issue, just a discussion I would like to have on building modular, well-defined applications under the elm architecture. I will try to keep it brief, which will require a lot of hand-waving.

The most important pieces of any application architecture I have implemented always seem to turn out the same:

  1. modularity / re-use with good separation of concerns
  2. the ability to clearly and predictably communicate between components
  3. the ability to concisely and predictably coordinate multiple components to perform major context switches / transitions.

These three pieces enormously impact the refactor-ability of the codebase, the velocity of developers in that codebase, and the lifespan/maintainability of the entire application.

Modularity / Re-use

Ideally an entire application is built from the bottom up from small, loosely coupled, reusable components. If these components can be completely unaware of their place in an application, and only serve a small, defined purpose with a minimal api surface, you are on the right track to a highly maintainable and refactor-able code base.

Clear and predictable communication

If each component is modular, you can build up a tree hierarchy of components where communication between depths or leaves or branches happens only across a small interface at defined intersections. No matter the form of communication - be it a flux architecture, a messaging bus, or pub/sub, this "bounded" communication also keeps you on the right track to a highly maintainable and refactor-able code base.

The ability to coordinate context switches

Most apps have major contextual chunks that form concrete or logical boundaries in which to partition your components. Sometimes this is as simple as main navigation tabs, and sometimes it is more nuanced (consider following a deep link to a different part of your application). If your architecture does not offer a way to reliably and conveniently swap between these contexts, you are going to end up with a lot of fragile code that has to be hand-held through state re-hydration, serialization, branching within contexts, and all sorts of other tedious and error-prone bandaids.

Where does elm fit in?

I have been fooling around with the elm architecture for a little bit, and have tried to familiarize myself with its strengths and weaknesses. It seems relatively similar to the redux pattern (immutable, explicit top->bottom action flow, predictability) with perhaps the major difference being that truly reusable components are much simpler.

Modularity

Using Signals and forwardTo, parents provide their reusable children the information necessary to "just work" so that children can be completely unaware of the rest of the application. There are plenty of (mostly) clear examples where this can be extended to allow lists of lists of entirely dynamic reusable components (the "Model with a context" example is still pretty unclear to me).

One issue I bumped into almost immediately using this pattern is a similar but slightly more advanced use case: when a parent does not merely want to forward its child's actions, but is interested in a subset of those actions.

For example, consider a simple chat interface with a MessageBox , a Post, and a Chat component to hold everything together. What I want to be able to do is pipe InputChanged into the MessageBox without needing to know the details, but when MessageSent appears, capture some details about that action inside of the parent. A rough sketch would be something like...

type Action
    = MessageBoxAction MessageBox.Action

update : Action -> Model -> Model
update act model =
    case act of
        MessageBoxAction msg ->
            case msg of
                -- for a particular action, do something before forwarding it on to the child
                MessageBox.Action.MessageSent ->
                    let
                        updatedMessage = MessageBox.update msg model.currentMessage
                        newPost = Post.init msg model.posts
                    in
                        { model |
                            posts = model.posts :: [ newPost ]
                            , currentMessage = updatedMessage
                        }
                -- for any unspecified actions, just forward to the child
                _ ->
                    { model |
                        currentMessage = MessageBox.update nested model.currentMessage
                    }

This won't compile. I can think of a few other ways to achieve the same end, but none of them are a good idea because they either burden the reusable component with unnecessary requirements or end up with circular and difficult-to-trace "on update do another update" patterns.

I feel like if a cleaner general pattern can be reached (and it might be simple and I'm just missing it), then truly reusable components are actually possible in elm.

Communication

This is pretty inherit in elm. Everything is explicit, and the communication lines are well drawn down a component hierarchy. The biggest challenge I believe will be maintaining a small API surface across components. Sometimes the temptation is strong to update on actions that probably aren't any of your component's business. This eventually carves out an application where changing one action name, or removing a single component can break everything in that hierarchy subtree.

            root
        a           b

    c   d         e   f    g

    h   i          j   k   l

"Update H" needs to be piped from a -> c -> h. In a naive implementation, changing the action to "Update h" requires also changing a and c. I think elm avoids this through the use of a generic "On some child action just pipe the message through and update the model".

Context

I have no idea how elm might handle something like this. I believe the excellent work done over at redux-saga handles context switching in one of the most elegant ways I have seen. Because redux, like the elm architecture, is basically an event-sourced architecture, the concept of sagas "just works". When SOME_TRANSITIONING_EVENT arrives, you can utilize the api of components to predictably transition the application step by step.

The problem with sagas, though, is they are by-nature imperative and not functional. It would be great to hear some thoughts on how the elm architecture handles this case.

Do effectful components count as part of the Elm Architecture?

So, I have the use case where I have a component that does some animations. These animations involve timing.

An example of this is the material design components:
https://material.angularjs.org/#/demo/material.components.button

In material design, when you click a button, you have this ripple effect. The effect goes as follows:

  1. Start as a small circle
  2. Grow to fill the container
  3. Wait a few milliseconds
  4. Fade away

Conceptually, in Elm, you could implement this as two components: Button and Ripple.

You'd like to send the Button an action like:

ClickAt (Int, Int)

and then that Button would send an action to the Ripple like :

Animate (Int, Int) Float

where you pass in the starting position of the ripple effect and the maximum size that effect would have.

The problem, is, how to implement this animation in Elm? The problem is that a single action is expected to produce several actions that are separated by a time interval.

Solution 1: Do it in CSS

You could implement this in CSS with CSS Animations and just change a "class" in Elm. Certainly, this follows some of the best practices, but then these things are harder to share.

Pros :

  1. Straightforward to implement
  2. Putting styles in a stylesheet follows best practices

Cons :

  1. You must include a separate stylesheet whenever you want to use a component, making it harder to have components that depend on other components that depend on other components especially if at each level of the dependency there's a different author / package.
  2. CSS is a different language. With inline styles, you get to pair the awesomeness of Elm and all of its libraries and functionality with CSS. For example, you can have functions that produce new styles and variables to hold different values (no need to use a pre-processor or something).
  3. Harder to maintain. Any modification of the component requires to make modifications in two different languages and keeping everything in sync is challenging.

Solution 2: Make the component effectful

Instead of having the view function for the Button look like this

view : Address Action -> State -> Html

it would instead look like this:

view : Address (Task error ()) -> Address Action -> State -> Html

And, instead of sending one action to the Ripple, you would send multiple actions interspersed by timers.

rippleAnimation : Address Ripple.Action -> (Int, Int) -> Float -> Task error ()
rippleAnimation address startingPosition maxRadius = 
  send address (StartAt startingPosition)
    `andThen` \_ -> send address (GrowTo maxRadius)
    `andThen` \_ -> sleep 100
    `andThen` \_ -> send address FadeAway

And then, in the Button.view you'd do something like:

onButtonClick taskAddress (rippleAnimation rippleAddress)

(we can assume onButtonClick gets the necessary info from the DOM and passes it to rippleAnimation)

Pros :

  1. No need to go into CSS. Animation is fully handled in Elm. No need for extra stylesheet. This also means that you can see the results in elm-reactor as opposed to in some html file.
  2. Easier to maintain. Everything is self-contained in Elm and subject to all the guarantees Elm provides.
  3. This solution is extensible to arbitrary effects. This means you can have a component that display a map from google maps or an autocompleter that can fetch its data from the web, etc...
    You can see here for real-life examples of effectful components

Cons :

  1. Components now require opening a port for them to work. Ideally, if you manage to make sure all your tasks are of the same type, then you could jam everything into a single address and thus need to open only one port. But this also means that leaving out the port does not guarantee that a button will work properly.
  2. A component which could be effect-free is now effectful just for the sake of an animation. This means that for an animation, this component has been granted the potential capability of getting data from or sending data to the internet, etc... It does feel a bit heavy handed if your goal is to just animate something.

So, my question is, do these things still count as part of the Elm Architecture? Is having components that can send tasks a good thing?

Debugger not available from example 5 onwards - better error message

Hi,

Firstly, thank you for Elm! I'm new to it, just finding my way around. I was playing with the early examples and enjoying the time travel debugger, until I hit example 5...

On example 5, if I run it in non debug mode it works as expected, but if use http://localhost:8000/Main.elm?debug then I get the following error:

"Cannot read property 'forEach' of undefined Open the developer console for more details."

After some digging (on IRC), I understand that this is because this example has ports and the debugger does not (cannot?) support that, presumably because of purity.

This took me a while to figure out, so maybe a note in the readme or someway to indicate that in the error message might help others ...

Many thanks

p.

Creating a complex business rule (exemple based on counters)

Hi,

I really like the ELM architecture that permits to bubble up the state and redispatch it to the tree in the update function.

Comparing it to React, this approach seems to permit to easily replace setState of React components (local state) and put that state in a global model / atom.

However now imagine my app's domain is counters.
It is composed of:

  • A pair of counters
  • A list of counters

The business rule

Now I'd like to create a new component that will display a value based on the following rule:

  • The value should increment by one on any counter increment
  • The value should decrement by one on any counter decrement
  • The value should never be more than 3 and less than 0 (if we increment with value 3, the value stays 3)

Now imagine the pair has actions:

type Action
    = Reset
    | Top Counter.Action
    | Bottom Counter.Action

And the list has actions

type Action
    = Insert
    | Remove
    | Modify ID Counter.Action

A sequence of actions like:

  • Top Increment
  • Top Increment
  • Modify 1 Increment
  • Bottom Increment
  • Bottom Increment
  • Modify 2 Decrement

The value for this sequence of action should be 2.

This business rule I want to implement might seem weird in this case but in the real world we often have to implement such rules...

The problem

How to create a model that receive these actions and then permit ti diplay that value?

The problem I see is that as the counter incrementations are "embedded" into parent actions, then we somehow need to pattern-match on the parent actions like Top / Bottom / Modify, before being able to see if the counter action is an increment.

It feels wrong to me, because tomorow if I need to add a new TupleX of counter, or Pyramid of counters or whatever with a strange shape, I don't want to have to manage additional pattern matching to compute the value I want.

If a simple "business event" (because counters is my business) increment was fired, then it would be much easier to listen to all these counter actions from any place of my app.

The idea would also be that to add my new view displaying the value I want, I should not need in any way to modify existing code normally. This is also the idea behind ideas like CQRS where you can spawn a new query view / index from an existing event log without having to rework at all the way events are emitted (because you can't erase the past anyway...)

Example needed

So here all the examples of this repository explains well how to handle local state.
However I do not see any example on how to implement real world business rules.

To compare with React I understand how to replace setState with ELM, but I don't understand (by reading this tutorial) how to replace Flux.

I think that to solve my problem described above, I should not need to have a global understanding of the app inner workins. I should be able to see there is some kind of a global/business actions union-type with Increment and Decrement, and then just decide to listen from them, without having to know if these actions are fired from a pair or list of counters because my business rule simply don't care about that.

I'm pretty sure it is largely possible to do that in ELM and an example would be welcome from an experienced ELM user :)

I'm thinking of something like this:

view : Signal.Address Action -> Signal.Address BusinessAction -> Model -> Html

Can I make the counter view fire 2 actions in 2 distinct adresses like that? So that my counter click is fired both for local state update and also global / business listening from other components?

Thanks

Counters example

Hi,

There used to be a set of counters examples in this repo, which were similar to that in the modularity section of the elm guide but they've disappeared. Are they going to be added soon?

One last reference to channels

The diagram signal-graph-summary.png is still making reference to channels: "Actions are sent back to our Elm program along channels."

This is just a state machine!

@evancz I just realized, this is just the "state machine" pattern! That's why it was so familiar, why I like it so much, why it's so easy to grasp! We provide a model representing the sum of every possible state, a list of acceptable actions that our state machine can accept, a transition function that creates a new model based on an action, and a function to transform the model into something the user can see and interact with! If this is a reasonable interpretation, why not describe it this way somewhere on Elm's main home-page? Or at least in this tutorial? (I don't understand why this elm-architecture-tutorial document isn't part of the official Elm documentation.)

Container Components

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.

Cannot find variable 'Html.program'

Brand new to elm, and I just copied the dice example, and it says Cannot find variable Html.program...is this package just outdated or something?

making deeply nested update effectful requires cascading refactoring

Example 5 introduces a new signature for update which works just fine on the new code base. But when in the existing code base you introduce say animation to a view you cause cascading demand to refactor all the code that used that update. In a way it reminds me of the issues in JS when one of your functions get turns into async causing you to refactor whole application.

I wonder if there could be a different pattern that would not suffer from the same cascading refactoring issue. One option maybe to force all update functions into Action -> Model -> (Model, Effects Action) signature but that does not seem ideal either.

I wonder if some alternatives have being considered or dismissed for any given reasons.

No mention of foldp?

I just noticed that the tutorial has been updated and there is no mention of foldp at all. I don't think a beginner can understand how things are being achieved without it. The startApp makes it tantamount to magic.

use indexedMap

instead of redundantly saving the index of an element, just use indexedMap, it simplifies the code by removing some deconstruction.
of cause this would remove the uniqueness of the keys.

multiple arguments in type annotations never explained

I couldn't find anywhere the explanation of how multiple arguments are separated by -> followed by the return, eg:

diamond: Color -> Float -> Form

It's not explained here:
http://elm-lang.org/guide/model-the-problem#contracts

I didn't figure it out until I got to the "Type Annotations" section of this 3rd party article:
https://pragmaticstudio.com/blog/2014/12/19/getting-started-with-elm

My experience was that I was trying to imagine various things that could be going on, and the best I came up with was that type annotations were describing functions that take a single argument which is a function that itself returns a function and so on lol. I thought it was recursively describing the types of passed in functions (and their parameters + returns).

I put a lot of mental work into trying to figure out what--my recommendation is--should be described in the "Model the Problem" article and re-iterated in this tutorial.

..my 2 cents

Example 4 uses unfamiliar syntax to create Counter.Context

In example 4, the CounterList creates a Counter.Context record using the syntax:

let context =
      Counter.Context
        (Signal.forwardTo address (Modify id))
        (Signal.forwardTo address (always (Remove id)))

As someone who is new to elm this syntax left me somewhat confused. Counter.Context is a type alias and it was not obvious to me that a type alias could be used to construct a record of that type. I have since confirmed that this is the case, but was unable to find documentation about this.

The example would have been slightly simpler for me to follow if it had avoided or explained this new syntax. It seems easy to avoid by changing the example to:

let context =
      {
        actions = (Signal.forwardTo address (Modify id))
        remove = (Signal.forwardTo address (always (Remove id)))
      }

comprehensive summary at the end

I followed most of this, but got kind of lost towards the end. Theres a lot of syntax sugar I'm unfamiliar with. I like how you built up to this point with a bunch of examples, but it would be cool if you ended with some highly-annotated code that explains everything inline, so I can really understand some of the syntax and the new types.

waiting.gif missing

In 05-http.elm getting this:

Failed to load resource: the server responded with a status of 404 (Not Found), http://localhost:8000/examples/waiting.gif

Didn't want to send a PR with a randomly picked up gif from the net, should I?

Error in tutorial text code example

I'm not sure if this is the right place to leave this, if the actual tutorial text was hosted I'd comment there, but the tutorial text has either a misleading or incorrect code example from 05-Http:

decodeGifUrl : Json.Decoder String
decodeGifUrl =
  Json.at ["data", "image_url"] Json.string

In order to match the accompanying code in this repo and in the online example:
Json.Decoder should be Decode.Decoder
Json.at should be Decode.at
Json.string should be Decode.String

CORS error in HTTP example.

Seems related to the change in 30ce490

I've copied the example directly from the repo here and get an error:

XMLHttpRequest cannot load https://api.giphy.com/v1/gifs/random?api_key=dc6zaTOxFJmzC&tag=cats. The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed. Origin 'http://localhost:8000' is therefore not allowed access.

Is there anything that can be done to correct the tutorial? My very brief investigation indicated this was likely a misconfiguration on gliphy's side, so maybe a different example is needed.

Missing package install step?

Hi,
I am getting started with Elm and when trying to run the examples in this repo through the following commands:

git clone https://github.com/evancz/elm-architecture-tutorial.git
cd elm-architecture-tutorial
elm-reactor

I am getting a runElmProgram is not defined error when I navigate to the examples e.g. http://localhost:8000/examples/1-button.elm
I fixed this by running elm-package install to install the dependencies.
Is this something that should be in the instructions or was I missing something all along?

Would sum types work with your "One Last Pattern" section?

In your "One Last Pattern" you seem to suggest changing the update function's signature to allow specific use-cases to return more context than just an updated model. But for many different actions, this can get out of hand quickly. Would using sum types be appropriate here instead?

"Upper case characters are not allowed in package names."

Fresh install of elm-platform 0.16.0 on OSX 10.11.1 via the pkg installer.

Cloned this repo, tried to run it, and it complains about the "repository" value in elm-package.json being upper case:

"repository": "https://github.com/USER/PROJECT.git",

Downcasing it satisfied the error, and I assume arose from a recent change in elm-package, but obviously it should be updated so that a fresh git clone is runnable.

how to properly shutdown elm-reactor?

I try cltr + z to shut down elm-reactor, the prompt then becomes available again. But the process is still running and i have to go into htop to send SIGKILL (normal end does not work) before i can restart the server

?debug parameter won't work

First example can be viewed on http://localhost:8000/Counter.elm for me, but navigating to http://localhost:8000/Counter.elm?debug will return this to me

Failed to load resource: the server responded with a status of 500 (Internal Server Error)
Uncaught TypeError: Elm.fullscreenDebug is not a function

Do I need to install something else? I'm running this with Elm Reactor 0.3.1 (Elm Platform 0.15).

I'm opening this issue because README.md of this repository is linking to http://localhost:8000/Counter.elm?debug.

elm-reactor gives 404

I am learning elm and so I've started with the first example.

I am using elm-reactor (v 0.16.0) so I can try to change something and see the result. I am starting elm-reactor from elm-architecture-tutorial/examples/1 but each time I am getting

{
  "statusCode": 404,
  "error": "Not Found"
}

I am not really sure what I am doing wrong; if I run elm-make I correctly get index.html though.

Do you have any suggestions / hints?

Why not "See code" instead of "Run locally"?

As a reader of the README,
I felt the link "Run locally" isn't named as it actually is:
When I was reading the README for the first time on my tablet,
I guessed it was to some URL like localhost:8000/***, which would never work on a tablet.
So I always used links in examples, then wondered
๐Ÿ˜• "Why dosen't it have links to view the source directly?"

So, I suggest to change the link text of "Run locally" into "See code".
This sounds more naturally and show what actually it is.
Tell me your opinion.
If you approve, I'm going to fix.

Context signal address with effects

Hi,
reading the tutorial I have some doubts regarding the use of a Context to propagate a signal to a parent component (as in example 4) where the component use Effects API.

I'm thinking to a component-form with Actions like Save | Error | Saved, that can be created dynamically and deleted only after a success save.

What is the right way to go? create a customized update to send the remove action to the parent component?

Mixed content error on example 5, 6 and 7

When the demos are loaded through a https connection, as it is the case of the links from the README.md of each individual demo, a Mixed Content error is triggered by the fact that the images are fetched through a http connection.

This error is reported only in the Console and the examples appear to not work.

Are there any issues/limitations of using https for the giphy API?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.