{"id":15059425,"url":"https://github.com/dwyl/learn-elm-architecture-in-javascript","last_synced_at":"2025-08-21T20:32:14.970Z","repository":{"id":66054439,"uuid":"90406606","full_name":"dwyl/learn-elm-architecture-in-javascript","owner":"dwyl","description":":unicorn: Learn how to build web apps using the Elm Architecture in \"vanilla\" JavaScript (step-by-step TDD tutorial)!","archived":false,"fork":false,"pushed_at":"2019-03-29T09:20:26.000Z","size":394,"stargazers_count":213,"open_issues_count":14,"forks_count":19,"subscribers_count":16,"default_branch":"master","last_synced_at":"2024-12-07T19:11:42.298Z","etag":null,"topics":["beginner-friendly","elm","elm-architecture","es5-javascript","howto","javascript","tests","tutorial"],"latest_commit_sha":null,"homepage":"https://todomvc-app.herokuapp.com","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dwyl.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-05-05T18:43:32.000Z","updated_at":"2024-11-21T03:53:27.000Z","dependencies_parsed_at":"2023-03-17T15:01:03.892Z","dependency_job_id":null,"html_url":"https://github.com/dwyl/learn-elm-architecture-in-javascript","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dwyl%2Flearn-elm-architecture-in-javascript","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dwyl%2Flearn-elm-architecture-in-javascript/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dwyl%2Flearn-elm-architecture-in-javascript/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dwyl%2Flearn-elm-architecture-in-javascript/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dwyl","download_url":"https://codeload.github.com/dwyl/learn-elm-architecture-in-javascript/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230532443,"owners_count":18240792,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["beginner-friendly","elm","elm-architecture","es5-javascript","howto","javascript","tests","tutorial"],"created_at":"2024-09-24T22:43:37.421Z","updated_at":"2024-12-20T04:07:26.060Z","avatar_url":"https://github.com/dwyl.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Learn Elm Architecture in _Plain_ JavaScript\n\nLearn how to build web applications using\nthe Elm (\"Model Update View\") Architecture in \"_plain_\" JavaScript.\n\n[![Build Status](https://travis-ci.org/dwyl/learn-elm-architecture-in-javascript.svg?branch=master)](https://travis-ci.org/dwyl/learn-elm-architecture-in-javascript)\n[![test coverage](https://codecov.io/gh/dwyl/learn-elm-architecture-in-javascript/branch/master/graph/badge.svg)](https://codecov.io/gh/dwyl/learn-elm-architecture-in-javascript)\n[![dependencies Status](https://david-dm.org/dwyl/learn-elm-architecture-in-javascript/status.svg)](https://david-dm.org/dwyl/learn-elm-architecture-in-javascript)\n[![devDependencies Status](https://david-dm.org/dwyl/learn-elm-architecture-in-javascript/dev-status.svg)](https://david-dm.org/dwyl/learn-elm-architecture-in-javascript?type=dev)\n[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/dwyl/learn-elm-architecture-in-javascript/issues)\n[![HitCount](http://hits.dwyl.io/dwyl/learn-elm-architecture-in-javascript.svg)](http://hits.dwyl.io/dwyl/learn-elm-architecture-in-javascript)\n\n\n\u003e We think Elm is the _future_ of Front End Web Development \u003cbr /\u003e\nfor all the _reasons_ described in:\n[github.com/dwyl/**learn-elm#why**](https://github.com/dwyl/learn-elm#why) \u003cbr /\u003e\n_However_ we _acknowledge_ that Elm is \"_**not everyone's taste**_\"! \u003cbr /\u003e\n\n\u003e What [_many_](https://youtu.be/VNGFep6rncY)\nFront-End Developers _are_ learning/using is\n[React.js](https://github.com/dwyl/learn-react). \u003cbr /\u003e\n_Most_ new _React.js_ apps are built using\n[Redux](https://github.com/dwyl/learn-redux) which \"_takes cues from_\" \u003cbr /\u003e\n(_takes **all** it's **best ideas/features** from_) Elm: \u003cbr /\u003e\n![redux-borrows-elm](https://cloud.githubusercontent.com/assets/194400/25845941/c7a9ce78-34a7-11e7-91fb-a65f99ce0046.png)\n\n\u003e Therefore, by learning the Elm Architecture,\nyou will **_intrinsically_ understand Redux** \u003cbr /\u003e\nwhich will help you learn/develop\n[React](https://github.com/dwyl/learn-react/issues/18)\napps.\u003cbr /\u003e\n\n\u003e This ***step-by-step tutorial*** is a _gentle_ introduction to\nthe Elm Architecture, \u003cbr /\u003e\nfor people who write JavaScript and want\na _**functional**, **elegant** and **fast**_ \u003cbr /\u003e\nway of organizing their JavaScript code _without_\nhaving the learning curve \u003cbr /\u003e\nof a completely new (_functional_) programming language!\n\n\n## _Why?_\n\n![simple-life](https://cloud.githubusercontent.com/assets/194400/25773897/ea0c11fa-327d-11e7-86e0-7d8721c2d7ea.png)\n\n_Organizing_ `code` in a Web (_or Mobile_) Application\nis _really easy_ to ***over-complicate***, \u003cbr /\u003e\n_especially_ when you are just starting out and there\nare _dozens_ of competing ideas\nall _claiming_ to be the \"***right way***\"...\n\nWhen we encounter this type of \"_what is the **right way**_?\"\nquestion, \u003cbr /\u003e\nwe always follow\n[***Occam's Razor***](https://en.wikipedia.org/wiki/Occam%27s_razor)\nand _ask_:\nwhat is the ***simplest way***? \u003cbr /\u003e\nIn the case of web application organization,\nthe ***answer*** is:\nthe \"**Elm _Architecture_**\".\n\n\nWhen compared to _other_ ways of organizing your code,\n\"Model Update View\" (MUV) has the following benefits:\n+ Easier to _understand_ what is going on in more advanced apps because there is no complex logic,\nonly one basic principal\nand the \"_flow_\" is _always_ the same.\n+ ***Uni-directional data flow*** means the \"state\"\nof the app is always _predictable_;\ngiven a specific starting \"state\" and sequence of update actions,\nthe output/end state will _always_ be the same. This makes testing/testability\nvery easy!\n+ There's **no** \"***middle man***\" to complicate things\n(_the way there is in other application architectures\n  such as\n[Model-view-Presenter](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93presenter) or \"Model-View-ViewModel\" (MVVM) which is \"overkill\" for most apps_).\n\n\u003e _**Note**: **don't panic** if any of the terms above are strange\nor even confusing to you right now.\n\u003e Our **quest** is to put all the concepts into **context**.\n\u003e And if you get \"**stuck**\" at any point, we are here to help!\n\u003e Simply **open a question** on GitHub:_\n[github.com/dwyl/**learn-elm-architecture**-in-javascript/**issues**](https://github.com/dwyl/learn-elm-architecture-in-javascript/issues)\n\n\n## _Who? (Should I Read/Learn This...?)_\n\n[![everybodys-gotta-learn-sometime](https://cloud.githubusercontent.com/assets/194400/25806590/a1619644-33fb-11e7-8b84-1a21be188fb7.png)](https://www.youtube.com/results?q=The+Korgis+-+Everybody%27s+Gotta+Learn+Sometime)\n\nAnyone who knows a _little_ bit of JavaScript\nand wants to learn how to organize/structure \u003cbr /\u003e\ntheir code/app in a _sane_, predictable and testable way.\n\n### _Prerequisites_?\n\n[![all-you-need-is-less](https://cloud.githubusercontent.com/assets/194400/25772135/a4230490-325b-11e7-9f12-da19fa4eb5e9.png)](https://www.ted.com/talks/graham_hill_less_stuff_more_happiness)\n\n+ **_Basic_ JavaScript Knowledge**.\nsee: [github.com/dwyl/**Javascript**-the-**Good-Parts**-notes](https://github.com/iteles/Javascript-the-Good-Parts-notes)\n+ _Basic_ Understanding of **TDD**. If you are _completely_ new to TDD,\nplease see: [github.com/dwyl/**learn-tdd**](https://github.com/dwyl/learn-tdd)\n+ A computer with a Web Browser.\n+ **30 minutes**.\n\n\u003e No other knowledge is assumed or implied.\nIf you have **_any_ questions**, ***please ask***: \u003cbr /\u003e\n[github.com/dwyl/**learn-elm-architecture**-in-javascript/**issues**](https://github.com/dwyl/learn-elm-architecture-in-javascript/issues)\n\n\n## _What?_\n\n[![image](https://cloud.githubusercontent.com/assets/194400/25772120/3fa2492c-325b-11e7-9aee-90b059360c14.png)](https://youtu.be/yYCmhHFhopA?t=4s)\n\n### A _Complete Beginner's_ Guide to \"MUV\"\n\nStart with a few definitions:\n\n+ **Model** - or \"data model\" is the place where all data is stored;\noften referred to as the application's `state`.\n+ **Update** - how the app handles `actions` performed\nby people and `update`s the `state`,\nusually organised as a `switch` with various `case` statements corresponding\nto the different \"_actions_\" the user can take in your App.\n+ **View** - what people using the app can _see_;\na way to `view` the Model (in the case of the first tutorial below,\nthe counter) as `HTML` rendered in a web browser.\n\n![elm-muv-architecture-diagram](https://cloud.githubusercontent.com/assets/194400/25773775/b6a4b850-327b-11e7-9857-79b6972b49c3.png)\n\n\u003cbr /\u003e\nIf you're not into flow diagrams,\nhere is a much more \"user friendly\" explanation\nof The Elm Architecture (\"TEA\"): \u003cbr /\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n![elm-architecture-puppet-show](https://user-images.githubusercontent.com/194400/41206474-62d1a6a4-6cfc-11e8-8029-e27b7aa7f069.jpg)\n\n\u003cbr /\u003e\n\n[**Kolja Wilcke**'s](https://twitter.com/01k/status/986528602635358208?s=20)\n[\"View Theater\" diagram](https://github.com/w0rm/creating-a-fun-game-with-elm/blob/001baf05b3879d12c0ff70075e9d25e8cc7c4656/assets/the-elm-architecture1.jpg)\nCreative Commons License\n[Attribution 4.0 International (CC BY 4.0)](https://twitter.com/01k/status/986528602635358208?s=20)\n\n\u003cbr /\u003e\n\n\u003c/div\u003e\n\nIn the \"View Theatre\" diagram, the:\n+ **`model`** is the ensamble of characters (_or \"**puppets**\"_)\n+ **`update`** is the function that transforms (_\"changes\"_) the `model`\n(_the \"**puppeteer**\"_).\n+ **`view`** what the audience sees through \"view port\" (_stage_).\n\n\n\u003e If this diagram is not clear (_yet_), again, don't panic,\nit will all be clarified when you start seeing it in _action_ (_below_)!\n\n\n## _How?_\n\n### 1. Clone this Repository\n\n```sh\ngit clone https://github.com/dwyl/learn-elm-architecture-in-javascript.git \u0026\u0026 cd learn-elm-architecture-in-javascript\n```\n\n### 2. Open Example `.html` file in Web Browser\n\n\u003e **Tip**: if you have **node.js** installed, simply run **`npm install`**!\n\u003e That will install **`live-server`** which will _automatically_ refresh\nyour browser window when you make changes to the code!\n(_makes developing faster!_)\n\nWhen you open `examples/counter-basic/index.html` you should see:\n\n![elm-architecture-counter](https://cloud.githubusercontent.com/assets/194400/25780607/d2251eac-3321-11e7-8e65-9abbfa204fb3.gif)\n\nTry clicking on the buttons to increase/decrease the counter.\n\n### 3. Edit Some Code\n\nIn your Text Editor of choice,\nedit the _initial value_ of the model\n(_e.g: change the initial value from 0 to 9_).\nDon't forget to save the file!\n\n![elm-architecture-code-update](https://user-images.githubusercontent.com/4185328/46260332-6f107980-c4dc-11e8-98c8-e1775453dfac.gif)\n\n### 4. Refresh the Web Browser\n\nWhen you refresh the your Web Browser you will see\nthat the \"_initial state_\" is now **9**\n(or whichever number you changed the initial value to):\n\n![update-initial-model-to-9](https://cloud.githubusercontent.com/assets/194400/25780667/c84d0bf4-3323-11e7-929d-2019f5face2c.png)\n\nYou have just seen how easy it is to set the \"_initial state_\"\nin an App built with the Elm Architecture. \u003cbr /\u003e\n\n\n### 5. Read Through \u0026 Break Down the Code in the Example\n\nYou _may_ have taken the time to read the code in Step 3 (_above_) ... \u003cbr /\u003e\nIf you did, _well done_ for challenging yourself\nand getting a \"_head start_\" on reading/learning! \u003cbr /\u003e\nReading (_other people's_) code is the _fastest_ way\nto learn programming skills and\nthe _only_ way to learn useful \"_patterns_\". \u003cbr /\u003e\nIf you didn't read through the code in Step 3, that's ok!\nLet's walk through the functions _now_!\n\n\u003e As always, our _hope_ is that the functions\nare clearly named and well-commented, \u003cbr /\u003e\nplease inform us if anything is unclear please\nask any questions as **issues**: \u003cbr /\u003e\n[github.com/dwyl/**learn-elm-architecture**-in-javascript/**issues**](https://github.com/dwyl/learn-elm-architecture-in-javascript/issues)\n\n\n### 5.1 `mount` Function Walkthrough\n\nThe mount function \"initializes\" the app and tells the _view_\nhow to process a `signal` sent by the user/client.\n\n```js\nfunction mount(model, update, view, root_element_id) {\n  var root = document.getElementById(root_element_id); // root DOM element\n  function signal(action) {          // signal function takes action\n    return function callback() {     // and returns callback\n      model = update(model, action); // update model according to action\n      view(signal, model, root);     // subsequent re-rendering\n    };\n  };\n  view(signal, model, root);         // render initial model (once)\n}\n```\n\nThe `mount` function receives the following _four_ arguments:\n+ `model`: \"_initial state_\" of your application\n(_in this case the counter which starts at 0_)\n+ `update`: the function that gets executed when ever a \"_signal_\"\nis received from the client (_person using the app_).\n+ `view`: the function that renders the DOM (_see: section 5.3 below_)\n+ `root_element_id` is the `id` of the \"root DOM element\"; this is the DOM element \u003cbr /\u003e\nwhere your app will be \"_mounted to_\". In other words your app\nwill be _contained_ within this root element. \u003cbr /\u003e\n(_so make sure it is empty before `mount`ing_)\n\nThe first line in `mount` is to get a _reference_ to the root DOM element; \u003cbr /\u003e\nwe do this _once_ in the entire application to _minimize_ DOM lookups.\n\n#### `mount` \u003e `signal` \u003e `callback` ?\n\nThe _interesting_ part of the `mount` function is `signal` (_inner function_)! \u003cbr /\u003e\nAt first this function may seem a little strange ... \u003cbr /\u003e\n_Why_ are we defining a function that returns another function? \u003cbr /\u003e\nIf this your first time seeing this \"_pattern_\",\nwelcome to the wonderful world of \"_closures_\"!\n\n#### _What_ is a \"Closure\" and _Why/How_ is it Useful?\n\nA `closure` is an inner function that has access\nto the outer (enclosing) function's variables—scope chain.\nThe closure has three scope chains: it has access to its own scope\n(variables defined between its curly brackets), it has access to\nthe outer function's variables, and it has access to the global variables.\n\nIn the case of the `callback` function inside `signal`,\nthe `signal` is \"passed\" to the various bits of UI\nand the `callback` gets executed when the UI gets interacted with.\nIf we did not have the `callback` the `signal`\nwould be executed _immediately_ when the `button` is _defined_. \u003cbr /\u003e\nWhereas we only want the `signal` (`callback`) to be triggered\nwhen the button is _clicked_. \u003cbr /\u003e\nTry removing the `callback` to see the effect:\n\n![range-error-stack-exceeded](https://cloud.githubusercontent.com/assets/194400/25838395/bcb3296e-348a-11e7-8a8b-10114016cdfb.png)\n\nThe `signal` is triggered when button is _created_, which _re-renders_\nthe `view` creating the button again. And, since the `view` renders _two_\nbuttons each time it creates a \"_chain reaction_\" which almost\ninstantly _exceeds_ the \"***call stack***\"\n(_i.e. exhausts the allocated memory_) of the browser!\n\nPutting the `callback` in a _closure_ means we can pass a _reference_\nto the `signal` (_parent/outer_) function to the `view` function.\n\n##### Further Reading on Closures\n\n+ https://developer.mozilla.org/en/docs/Web/JavaScript/Closures\n+ http://javascriptissexy.com/understand-javascript-closures-with-ease/\n+ ... if closures aren't \"clicking\",\nor you want _more_ detail/examples,\n[***please ask***!](https://github.com/dwyl/learn-elm-architecture-in-javascript/issues)\n\n\n#### 5.1.1 `mount` \u003e render initial view\n\nThe last line in the `mount` function is to _render_ the `view` function\nfor the first time, passing in the `signal` function, initial model (\"state\")\nand root element. This is the _initial_ rendering of the UI.\n\n\n### 5.2 Define the \"_Actions_\" in your App\n\nThe next step in the Elm Architecture is to _define_ the Actions\nthat can be taken in your application. In the case of our _counter_\nexample we only have _two_ (_for now_):\n\n```js\n// Define the Component's Actions:\nvar Inc = 'inc';                     // increment the counter\nvar Dec = 'dec';                     // decrement the counter\n```\nThese _Actions_ are used in the `switch` (_i.e. decide what to do_)\ninside the `update` function.\n\nActions are always defined as a `String`. \u003cbr \u003e\nThe Action _variable_ gets passed around inside the JS code \u003cbr /\u003e\nbut the `String` representation is what appears in the DOM \u003cbr /\u003e\nand then gets passed in `signal` from the UI back to the `update` function.\n\nOne of the biggest (_side_) benefits of defining actions like this\nis that it's really quick to see what the application _does_\nby _reading_ the list of actions!\n\n### 5.3 Define the `update` Function\n\nThe `update` function is a simple\n[`switch`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/switch)\nstatement that evaluates the `action` and \"dispatches\"\nto the required function for processing.\n\nIn the case of our simple counter we aren't defining functions for each `case`:\n```js\nfunction update(model, action) {     // Update function takes the current model\n  switch(action) {                   // and an action (String) runs a switch\n    case Inc: return model + 1;      // add 1 to the model\n    case Dec: return model - 1;      // subtract 1 from model\n    default: return model;           // if no action, return current model.\n  }                                  // (default action always returns current)\n}\n```\nHowever if the \"_handlers_\" for each `action` were \"_bigger_\",\nwe would split them out into their own functions e.g:\n\n```js\n// define the handler function used when action is \"inc\"\nfunction increment(model) {\n  return model + 1\n}\n// define handler for \"dec\" action\nfunction decrement(model) {\n  return model - 1\n}\nfunction update(model, action) {     // Update function takes the current state\n  switch(action) {                   // and an action (String) runs a switch\n    case Inc: return increment(model);  // add 1 to the model\n    case Dec: return decrement(model);  // subtract 1 from model\n    default: return model;           // if no action, return current state.\n  }                                  // (default action always returns current)\n}\n```\nThis is _functionally_ equivalent to the simpler `update` (_above_) \u003cbr /\u003e\nBut does not offer any _advantage_ at this stage (_just remember it for later_).\n\n### 5.4 Define the `view` Function\n\nThe `view` function is responsible\nfor _rendering_ the `state` to the DOM. \u003cbr /\u003e\n\n```js\nfunction view(signal, model, root) {\n  empty(root);                                 // clear root element before\n  [                                            // Store DOM nodes in an array\n    button('+', signal, Inc),                  // create button (defined below)\n    div('count', model),                       // show the \"state\" of the Model\n    button('-', signal, Dec)                   // button to decrement counter\n  ].forEach(function(el){ root.appendChild(el) }); // forEach is ES5 so IE9+\n}\n```\n\nThe `view` receives three arguments:\n+ `signal` defined above in `mount` tells each (DOM) element\nhow to \"handle\" the user input.\n+ `model` a reference to the _current_ value of the counter.\n+ `root` a reference to the root DOM element where the app is _mounted_.\n\nThe `view` function starts by _emptying_\nthe DOM inside the `root` element using the `empty` helper function. \u003cbr /\u003e\nThis is _necessary_ because, in the Elm Architecture, we _re-render_\nthe _entire_ application for each action. \u003cbr /\u003e\n\n\u003e See note on DOM Manipulation and \"Virtual DOM\" (_below_)\n\nThe `view` creates a _list_ (`Array`) of DOM nodes that need to be rendered.\n\n\n#### 5.4.1 `view` helper functions: `empty`, `button` and `div`\n\nThe `view` makes use of three \"helper\" (_DOM manipulation_) functions:\n\n1. `empty`: empty the `root` element of any \"child\" nodes.\n_Essentially_ `delete` the DOM inside whichever element's passed into `empty`.\n```js\nfunction empty(node) {\n  while (node.firstChild) { // while there are still nodes inside the \"parent\"\n      node.removeChild(node.firstChild); // remove any children recursively\n  }\n}\n```\n\n2. `button`: creates a\n[`\u003cbutton\u003e`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button)\nDOM element and attaches a\n[\"text node\"](https://developer.mozilla.org/en-US/docs/Web/API/Document/createTextNode)\nwhich is the _visible_ contents of the button the \"_user_\" sees.\n```js\nfunction button(buttontext, signal, action) {\n  var button = document.createElement('button');  // create a button HTML node\n  var text = document.createTextNode(buttontext); // human-readable button text\n  button.appendChild(text);                       // text goes *inside* button\n  button.className = action;                      // use action as CSS class\n  button.onclick = signal(action);                // onclick sends signal\n  return button;                                  // return the DOM node(s)\n}\n```\n\n3. `div`: creates a `\u003cdiv\u003e` DOM element and applies an `id` to it,\nthen if some `text` was supplied in the _second_ argument,\ncreates a \"text node\" to display that text.\n(_in the case of our counter the `text` is the current value of the model,\n  i.e. the count_)\n```js\nfunction div(divid, text) {\n  var div = document.createElement('div'); // create a \u003cdiv\u003e DOM element\n  div.id = divid;\n  if(text !== undefined) { // if text is passed in render it in a \"Text Node\"\n    var txt = document.createTextNode(text);\n    div.appendChild(txt);\n  }\n  return div;\n}\n```\n\n\u003e _**Note**: in `elm` land all of these \"helper\" functions are in the\n[`elm-html`](http://package.elm-lang.org/packages/evancz/elm-html/latest/)\npackage, but we have defined them in this counter example\nso there are **no dependencies** and you can see **exactly**\nhow everything is \"made\" from \"**first principals**\"_.\n\nOnce you have read through the functions\n(_and corresponding comments_), \u003cbr /\u003e\ntake a look at the _tests_.\n\n\u003e _**Pro Tip**: Writing code is an **iterative** (repetitive) process,\n**manually refreshing** the web browser each time you update\nsome code gets **tedious** quite fast, Live Server to the rescue!_\n\n### 6. (_Optional_) Install \"Live Server\" for \"_Live Reloading_\"\n\n\u003e **Note**: Live Reloading is not required,\ne.g. if you are on a computer where you cannot install anything,\nthe examples will still work in your web browser.\n\nLive Reloading helps you iterate/work faster because you don't have to \u003cbr /\u003e\n_manually_ refresh the page each time.  \nSimply run the following command:\n\n```\nnpm install \u0026\u0026 npm start\n```\nThis will download and start\n[`live-server`](https://github.com/tapio/live-server)\nwhich will auto-open your `default` browser: \u003cbr /\u003e\nThen you can _navigate_ to the desired file.\ne.g:\n[http://127.0.0.1:8000/examples/**counter-basic**/](http://127.0.0.1:8000/examples/counter-basic/)\n\n### 7. Read the _Tests_!\n\nIn the _first_ example we kept everything in\n_one_ file (`index.html`) for simplicity. \u003cbr /\u003e\nIn order to write tests (_and collect coverage_),\nwe need to _separate_ out\nthe JavaScript code from the HTML.\n\nFor this example there are 3 _separate_ files:\n\n![test-example-files](https://cloud.githubusercontent.com/assets/194400/25785513/768205e8-337a-11e7-826f-887c3ac937b6.png)\n\n\nLet's start by opening the `/examples/counter-basic-test/index.html`\nfile in a web browser: \u003cbr /\u003e\nhttp://127.0.0.1:8000/examples/counter-basic-test/?coverage\n\n![counter-coverage](https://cloud.githubusercontent.com/assets/194400/25816673/b994d25a-341c-11e7-8fd1-52e136fb7152.png)\n\nBecause all functions are \"pure\", testing\nthe `update` function is _very_ easy:\n\n```js\ntest('Test Update update(0) returns 0 (current state)', function(assert) {\n  var result = update(0);\n  assert.equal(result, 0);\n});\n\ntest('Test Update increment: update(1, \"inc\") returns 2', function(assert) {\n  var result = update(1, \"inc\");\n  assert.equal(result, 2);\n});\n\ntest('Test Update decrement: update(3, \"dec\") returns 2', function(assert) {\n  var result = update(1, \"dec\");\n  assert.equal(result, 0);\n});\n```\nopen: `examples/counter-basic-test/test.js` to see these and _other_ tests.\n\n\u003e The _reason_ why Apps built using the Elm Architecture\nare _**so easy**_ to _understand_ \u003cbr /\u003e\n(_or [\"**reason about**\"](http://stackoverflow.com/q/18666821)_)\nand _test_ is that all functions are \"Pure\".\n\n### 8. What is a \"_Pure_\" Function? (_Quick Learning/Recap_)\n\nPure Functions are functions that **always\nreturn** the **same output** for a **given input**. \u003cbr /\u003e\nPure Functions have \"_no side effects_\",\nmeaning they don't change anything they aren't supposed to, \u003cbr /\u003e\nthey just do what they are told; this makes them very predictable/testable.\nPure functions \"transform\" data into the desired value,\nthey do not \"mutate\" state.\n\n#### 8.1 Example of an _Impure_ Function\n\nThe following function is \"_impure_\" because it \"_mutates_\"\ni.e. changes the `counter` variable which is _outside_ of the function\nand not passed in as an argument:\n```js\n// this is an \"impure\" function that \"mutates\" state\nvar counter = 0;\nfunction increment () {\n  return ++counter;\n}\nconsole.log(increment()); // 1\nconsole.log(increment()); // 2\nconsole.log(increment()); // 3\n```\nsee: https://repl.it/FIot/1\n\n#### 8.2 Example of an _Pure_ Function\n\nThis example is a \"pure\" function because it will _always_ return\nsame result for a given input.\n```js\nvar counter = 0;\nfunction increment (my_counter) {\n  return my_counter + 1;\n}\n// counter variable is not being \"mutated\"\n// the output of a pure function is always identical\nconsole.log(increment(counter)); // 1\nconsole.log(increment(counter)); // 1\nconsole.log(increment(counter)); // 1\n// you can \"feed\" the output of one pure function into another to get the same result:\nconsole.log(increment(increment(increment(counter)))); // 3\n```\nsee: https://repl.it/FIpV\n\n#### 8.3 Counter Example written in \"Impure\" JS\n\nIt's _easy_ to get\n[_suckered_](http://www.urbandictionary.com/define.php?term=suckered)\ninto thinking that the \"_impure_\" version of the counter \u003cbr /\u003e\n`examples/counter-basic-impure/index.html`\nis \"_simpler_\" ... \u003cbr /\u003e\nthe _complete_ code (_including HTML and JS_) is ***8 lines***:\n\n```html\n\u003cbutton class='inc' onclick=\"incr()\"\u003e+\u003c/button\u003e\n\u003cdiv id='count'\u003e0\u003c/div\u003e\n\u003cbutton class='dec' onclick=\"decr()\"\u003e-\u003c/button\u003e\n\u003cscript\u003e\n  var el = document.getElementById('count')\n  function incr() { el.innerHTML = parseInt(el.textContent, 10) + 1 };\n  function decr() { el.innerHTML = parseInt(el.textContent, 10) - 1 };\n\u003c/script\u003e\n```\n\n\nThis counter _does_ the same thing as\nour Elm Architecture example (_above_), \u003cbr /\u003e\nand to the _end-user_ the UI **_looks_ identical**:\n\n![counter-impure-665](https://cloud.githubusercontent.com/assets/194400/25816521/3a0e0722-341c-11e7-9afc-269abb4bb225.png)\n\n\nThe difference is that in the _impure_ example is \"_mutating state_\"\nand it's impossible to predict what that state will be!\n\n\u003e _Annoyingly, for the person explaining the benefits\nof function \"purity\" and the virtues of the Elm Architecture \u003cbr /\u003e\nthe \"impure\" example is both **fewer lines of code**\n(which means it **loads faster**!), takes less time to read  \u003cbr /\u003e\nand renders faster because only the `\u003cdiv\u003e` text content\nis being updated on each update! \u003cbr /\u003e\n\u003e This is why it can often be **difficult to explain** to \"**non-technical**\"\n**people** that code which has similar output  \u003cbr /\u003e\non the **screen**(s)\nmight **not the same** quality \"**behind the scenes**\"!_ \u003cBr /\u003e\n\u003e _Writing impure functions is like setting off on a marathon run after\n[tying your shoelaces **incorrectly**](https://youtu.be/zAFcV7zuUDA) ... \u003cbr /\u003e\nYou might be \"OK\" for a while, but pretty soon your laces will come undone\nand you will have to **stop** and **re-do** them._\n\n\nTo conclude: Pure functions do not mutate a \"global\" state\nand are thus predictable and easy to test;\nwe _always_ use \"Pure\" functions in Apps built with the Elm Architecture.\nThe moment you use \"_impure_\" functions you forfeit reliability.\n\n\n### 9. Extend the Counter Example following \"TDD\": Reset the Count!\n\nAs you (_hopefully_) recall from our\n[Step-by-Step TDD Tutorial](https://github.com/dwyl/learn-tdd),\nwhen we craft code following the \"TDD\" approach,\nwe go through the following steps:\n1. Read and understand the \"user story\"\n(_e.g: in this case_:\n  [issues/5](https://github.com/dwyl/learn-elm-architecture-in-javascript/issues/5))\n![reset-counter-user-story](https://cloud.githubusercontent.com/assets/194400/25817522/84fdd9bc-341f-11e7-9efd-406d76a3b1f3.png) \u003cbr /\u003e\n2. Make sure the \"_acceptance criteria_\" are clear\n(_the checklist in the issue_)\n3. Write your test(s) based on the acceptance criteria.\n(_Tip: a single feature - in this case resetting the counter - can\n  and often `should` have multiple tests to cover all cases._)\n4. Write code to make the test(s) pass.\n\n\u003e `BEFORE` you continue, try and build the \"reset\"\nfunctionality yourself following TDD approach!\n\n\n\n\u003cbr /\u003e\u003cbr /\u003e\u003cbr /\u003e\n\n#### 9.1 Tests for Resetting the Counter (Update)\n\nWe _always_ start with the Model test(s)\n(_because they are the easiest_):\n\n```js\ntest('Test: reset counter returns 0', function(assert) {\n  var result = update(6, \"reset\");\n  assert.equal(result, 0);\n});\n```\n#### 9.2 Watch it Fail!\n\nWatch the test _fail_ in your Web Browser: \u003cbr /\u003e\n![reset-counter-failing-test](https://cloud.githubusercontent.com/assets/194400/25818566/e2c33152-3422-11e7-9c4c-9ecd9fa9ffc6.png)\n\n#### 9.3 Make it Pass (_writing the minimum code_)\n\nIn the case of an App written with the Elm Architecture,\nthe minimum code is:\n+ Action in this case `var Res = 'reset';`\n+ Update (_case and/or function_) to \"_process the signal_\" from the UI\n(_i.e. handle the user's desired action_)\n```js\ncase Res: return 0;\n```\n![reset-counter-test-passing](https://cloud.githubusercontent.com/assets/194400/25818892/05349e96-3424-11e7-8d42-b4cbbc1eb1a6.png)\n\n#### 9.4 Write View (UI) Tests\n\nOnce we have the Model tests passing\nwe need to give the _user_ something to interact with! \u003cbr /\u003e\nWe are going to be \"_adventurous_\" and write _two_ tests this time! \u003cbr /\u003e\n(_thankfully we already have a UI test for another button we can \"copy\"_)\n\n```js\ntest('reset button should be present on page', function(assert) {\n  var reset = document.getElementsByClassName('reset');\n  assert.equal(reset.length, 1);\n});\n\ntest('Click reset button resets model (counter) to 0', function(assert) {\n  mount(7, update, view, id); // set initial state\n  var root = document.getElementById(id);\n  assert.equal(root.getElementsByClassName('count')[0].textContent, 7);\n  var btn = root.getElementsByClassName(\"reset\")[0]; // click reset button\n  btn.click(); // Click the Reset button!\n  var state = root.getElementsByClassName('count')[0].textContent;\n  empty(document.getElementById(id)); // Clear the test DOM elements\n});\n```\n#### 9.5 Watch View/UI Tests Fail!\n\nWatch the UI tests go red in the browser:\n\n![reset-counter-failing-tests](https://cloud.githubusercontent.com/assets/194400/25819267/59ea1a64-3425-11e7-8f77-2380c6518b9d.png)\n\n#### 9.6 Make UI Tests Pass (_writing the minimum code_)\n\nLuckily, to make _both_ these tests _pass_ requires\na _single_ line of code in the `view` function!\n\n```js\nbutton('Reset', signal, Res)\n```\n![reset-counter](https://cloud.githubusercontent.com/assets/194400/25822128/82eb7a8e-342f-11e7-9cd0-1a69d95ee878.gif)\n\n\u003cbr /\u003e\n\n### 10. _Next Level: Multiple Counters_!\n\nNow that you have _understood_ the Elm Architecture\nby following the basic (_single_) counter example,\nit's time to take the example to the next level:\nmultiple counters on the same page!\n\n#### Multiple Counters Exercise\n\nFollow your _instincts_ and `try` to the following:\n\n**1.** **Refactor** the \"reset counter\" example\nto use an `Object` for the `model` (_instead of an_ `Integer`) \u003cbr /\u003e\n**e.g**: `var model = { counters: [0] }` \u003cbr /\u003e\nwhere the value of the first element in the `model.counters` Array\nis the value for the _single_ counter example. \u003cbr /\u003e\n\n**2.** **Display _multiple_ counters** on the **_same_ page**\nusing the `var model = { counters: [0] }` approach. \u003cbr /\u003e\n\n**3.** **Write tests** for the scenario where there\nare multiple counters on the same page.\n\nOnce you have had a go, checkout our solutions:\n[`examples/multiple-counters`](https://github.com/dwyl/learn-elm-architecture-in-javascript/tree/master/examples/multiple-counters)\n\u003cbr /\u003e\nand corresponding writeup:\n[**multiple-counters.md**](https://github.com/dwyl/learn-elm-architecture-in-javascript/blob/master/multiple-counters.md)\n\n\n\u003cbr /\u003e\n\n### 11. Todo List!\n\nThe _ultimate_ test of whether you _learned/understood_ something is \u003cbr /\u003e\n_applying_ your knowledge to _different_ context from the one you learned in.\n\nLet's \"_turn this up to eleven_\" and build something \"_useful_\"!\n\nGOTO:\n[`todo-list.md`](https://github.com/dwyl/learn-elm-architecture-in-javascript/blob/master/todo-list.md)\n\n\u003cbr /\u003e\n\n\n## Futher/Background Reading\n\n+ The Elm Architecture Simple, yet powerful – An overview by example:\nhttps://dennisreimann.de/articles/elm-architecture-overview.html\n(_written in Elm so not much use for people who only know JS,\n  but a good post for further reading!_)\n+ What does it mean when something is \"_easy to **reason about**_\"?  \nhttp://stackoverflow.com/questions/18666821/what-does-the-term-reason-about-mean-in-computer-science\n+ Elm Architecture with JQuery by @steos:\nhttps://medium.com/javascript-inside/elm-architecture-with-jquery-152cb98a62f\n(_written in JQuery and no Tests so\n  not ideal for teaching beginners good habits, but still a v. good post!_)\n+ Pure functions: https://en.wikipedia.org/wiki/Pure_function\n+ Higher Order Functions in JavaScript:\nhttp://eloquentjavascript.net/05_higher_order.html\n+ Higher-order functions - Part 1 of Functional Programming in JavaScript:\nhttps://youtu.be/BMUiFMZr7vk\n\n\n\u003cbr /\u003e \u003cbr /\u003e\u003cbr /\u003e\n# tl;dr\n\n\n### _Flattening_ the Learning Curve\n\nThe issue of the \"Elm Learning Curve\" was raised in:\n[github.com/dwyl/**learn-elm**/issues/**45**](https://github.com/dwyl/learn-elm/issues/45) \u003cbr /\u003e\nand scrolling down to to @lucymonie's\n[list](https://github.com/dwyl/learn-elm/issues/45#issuecomment-275947200)\nwe see the **Elm _Architecture_** at number four ... \u003cbr /\u003e\n`this` seems fairly logical (_initially_) because the _Elm **Guide**_\nuses the _Elm **Language**_ to explain the _Elm **Architecture**_:\nhttps://guide.elm-lang.org/architecture\n\n![elm-architecture](https://cloud.githubusercontent.com/assets/194400/25771470/72eccdd6-324a-11e7-8723-f07bcc188c21.png)\n\ni.e. it ***assumes*** that people **already _understand_**\nthe (Core) _Elm **Language**_... \u003cbr /\u003e\nThis is a _fair_ assumption given the _ordering_ of the Guide _however_\n... we have a _different_ idea:\n\n### Hypothesis: Learn (\u0026 Practice) Elm Architecture _`before`_ Learning Elm?\n\nWe ***hypothesize*** that if we _**explain** the **Elm Architecture**_\n(_**in detail**_) using a **language** \u003cbr /\u003e\npeople are _**already familiar**_ with (_i.e **JavaScript**_)\n_`before`_ diving into the Elm Language \u003cbr /\u003e\nit will\n[\"***flatten***\"](https://english.stackexchange.com/questions/6212/whats-the-opposite-for-steep-learning-curve)\nthe **learning curve**.\n\n\u003e _**Note**: Understanding the **Elm Architecture**\nwill give you a **massive headstart** \u003cbr /\u003e\non [learning **Redux**](https://github.com/dwyl/learn-redux)\nwhich is the \"de facto\" way of structuring React.js Apps. \u003cbr /\u003e\nSo even if you\ndecide not to learn/use Elm, you will still gain\n**great frontend skills**!_\n\n### Isn't DOM Manipulation Super Slow...?\n\n\u003e _DOM manipulation is the **slowest**\npart of any \"**client-side**\" web app. \u003cbr /\u003e\n\u003e That is why so many client-side frameworks\n(including **Elm**, React and Vue.js) now use a \"**Virtual DOM**\".\n\u003e For the purposes of `this` tutorial, and for **most small apps**\nVirtual DOM is total **overkill**! \u003cbr /\u003e\nIt's akin to putting a **jet engine** in a [**go kart**](https://en.wikipedia.org/wiki/Go-kart)!_\n\n### What is \"_Plain_\" JavaScript?\n\n\"_Plain_\" JavaScript just means not using _any_ frameworks\nor features that require \"compilation\".\n\nThe point is to _understand_ that you don't need\n_anything_ more than\n[\"***JavaScript the Good Parts***\"](https://github.com/iteles/Javascript-the-Good-Parts-notes) \u003cbr /\u003e\nto build something full-featured and easy/fast to read!!\n\n[![babel](https://cloud.githubusercontent.com/assets/194400/25772913/72a818f4-326c-11e7-8020-9b5dab715987.png)](https://twitter.com/iamdevloper/status/787969734918668289 \"Babel, how to show off that you don't have core ES5 skills.\")\n\nIf you can build with \"ES5\" JavaScript: \u003cbr /\u003e\n**a)** you side-step the\n[_noise_](https://twitter.com/iamdevloper/status/610191865216786432)\nand focus on core skills that **_already_ work everywhere**! \u003cbr /\u003e\n(_don't worry you can always \"top-up\" your\nJS knowledge later with ES6, etc!_)\u003cbr /\u003e\n**b)** you **don't** need to **waste time** installing\n[_**Two Hundred Megabytes**_](https://cloud.githubusercontent.com/assets/194400/13321493/39fcfa30-dbc7-11e5-8b05-f046675f9cb6.png)\nof dependencies just to run a simple project! \u003cbr /\u003e\n**c)** You ***save time*** (_for yourself, your team and end-users!_)\nbecause your code is _already_ optimized to run in _any_ browser!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdwyl%2Flearn-elm-architecture-in-javascript","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdwyl%2Flearn-elm-architecture-in-javascript","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdwyl%2Flearn-elm-architecture-in-javascript/lists"}