Notice: This lesson uses Elm 0.17!
This lesson gives a rapid-paced introduction to what's known as the Elm Application Architecture. You can read about it in greater detail here:
We'll build a counter that utilizes the standard Elm combination of a model, a view, and update function.
See the linked code for a good starting place.
I'm going to start out this project by typing NPM Start. This run some NPM scripts that run the Elm compiler for me, and will reload the browser when I make changes. For example, if I type "Hello, pal," you should get an update in the browser right away. Let's start making an app. A great place to start is with the model. Let's make a type alias called type alias model. The app we're making right now is a little counter, so the model is just going to be an integer.
Type alias model means we're making a new type that we can use in the app, but it's just an alias to the integer type. Now let's define some messages. Messages are the actions that can be taken in our app, or things that can be done to change the state of the app. We define messages by making a new tagged union type, we can do that by typing type message, give it a name. For the sake of readability, I'm going to put the equal on the next line, and you'll see why in just a moment.
The two messages we're going to have in this app are increment and decrement the counter. You see that these two different tags are joined with a bar character. This means that if I pass around these values, increment or decrement in my app, any of them can be used wherever I expect a type message. Now let's go to the update function. In Elm applications the update function takes in a message, and a model, and returns another model. This is what a type annotation looks like for functions.
We have the function name, then a colon, then the first argument of the function, then an arrow, then the second argument of the function, then an arrow, and then the return value from the function. Then right beneath it, we can implement the function by typing the function name and then the name of the parameters, so message in this case, and model, and then an equals sign. Everything that comes after the equal sign will be the body of the function.
We're going to take in a message and a model, and as the body of the function we're going to switch on the type of message that's coming in by typing case message up. In the case of an increment message, we're going to return the current model plus one. In the case of a decrement message, we're going to return the current model minus one. Now for the view function. The view function takes in a model and returns an HTML of type message. HTML is a third-party library that we've imported already up at the top.
You can see that it's installed by opening up the Elm-package.JSON, and looking at the dependencies, Elm-lang HTML is right there. The implementation of the view looks like this. We're going to call the function div as defined by the HTML library, pass in a list of attributes which we have none right now, and we're going to pass in a list of children.
We'll make the children by calling other functions from the HTML library, like for example H1, pass in no attributes, pass in the function text that converts a string into something that can be used by HTML, we'll pass in a string, "Hi there," save the file, and you'll notice that it didn't update. That's because up at the top I've got this main function, whatever I give to main gets rendered to the screen, and right now I'm rendering straight HTML.
Now let's save and see what we've got going on. Great, our H1 rendered. Now you start fleshing out our view function. Inside of a div, right below the H1, let's put the value of our counter. We can use that by using the text function as mentioned earlier, and then the toString function. This is a special function that's available anywhere inside Elm, that tries to turn any value into a string. We'll call toString and pass in our model. Let's change the text of our H1 to be "counter."
Save the file, and looks like we've got a title and a counter value. Now we need a couple of buttons for changing the value of the counter. I'll make one by calling the button function. Increment, and let's make another one called Decrement. There are our buttons, but currently they don't do anything. That's because we haven't wired any of our buttons to trigger these messages yet.
We can do that by importing Html.Events exposing(onClick). onClick is a function that will take a message and fire off that message to our update function in response to a click event. We can put that inside of the attributes list for our button function, onClick.increment, and onClick.decrement. Save the file, looks like it's working. Just to recap, we've got main function that calls HTML.app.beginnerprogram.
We've got a model which is just an integer in this case, we've got a couple of messages that describes the interaction the user can take with the model. We've got the update function that describes the changes to the model in response to the messages that are fired, and we've got a view function which allows the user to interact with the model through events.