<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Ben Booth]]></title><description><![CDATA[Hi 👋 I'm Ben and I make things for the web. Sometimes I write things here and sometimes I talk about things. I'm also a husband & father, football (soccer) addict and a Christian.]]></description><link>https://benbooth.dev</link><generator>RSS for Node</generator><lastBuildDate>Sat, 11 Sep 2021 14:07:57 GMT</lastBuildDate><author><![CDATA[Ben Booth]]></author><copyright><![CDATA[© 2021 Ben Booth]]></copyright><item><title><![CDATA[Animating Loading Spinners with CSS]]></title><description><![CDATA[On a recent side project I had wasted a bunch of time creating a fancy loading spinner while I was mentally blocked trying to solve a real problem. Explore the interesting parts of the CSS animation API through the medium of loading spinners.]]></description><link>https://benbooth.dev/animating-loading-spinners-with-css</link><guid isPermaLink="false">https://benbooth.dev/animating-loading-spinners-with-css</guid><dc:creator><![CDATA[Ben Booth]]></dc:creator><pubDate>Tue, 20 Jun 2017 22:49:09 GMT</pubDate><content:encoded>&lt;p&gt;I recently had the privilege of being invited to give my first ever meetup talk at &lt;a href=&quot;https://www.meetup.com/SydCSS/&quot;&gt;SydCSS&lt;/a&gt;. It was a first time speakers night so short talks (5 mins) and high nerves were the order of the day. On a recent side project I had wasted a bunch of time creating a fancy loading spinner while I was mentally blocked trying to solve a real problem. I had the idea at the time that I could probably give a reasonably interesting talk by making some loading animations with CSS and explaining the interesting parts of the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/animation&quot;&gt;CSS animation&lt;/a&gt; API used for each animation. I had a rough plan and a platform, the rest of this article is the transcript of that talk rewritten as a blog post.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can view the &lt;a href=&quot;https://github.benbooth.dev/sydcss-talk-animations/&quot;&gt;slides&lt;/a&gt; for the talk &lt;a href=&quot;https://github.benbooth.dev/sydcss-talk-animations/&quot;&gt;here&lt;/a&gt;, take a look and play around with the examples on the slides!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are two basic building blocks for &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/animation&quot;&gt;CSS animations&lt;/a&gt;. Firstly the &lt;a href=&quot;https://developer.mozilla.org/en/docs/Web/CSS/@keyframes&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@keyframes&lt;/code&gt; at-rule&lt;/a&gt;, which you define with the &lt;code class=&quot;language-text&quot;&gt;@keyframes&lt;/code&gt; keyword, then a name or identifier for the keyframes set, then a list of steps which define CSS properties for each step.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;css&quot;&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@keyframes&lt;/span&gt; my-sweet-animation&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token selector&quot;&gt;0%&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token selector&quot;&gt;50%&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token selector&quot;&gt;100%&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Secondly the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/animation&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;animation&lt;/code&gt;&lt;/a&gt; properties which you can use in shorthand form, or by using individual sub-properties.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;css&quot;&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@keyframes&lt;/span&gt; my-sweet-animation&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;.thing-to-animate&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* shorthand */&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;animation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2s my-sweet-animation&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;/* individual sub-properties */&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;animation-name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; my-sweet-animation&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;animation-duration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2s&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;animation-timing-function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ease&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There are 8 &lt;code class=&quot;language-text&quot;&gt;animation&lt;/code&gt; sub-properties and they provide a great deal of flexibility: &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/animation-name&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;animation-name&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/animation-duration&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;animation-duration&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/animation-delay&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;animation-delay&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/animation-direction&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;animation-direction&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/animation-iteration-count&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;animation-iteration-count&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timing-function&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;animation-timing-function&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/animation-fill-mode&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;animation-fill-mode&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/animation-play-state&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;animation-play-state&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Fading&lt;/h2&gt;
&lt;iframe height=&quot;265&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Fading dot, 3-step @keyframes&quot; src=&quot;//codepen.io/bkbooth/embed/WOjvPM/?height=265&amp;theme-id=0&amp;default-tab=css,result&quot; frameborder=&quot;no&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;
  See the Pen &lt;a href=&apos;https://codepen.io/bkbooth/pen/WOjvPM/&apos;&gt;Fading dot, 3-step @keyframes&lt;/a&gt; by Ben (&lt;a href=&apos;https://codepen.io/bkbooth&apos;&gt;@bkbooth&lt;/a&gt;)
  on &lt;a href=&apos;https://codepen.io&apos;&gt;CodePen&lt;/a&gt;.
&lt;/iframe&gt;
&lt;p&gt;Starting with a simple fading dot animation, which is just a block with rounded corners where the &lt;code class=&quot;language-text&quot;&gt;opacity&lt;/code&gt; is being faded in and out. I’ve defined the &lt;a href=&quot;https://developer.mozilla.org/en/docs/Web/CSS/@keyframes&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@keyframes&lt;/code&gt; at-rule&lt;/a&gt; with 3 steps going from completely visible, to completely invisible, then back to completely visible. To use these keyframes to animate the dot, I’ve used the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/animation&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;animation&lt;/code&gt;&lt;/a&gt; shorthand property to set the &lt;code class=&quot;language-text&quot;&gt;animation-duration&lt;/code&gt; to &lt;em&gt;1 second&lt;/em&gt;; the &lt;code class=&quot;language-text&quot;&gt;animation-name&lt;/code&gt; to &lt;em&gt;‘fade-in-out’&lt;/em&gt; which matches the &lt;code class=&quot;language-text&quot;&gt;@keyframes&lt;/code&gt; at-rule; and &lt;em&gt;‘infinite’&lt;/em&gt; for the &lt;code class=&quot;language-text&quot;&gt;animation-iteration-count&lt;/code&gt;. &lt;code class=&quot;language-text&quot;&gt;animation-iteration-count&lt;/code&gt; can be a number or &lt;em&gt;‘infinite’&lt;/em&gt; and defaults to &lt;em&gt;1&lt;/em&gt;. A single pass through the keyframes isn’t very useful for loading animations, so I’ll be using &lt;em&gt;‘infinite’&lt;/em&gt; for all of these animations. You can tweak the speed of the animation by modifying the &lt;code class=&quot;language-text&quot;&gt;animation-duration&lt;/code&gt; property which takes seconds or milliseconds values.&lt;/p&gt;
&lt;iframe height=&quot;266&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Fading dot, 2-step @keyframes&quot; src=&quot;//codepen.io/bkbooth/embed/wedKWj/?height=266&amp;theme-id=0&amp;default-tab=css,result&quot; frameborder=&quot;no&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;
  See the Pen &lt;a href=&apos;https://codepen.io/bkbooth/pen/wedKWj/&apos;&gt;Fading dot, 2-step @keyframes&lt;/a&gt; by Ben (&lt;a href=&apos;https://codepen.io/bkbooth&apos;&gt;@bkbooth&lt;/a&gt;)
  on &lt;a href=&apos;https://codepen.io&apos;&gt;CodePen&lt;/a&gt;.
&lt;/iframe&gt;
&lt;p&gt;In this case the &lt;a href=&quot;https://developer.mozilla.org/en/docs/Web/CSS/@keyframes&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@keyframes&lt;/code&gt; at-rule&lt;/a&gt; can be simplified to just the start and end steps by setting the &lt;code class=&quot;language-text&quot;&gt;animation-direction&lt;/code&gt; property to &lt;em&gt;‘alternate’&lt;/em&gt;, which means the animation goes forward through the keyframes steps, then back through in reverse. Now that a full animation loop goes through the keyframes twice, the &lt;code class=&quot;language-text&quot;&gt;animation-duration&lt;/code&gt; should be halved. This approach means that you can define more generic and reusable &lt;a href=&quot;https://developer.mozilla.org/en/docs/Web/CSS/@keyframes&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@keyframes&lt;/code&gt; at-rules&lt;/a&gt;. You may also see &lt;em&gt;‘from’&lt;/em&gt; and &lt;em&gt;‘to’&lt;/em&gt; instead of percentages for keyframes steps, these are just aliases for &lt;em&gt;‘0%’&lt;/em&gt; and &lt;em&gt;‘100%’&lt;/em&gt; respectively. I personally prefer to stick with percentage steps.&lt;/p&gt;
&lt;h2&gt;Spinning&lt;/h2&gt;
&lt;iframe height=&quot;263&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Rotating star&quot; src=&quot;//codepen.io/bkbooth/embed/yXboZM/?height=263&amp;theme-id=0&amp;default-tab=css,result&quot; frameborder=&quot;no&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;
  See the Pen &lt;a href=&apos;https://codepen.io/bkbooth/pen/yXboZM/&apos;&gt;Rotating star&lt;/a&gt;
  by Ben (&lt;a href=&apos;https://codepen.io/bkbooth&apos;&gt;@bkbooth&lt;/a&gt;)
  on &lt;a href=&apos;https://codepen.io&apos;&gt;CodePen&lt;/a&gt;.
&lt;/iframe&gt;
&lt;p&gt;Spinners are another simple animation that can be defined easily in CSS. I’ve introduced the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/transform&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;transform&lt;/code&gt;&lt;/a&gt; property to handle the rotation, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/transform&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;transform&lt;/code&gt;&lt;/a&gt; provides a great toolset of functions for 2D and 3D translating (as in movement), scaling and rotation. The &lt;em&gt;‘rotate’&lt;/em&gt; &lt;a href=&quot;https://developer.mozilla.org/en/docs/Web/CSS/@keyframes&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@keyframes&lt;/code&gt; at-rule&lt;/a&gt; just sets the starting rotation to &lt;em&gt;‘0deg’&lt;/em&gt; and the ending rotation to &lt;em&gt;‘360deg’&lt;/em&gt;. I’ve introduced the &lt;code class=&quot;language-text&quot;&gt;animation-timing-function&lt;/code&gt; property and set it to &lt;em&gt;‘linear’&lt;/em&gt;. &lt;code class=&quot;language-text&quot;&gt;animation-timing-function&lt;/code&gt; defaults to &lt;em&gt;‘ease’&lt;/em&gt; to ease the animation in and out, this caused the fading dot to “breathe” in and out. If a rotation animation uses &lt;em&gt;‘ease’&lt;/em&gt; it speeds up and slows down, for rotation you want a nice even &lt;em&gt;‘linear’&lt;/em&gt; animation.&lt;/p&gt;
&lt;iframe height=&quot;270&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Rotating concentric circles&quot; src=&quot;//codepen.io/bkbooth/embed/RgVZvO/?height=231&amp;theme-id=0&amp;default-tab=css,result&quot; frameborder=&quot;no&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;
  See the Pen &lt;a href=&apos;https://codepen.io/bkbooth/pen/RgVZvO/&apos;&gt;Rotating concentric circles&lt;/a&gt;
  by Ben (&lt;a href=&apos;https://codepen.io/bkbooth&apos;&gt;@bkbooth&lt;/a&gt;)
  on &lt;a href=&apos;https://codepen.io&apos;&gt;CodePen&lt;/a&gt;.
&lt;/iframe&gt;
&lt;p&gt;Using the same rotation &lt;a href=&quot;https://developer.mozilla.org/en/docs/Web/CSS/@keyframes&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@keyframes&lt;/code&gt; at-rule&lt;/a&gt; you can create more complex animations by just combining things we’ve already looked at. Another value that you can set for the &lt;code class=&quot;language-text&quot;&gt;animation-direction&lt;/code&gt; property is &lt;em&gt;‘reverse’&lt;/em&gt; which as you can probably guess, plays the keyframes in reverse.&lt;/p&gt;
&lt;p&gt;You can use the same &lt;code class=&quot;language-text&quot;&gt;keyframes&lt;/code&gt; to rotate pretty much anything you want…&lt;/p&gt;
&lt;iframe height=&quot;203&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Rotating doge&quot; src=&quot;//codepen.io/bkbooth/embed/awWyeK/?height=203&amp;theme-id=0&amp;default-tab=css,result&quot; frameborder=&quot;no&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;
  See the Pen &lt;a href=&apos;https://codepen.io/bkbooth/pen/awWyeK/&apos;&gt;Rotating doge&lt;/a&gt;
  by Ben (&lt;a href=&apos;https://codepen.io/bkbooth&apos;&gt;@bkbooth&lt;/a&gt;)
  on &lt;a href=&apos;https://codepen.io&apos;&gt;CodePen&lt;/a&gt;.
&lt;/iframe&gt;
&lt;h2&gt;Chasing&lt;/h2&gt;
&lt;iframe height=&quot;405&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Chasing dots, CSS&quot; src=&quot;//codepen.io/bkbooth/embed/pwPWjw/?height=399&amp;theme-id=0&amp;default-tab=css,result&quot; frameborder=&quot;no&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;
  See the Pen &lt;a href=&apos;https://codepen.io/bkbooth/pen/pwPWjw/&apos;&gt;Chasing dots, CSS&lt;/a&gt;
  by Ben (&lt;a href=&apos;https://codepen.io/bkbooth&apos;&gt;@bkbooth&lt;/a&gt;)
  on &lt;a href=&apos;https://codepen.io&apos;&gt;CodePen&lt;/a&gt;.
&lt;/iframe&gt;
&lt;p&gt;For this animation I’ve arranged a series of small dots around a circle and used a similar &lt;a href=&quot;https://developer.mozilla.org/en/docs/Web/CSS/@keyframes&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@keyframes&lt;/code&gt; at-rule&lt;/a&gt; as earlier, fading the dots in and out to &lt;em&gt;‘20%’&lt;/em&gt; &lt;code class=&quot;language-text&quot;&gt;opacity&lt;/code&gt;. The main &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/animation&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;animation&lt;/code&gt;&lt;/a&gt; shorthand property adds nothing new and is being applied to all of the individual dots with an attribute selector. I’ve set an &lt;code class=&quot;language-text&quot;&gt;animation-delay&lt;/code&gt; for each of the dots to offset each of them starting by an 1/8th of a second. As you can see it’s a little tedious having to manually set the offset for each dot, especially if you wanted to change the speed of the whole animation.&lt;/p&gt;
&lt;iframe height=&quot;350&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Chasing dots, SCSS&quot; src=&quot;//codepen.io/bkbooth/embed/zzwEqa/?height=331&amp;theme-id=0&amp;default-tab=css,result&quot; frameborder=&quot;no&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;
  See the Pen &lt;a href=&apos;https://codepen.io/bkbooth/pen/zzwEqa/&apos;&gt;Chasing dots, SCSS&lt;/a&gt;
  by Ben (&lt;a href=&apos;https://codepen.io/bkbooth&apos;&gt;@bkbooth&lt;/a&gt;)
  on &lt;a href=&apos;https://codepen.io&apos;&gt;CodePen&lt;/a&gt;.
&lt;/iframe&gt;
&lt;p&gt;If you’re using SASS or something similar, you can improve on this by setting the desired animation speed and the number of dots in variables. Halve the animation speed for the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/animation&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;animation&lt;/code&gt;&lt;/a&gt; property definition. Then loop through the number of dots and calculate the &lt;code class=&quot;language-text&quot;&gt;animation-delay&lt;/code&gt; for each dot using the desired animation speed, number of dots and current iteration variables.&lt;/p&gt;
&lt;h2&gt;Bouncing&lt;/h2&gt;
&lt;iframe height=&quot;315&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Bouncing dot, single&quot; src=&quot;//codepen.io/bkbooth/embed/owWGGr/?height=284&amp;theme-id=0&amp;default-tab=css,result&quot; frameborder=&quot;no&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;
  See the Pen &lt;a href=&apos;https://codepen.io/bkbooth/pen/owWGGr/&apos;&gt;Bouncing dot, single&lt;/a&gt;
  by Ben (&lt;a href=&apos;https://codepen.io/bkbooth&apos;&gt;@bkbooth&lt;/a&gt;)
  on &lt;a href=&apos;https://codepen.io&apos;&gt;CodePen&lt;/a&gt;.
&lt;/iframe&gt;
&lt;p&gt;This bouncing dot animation uses yet another fairly simple &lt;a href=&quot;https://developer.mozilla.org/en/docs/Web/CSS/@keyframes&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@keyframes&lt;/code&gt; at-rule&lt;/a&gt;, it’s just using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/transform&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;transform&lt;/code&gt;&lt;/a&gt; property to translate the dot up, and I’m using &lt;em&gt;‘alternate’&lt;/em&gt; for the &lt;code class=&quot;language-text&quot;&gt;animation-direction&lt;/code&gt; again. To make it look more “bouncy” I’ve defined a &lt;em&gt;‘cubic-bezier’&lt;/em&gt; function for the &lt;code class=&quot;language-text&quot;&gt;animation-timing-function&lt;/code&gt; property. If that looks a little daunting to you, don’t worry, I didn’t actually write this, and you should never need to write one of these by hand because Chrome (and possibly other browsers?) has an awesome bezier curve editor where you can just drag some dots to visually create the cubic-bezier curve and it will write the cubic-bezier function for you.&lt;/p&gt;
&lt;p&gt;&lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 500px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 88.2%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAIAAADUsmlHAAAACXBIWXMAAAsSAAALEgHS3X78AAACbUlEQVQ4y2VTiXKbMBTk//+rbdxMMuMkPjEYAtjcQhJCB4h0gdp1J2uOJ1n73r4VcuIgiH2fVHUQxxWlsu+NHZXRZjA9YlzGjOP49T+stWmaOvL5Wfz81R2O+XZXH91k/V65h2Tz+fa0P5y93d5df2zDKC6rijSUMl7VdUVIVhTgO6JtlRBaCEVpW9eGc0kbxTvdGq00FBjTK6WlVBhqqTssp7LrpFLKSfaHIs22RzcvijTPCaV5WTLOdNnLUg+dHeRglUVgaC8LzTyRP6FG3wruyNVK7vaHo/sZJXbGMAwo97e5x2bH6bKDHfGztm1bp/39TLa70A9e1u9RnASfEWNca90PPSE1lk0sO85c+DbeDZvI3ccHP3l5FEsl0RhlDC9YnGVZEAQPVSfaYAZSNk1JoW4ii9VKrdfd6ysLgjBKTl5gZoCMLBNt/Lr8KIfW8qrdvu0CN+S0xeZN5MFaqTVkcLgtBGxcAJqe5xEYNsDb/WGPmbtsSqmTJMn1ek2zLAzD8/mMZ1mWyMo59zxvIQNooWmahbY8q6py8jzHixCC1UVRIB8Eg3y5XBAvTHThnk5zC/8MA3Ei34EsdV1HUYREWAHxS51LmvgvQXuWdz7mUcNZdIIZxzHG4IPcdR1U4K8pRafOx0ARbVh/33mQ0ayDmzEGAmhCiOsMVMZ3jxTjDd8PxlQZOlEWS5ECnWMKQ8SPHX4H9hmmOFALw33fRzXoxBSMZYwuK5avdYG9ATFO62azcZJLgj2A1MUzkGEBEpU1Kas6K/BusrxoKBNS4lQy3hZlhTM1yUZjaBXGihkYgjnt/A1LfH3AMkCNP2Yo+l6/o4JvAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;picture&gt;
        &lt;source
          srcset=&quot;/static/60e97545037c56f527d502e24c13c96e/98976/cubic-bezier.webp 178w,
/static/60e97545037c56f527d502e24c13c96e/59b7f/cubic-bezier.webp 355w,
/static/60e97545037c56f527d502e24c13c96e/f452f/cubic-bezier.webp 500w&quot;
          sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
          type=&quot;image/webp&quot;
        /&gt;
        &lt;source
          srcset=&quot;/static/60e97545037c56f527d502e24c13c96e/3dc0b/cubic-bezier.png 178w,
/static/60e97545037c56f527d502e24c13c96e/55102/cubic-bezier.png 355w,
/static/60e97545037c56f527d502e24c13c96e/c37a4/cubic-bezier.png 500w&quot;
          sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
          type=&quot;image/png&quot;
        /&gt;
        &lt;img
          class=&quot;gatsby-resp-image-image&quot;
          style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
          src=&quot;/static/60e97545037c56f527d502e24c13c96e/c37a4/cubic-bezier.png&quot;
          alt=&quot;Chrome cubic-bezier editor&quot;
          title=&quot;Chrome cubic-bezier editor&quot;
        /&gt;
      &lt;/picture&gt;
  &lt;/span&gt;&lt;/p&gt;
&lt;iframe height=&quot;365&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Bouncing dot, triple&quot; src=&quot;//codepen.io/bkbooth/embed/XgReQG/?height=356&amp;theme-id=0&amp;default-tab=css,result&quot; frameborder=&quot;no&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;
  See the Pen &lt;a href=&apos;https://codepen.io/bkbooth/pen/XgReQG/&apos;&gt;Bouncing dot, triple&lt;/a&gt;
  by Ben (&lt;a href=&apos;https://codepen.io/bkbooth&apos;&gt;@bkbooth&lt;/a&gt;)
  on &lt;a href=&apos;https://codepen.io&apos;&gt;CodePen&lt;/a&gt;.
&lt;/iframe&gt;
&lt;p&gt;Finally, to create this excitedly impatient series of dots, I’ve defined a slightly more complex &lt;a href=&quot;https://developer.mozilla.org/en/docs/Web/CSS/@keyframes&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@keyframes&lt;/code&gt; at-rule&lt;/a&gt; which performs the translation up and down in just the first 1/3rd of the time. I’ve also set an &lt;code class=&quot;language-text&quot;&gt;animation-delay&lt;/code&gt; for each of the dots in the series to offset them starting.&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;Most of this is relatively new to the CSS spec but support in modern browsers is actually really good. Depending what browsers you need to target though you’ll get a lot of mileage out of using &lt;a href=&quot;https://github.com/postcss/autoprefixer&quot;&gt;autoprefixer&lt;/a&gt; to process your CSS and automatically add any required vendor prefixes like &lt;code class=&quot;language-text&quot;&gt;-webkit&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;-moz&lt;/code&gt;, etc.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en/docs/Web/CSS/animation#Browser_compatibility&quot;&gt;&lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 710px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 23.616734143049932%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAYAAABFA8wzAAAACXBIWXMAABYlAAAWJQFJUiTwAAAA+UlEQVQY01VQ2W6DMBDk/z8ubSM1hSgH2IQCMfjAHCYN011IH7rS7Mzao1nLURwnYEiZ45gkOBy+8P6xx273BiEkuJZl4c5i4xX4z8umo/1njFMqYfsB+d2gbg3GaYKnuSdwPV/+NepPU2N+vnjBpqP4nOJWN8grhayoUGuL7FaidQ5Vo3GRBc2Mb1xzRrEye0RRQpY1riLHOROUoxAp1UBrg7ZtYU0KYyuaGzh7oVANSUvu1RGd1+urQwgI8wzXdVD1Cb5T5BcwpoAfRkTDFDCMEwU59MR86LwnPaIbApRx0NZiDDOm+bEiPH7Qk08b+h5awBl83xP/ApmvfSnu5AhtAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;picture&gt;
        &lt;source
          srcset=&quot;/static/6d6e5c848c1c40f7193906dc96a1746b/98976/mdn-animations.webp 178w,
/static/6d6e5c848c1c40f7193906dc96a1746b/59b7f/mdn-animations.webp 355w,
/static/6d6e5c848c1c40f7193906dc96a1746b/535f3/mdn-animations.webp 710w,
/static/6d6e5c848c1c40f7193906dc96a1746b/c70df/mdn-animations.webp 1065w,
/static/6d6e5c848c1c40f7193906dc96a1746b/ce8e6/mdn-animations.webp 1420w,
/static/6d6e5c848c1c40f7193906dc96a1746b/4f667/mdn-animations.webp 1482w&quot;
          sizes=&quot;(max-width: 710px) 100vw, 710px&quot;
          type=&quot;image/webp&quot;
        /&gt;
        &lt;source
          srcset=&quot;/static/6d6e5c848c1c40f7193906dc96a1746b/3dc0b/mdn-animations.png 178w,
/static/6d6e5c848c1c40f7193906dc96a1746b/55102/mdn-animations.png 355w,
/static/6d6e5c848c1c40f7193906dc96a1746b/d27e1/mdn-animations.png 710w,
/static/6d6e5c848c1c40f7193906dc96a1746b/afdd0/mdn-animations.png 1065w,
/static/6d6e5c848c1c40f7193906dc96a1746b/beee1/mdn-animations.png 1420w,
/static/6d6e5c848c1c40f7193906dc96a1746b/e86aa/mdn-animations.png 1482w&quot;
          sizes=&quot;(max-width: 710px) 100vw, 710px&quot;
          type=&quot;image/png&quot;
        /&gt;
        &lt;img
          class=&quot;gatsby-resp-image-image&quot;
          style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
          src=&quot;/static/6d6e5c848c1c40f7193906dc96a1746b/d27e1/mdn-animations.png&quot;
          alt=&quot;MDN browser support&quot;
          title=&quot;MDN browser support&quot;
        /&gt;
      &lt;/picture&gt;
  &lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://caniuse.com/#feat=css-animation&quot;&gt;&lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 710px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 34.19811320754717%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAYAAAAIy204AAAACXBIWXMAABYlAAAWJQFJUiTwAAAB4klEQVQozz2RzW8SQRjG+aP07smLFz2Y9GCaptRWk5qYpkaPfsRDD56siWnTEKyaViVt0YItaDUUWmBZF5ZSCrt8dWGBXXCLMSb98OeAxsOTZ96Z9/3NkxmXoSWpHsSp5LZp5KN0DxW6xj/V08LTHJnqf/WaWZxGhmYpKVzFMTM0agk6RopWOYmrfRDC3Funru3S6EtP0K4qtMsp7Gq/SRpAeq0sP1p7HDUFuKUKgCLW2UFtNWTRo4rzLK5ufg0r+4amGGzoElZF4vuhim2omALYT2hXZeyaLFIl6NXEYEWlW0nRFAGcyjeckiIuTlHOx3DZtX2sch5DFxuFOHU9ilmM8HDnEZfDbnb31zHFs1haAqcgsZlexpN4RqH4lU5FIZRb4qUyS7UUo6WJhFuZZXzxee6FpxnZcDO5cYub4UmuvB/igv8So8Ex3JvjeGNPCclLDAdHOee/yIrvMdV3C4ytjHBe1HORGQLyIq4vWR8+aYHVpIc12ctU6DZDwWEmPt4QoAmmQ1Pc3brD9eA4VwPXWNyZJSRCpD7Mob19zueol0D6NasJD37lBa5jq8CZrXNqa9Ap8yo3zwPpPk+UmYFrxjbHVhG19omIvoYjPuS36P/l6PzslTjpaJxaGmedv4w/3pzROKz5pRYAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;picture&gt;
        &lt;source
          srcset=&quot;/static/ffed71b7ef099acd46dc0dadbca02213/98976/caniuse-animations.webp 178w,
/static/ffed71b7ef099acd46dc0dadbca02213/59b7f/caniuse-animations.webp 355w,
/static/ffed71b7ef099acd46dc0dadbca02213/535f3/caniuse-animations.webp 710w,
/static/ffed71b7ef099acd46dc0dadbca02213/c70df/caniuse-animations.webp 1065w,
/static/ffed71b7ef099acd46dc0dadbca02213/ce8e6/caniuse-animations.webp 1420w,
/static/ffed71b7ef099acd46dc0dadbca02213/8b644/caniuse-animations.webp 2130w,
/static/ffed71b7ef099acd46dc0dadbca02213/e6c77/caniuse-animations.webp 2544w&quot;
          sizes=&quot;(max-width: 710px) 100vw, 710px&quot;
          type=&quot;image/webp&quot;
        /&gt;
        &lt;source
          srcset=&quot;/static/ffed71b7ef099acd46dc0dadbca02213/3dc0b/caniuse-animations.png 178w,
/static/ffed71b7ef099acd46dc0dadbca02213/55102/caniuse-animations.png 355w,
/static/ffed71b7ef099acd46dc0dadbca02213/d27e1/caniuse-animations.png 710w,
/static/ffed71b7ef099acd46dc0dadbca02213/afdd0/caniuse-animations.png 1065w,
/static/ffed71b7ef099acd46dc0dadbca02213/beee1/caniuse-animations.png 1420w,
/static/ffed71b7ef099acd46dc0dadbca02213/495d5/caniuse-animations.png 2130w,
/static/ffed71b7ef099acd46dc0dadbca02213/c5232/caniuse-animations.png 2544w&quot;
          sizes=&quot;(max-width: 710px) 100vw, 710px&quot;
          type=&quot;image/png&quot;
        /&gt;
        &lt;img
          class=&quot;gatsby-resp-image-image&quot;
          style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
          src=&quot;/static/ffed71b7ef099acd46dc0dadbca02213/d27e1/caniuse-animations.png&quot;
          alt=&quot;Can I use browser support&quot;
          title=&quot;Can I use browser support&quot;
        /&gt;
      &lt;/picture&gt;
  &lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;MDN is a great learning resources for understanding CSS properties and rules. There’s also a really helpful guide on using CSS animations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en/docs/Web/CSS/@keyframes&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@keyframes&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/animation&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;animation&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations&quot;&gt;Using CSS Animations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Managing Keybase private key with GPGTools]]></title><description><![CDATA[Import and manage your Keybase keys from with GPGTools. Use your Keybase keys to sign Git commits and show as verified on GitHub.]]></description><link>https://benbooth.dev/managing-keybase-private-key-with-gpgtools</link><guid isPermaLink="false">https://benbooth.dev/managing-keybase-private-key-with-gpgtools</guid><dc:creator><![CDATA[Ben Booth]]></dc:creator><pubDate>Wed, 08 Feb 2017 13:07:00 GMT</pubDate><content:encoded>&lt;p&gt;This is not a particularly well-written article. I’ve found everything here useful, but so irregularly that I always end up Googling and needing to put together info from multiple blog posts so I’m putting it all together here for my reference, and maybe it’ll help you if you stumbled across it. &lt;del&gt;At some stage I’ll organise this into a proper article.&lt;/del&gt; &lt;em&gt;[Update 2017-04-07]&lt;/em&gt; I’ll probably never actually update this article.&lt;/p&gt;
&lt;h2&gt;Import your &lt;a href=&quot;https://keybase.io/&quot; title=&quot;Keybase&quot;&gt;Keybase&lt;/a&gt; key into &lt;a href=&quot;https://gpgtools.org/&quot; title=&quot;GPGTools&quot;&gt;GPGTools&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Export your existing public and private keys from &lt;a href=&quot;https://keybase.io/&quot; title=&quot;Keybase&quot;&gt;Keybase&lt;/a&gt;, save them locally as &lt;code class=&quot;language-text&quot;&gt;keybase-public.key&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;keybase-private.key&lt;/code&gt; respectively.&lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/71c9dbb66cb9d1c83fefad67104f3d70/57f15/Screen-Shot-2017-02-08-at-11.23.16-pm.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 688px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 57.84883720930233%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABYlAAAWJQFJUiTwAAABvElEQVQoz6VSy3LbMAzU/39c20umaRMntmW7E4kS3y/J5AaglKanHlqOdgAI5BJcoBPTBBEBESqmAIwElYA3D5gMDGTdAoR1s2vBX1c3zRLjTjjHApsrHawtNqlCxoq4VvhcoCif7xWolb5PlFIa2O9O5x43IuxlRvAO3lk4QiD4BgNnze5bWGNgCNZaaK2b9d4jhEDnHDopJdYlY57nlnwbBgghMBKU0pBKNdt82ssxQ2uzW01kETHGlu8GIrCpYJhU++nplugZFmtODfdls3wx+y0mlA8/RyyUl1Kh6y+39uTzFGnTgrysrRmsoSYNXd50ZD05Hj1p3fSu1LAt5r3cNJajs87j5oCbTIikgzIWRwP8nCtOGr/xokhn+n+QoAu2SeAJEG0y6GImJK271+MJAyWvc0ROCdYH9JYq1hW/XMXFVtwsk1dc7YZEXV9LxbKDfV7crO7L128QxN7TELIO1sdG+CKZaKvqYj4rPe74qPbHVPE8M/Fe4Z+EOUVoF+i5vLHgVVV8FxVPdOBRbP4jERzkRsL+w7j9T3e08eqeng8YqQm98Pjf1Z587i+N8DoHmsWpzeO/gufwHTW9nXAwof1NAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;picture&gt;
        &lt;source
          srcset=&quot;/static/71c9dbb66cb9d1c83fefad67104f3d70/98976/Screen-Shot-2017-02-08-at-11.23.16-pm.webp 178w,
/static/71c9dbb66cb9d1c83fefad67104f3d70/59b7f/Screen-Shot-2017-02-08-at-11.23.16-pm.webp 355w,
/static/71c9dbb66cb9d1c83fefad67104f3d70/e79fb/Screen-Shot-2017-02-08-at-11.23.16-pm.webp 688w&quot;
          sizes=&quot;(max-width: 688px) 100vw, 688px&quot;
          type=&quot;image/webp&quot;
        /&gt;
        &lt;source
          srcset=&quot;/static/71c9dbb66cb9d1c83fefad67104f3d70/3dc0b/Screen-Shot-2017-02-08-at-11.23.16-pm.png 178w,
/static/71c9dbb66cb9d1c83fefad67104f3d70/55102/Screen-Shot-2017-02-08-at-11.23.16-pm.png 355w,
/static/71c9dbb66cb9d1c83fefad67104f3d70/57f15/Screen-Shot-2017-02-08-at-11.23.16-pm.png 688w&quot;
          sizes=&quot;(max-width: 688px) 100vw, 688px&quot;
          type=&quot;image/png&quot;
        /&gt;
        &lt;img
          class=&quot;gatsby-resp-image-image&quot;
          style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
          src=&quot;/static/71c9dbb66cb9d1c83fefad67104f3d70/57f15/Screen-Shot-2017-02-08-at-11.23.16-pm.png&quot;
          alt=&quot;Export private key from Keybase&quot;
          title=&quot;&quot;
        /&gt;
      &lt;/picture&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Import both keys into your local &lt;a href=&quot;https://gpgtools.org/&quot; title=&quot;GPGTools&quot;&gt;GPGTools&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ gpg --allow-secret-key-import --import keybase-private.key
$ gpg --import keybase-public.key&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Delete both the public and private key files.&lt;/p&gt;
&lt;p&gt;Optionally, edit &lt;code class=&quot;language-text&quot;&gt;~/.gnupg/gpg.conf&lt;/code&gt; to set the default key. Firstly get the ID of the key:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ gpg --list-secret-keys&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then add it to &lt;code class=&quot;language-text&quot;&gt;~/.gnupg/gpg.conf&lt;/code&gt; with this line:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ default-key &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;YOUR_KEY_ID&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Update the key with &lt;code class=&quot;language-text&quot;&gt;gpg&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Make any required changes to the key with the &lt;code class=&quot;language-text&quot;&gt;gpg&lt;/code&gt; command-line tool:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ gpg --edit-key &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;YOUR_KEY_ID&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Some useful &lt;code class=&quot;language-text&quot;&gt;gpg&gt;&lt;/code&gt; commands are:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;none&quot;&gt;&lt;pre class=&quot;language-none&quot;&gt;&lt;code class=&quot;language-none&quot;&gt;help    - show help
list    - list key and user IDs
uid N   - select user ID N
adduid  - add a user ID
deluid  - delete selected user IDs
trust   - change the ownertrust
save    - commit your changes and quit&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Don’t forget to &lt;code class=&quot;language-text&quot;&gt;save&lt;/code&gt; after making your changes!&lt;/p&gt;
&lt;h2&gt;Push the updated key to &lt;a href=&quot;https://keybase.io/&quot; title=&quot;Keybase&quot;&gt;Keybase&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that you’ve updated your local copy of the key, push it back to &lt;a href=&quot;https://keybase.io/&quot; title=&quot;Keybase&quot;&gt;Keybase&lt;/a&gt; with:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ keybase pgp update&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Export the updated public key to &lt;a href=&quot;https://github.com/&quot; title=&quot;GitHub&quot;&gt;GitHub&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Export your local key to the clipboard with:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ keybase pgp &lt;span class=&quot;token builtin class-name&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; pbcopy&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Go to &lt;a href=&quot;https://github.com/&quot; title=&quot;GitHub&quot;&gt;GitHub&lt;/a&gt; &gt; &lt;a href=&quot;https://github.com/settings/profile&quot;&gt;Settings&lt;/a&gt; &gt; &lt;a href=&quot;https://github.com/settings/keys&quot;&gt;SSH and GPG keys&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/04c283b2cc5383bb08ca30411e55fdf6/9441e/Screen-Shot-2017-02-08-at-11.52.57-pm.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 710px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 33.06666666666666%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAHABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAIF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAdywkSf/xAAYEAACAwAAAAAAAAAAAAAAAAAAARARIf/aAAgBAQABBQLYpH//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAWEAADAAAAAAAAAAAAAAAAAAAAEDH/2gAIAQEABj8CUP/EABcQAAMBAAAAAAAAAAAAAAAAAAARYTH/2gAIAQEAAT8h0hUkP//aAAwDAQACAAMAAAAQg/8A/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAER/9oACAEDAQE/EGR//8QAFhEBAQEAAAAAAAAAAAAAAAAAAAER/9oACAECAQE/EGR//8QAGhABAAMAAwAAAAAAAAAAAAAAAQARQSFRcf/aAAgBAQABPxApQAewWqciqLvc/9k=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;picture&gt;
        &lt;source
          srcset=&quot;/static/04c283b2cc5383bb08ca30411e55fdf6/98976/Screen-Shot-2017-02-08-at-11.52.57-pm.webp 178w,
/static/04c283b2cc5383bb08ca30411e55fdf6/59b7f/Screen-Shot-2017-02-08-at-11.52.57-pm.webp 355w,
/static/04c283b2cc5383bb08ca30411e55fdf6/535f3/Screen-Shot-2017-02-08-at-11.52.57-pm.webp 710w,
/static/04c283b2cc5383bb08ca30411e55fdf6/c70df/Screen-Shot-2017-02-08-at-11.52.57-pm.webp 1065w,
/static/04c283b2cc5383bb08ca30411e55fdf6/ce8e6/Screen-Shot-2017-02-08-at-11.52.57-pm.webp 1420w,
/static/04c283b2cc5383bb08ca30411e55fdf6/75b29/Screen-Shot-2017-02-08-at-11.52.57-pm.webp 1500w&quot;
          sizes=&quot;(max-width: 710px) 100vw, 710px&quot;
          type=&quot;image/webp&quot;
        /&gt;
        &lt;source
          srcset=&quot;/static/04c283b2cc5383bb08ca30411e55fdf6/edc7c/Screen-Shot-2017-02-08-at-11.52.57-pm.jpg 178w,
/static/04c283b2cc5383bb08ca30411e55fdf6/ace09/Screen-Shot-2017-02-08-at-11.52.57-pm.jpg 355w,
/static/04c283b2cc5383bb08ca30411e55fdf6/af774/Screen-Shot-2017-02-08-at-11.52.57-pm.jpg 710w,
/static/04c283b2cc5383bb08ca30411e55fdf6/fa28b/Screen-Shot-2017-02-08-at-11.52.57-pm.jpg 1065w,
/static/04c283b2cc5383bb08ca30411e55fdf6/cbe48/Screen-Shot-2017-02-08-at-11.52.57-pm.jpg 1420w,
/static/04c283b2cc5383bb08ca30411e55fdf6/9441e/Screen-Shot-2017-02-08-at-11.52.57-pm.jpg 1500w&quot;
          sizes=&quot;(max-width: 710px) 100vw, 710px&quot;
          type=&quot;image/jpeg&quot;
        /&gt;
        &lt;img
          class=&quot;gatsby-resp-image-image&quot;
          style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
          src=&quot;/static/04c283b2cc5383bb08ca30411e55fdf6/af774/Screen-Shot-2017-02-08-at-11.52.57-pm.jpg&quot;
          alt=&quot;Manage GPG keys on GitHub&quot;
          title=&quot;&quot;
        /&gt;
      &lt;/picture&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Add a ‘New GPG key’, or ‘Delete’ your existing one first if you’re updating it.&lt;/p&gt;
&lt;h2&gt;Signing Git commits with your &lt;a href=&quot;https://keybase.io/&quot; title=&quot;Keybase&quot;&gt;Keybase&lt;/a&gt; key&lt;/h2&gt;
&lt;p&gt;Add &lt;code class=&quot;language-text&quot;&gt;-S [YOUR_KEY_ID]&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;--gpg-sign=[YOUR_KEY_ID]&lt;/code&gt; to your &lt;code class=&quot;language-text&quot;&gt;git commit&lt;/code&gt; commands to sign the commit using the specified key. You can replace &lt;code class=&quot;language-text&quot;&gt;[YOUR_KEY_ID]&lt;/code&gt; with any email address added as a uid in the key.&lt;/p&gt;
&lt;p&gt;Run these lines to update your global config to sign git commits by default:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; config --global user.signingkey &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;YOUR_KEY_ID&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
$ &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; config --global core.gpgsign &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;These can additionally be set or unset on a per-project basis.&lt;/p&gt;
&lt;p&gt;Adding &lt;code class=&quot;language-text&quot;&gt;--no-gpg-sign&lt;/code&gt; to a &lt;code class=&quot;language-text&quot;&gt;git commit&lt;/code&gt; command will turn off signing for that commit only.&lt;/p&gt;
&lt;p&gt;Adding &lt;code class=&quot;language-text&quot;&gt;--show-signature&lt;/code&gt; to &lt;code class=&quot;language-text&quot;&gt;git log&lt;/code&gt; commands will show signatures in the git commit log.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Building a basic UI-clone of Instagram using Elm - Part 3]]></title><description><![CDATA[I've had a fascination with functional programming for a few years but never really jumped in with any language. Elm seems like a good jumping on point so follow along as I learn Elm while building a basic web app. Here I build the single post view and add the comments form.]]></description><link>https://benbooth.dev/building-a-basic-ui-clone-of-instagram-using-elm-part-3</link><guid isPermaLink="false">https://benbooth.dev/building-a-basic-ui-clone-of-instagram-using-elm-part-3</guid><dc:creator><![CDATA[Ben Booth]]></dc:creator><pubDate>Wed, 07 Dec 2016 12:34:00 GMT</pubDate><content:encoded>&lt;p&gt;This article is a part of a series, you should read &lt;a href=&quot;/building-a-basic-ui-clone-of-instagram-using-elm-part-1/&quot;&gt;part 1&lt;/a&gt; and &lt;a href=&quot;/building-a-basic-ui-clone-of-instagram-using-elm-part-2/&quot;&gt;part 2&lt;/a&gt; if you haven’t already. Alternatively you can get the code from the end of the last article &lt;a href=&quot;https://github.com/bkbooth/Elmstagram/tree/part2&quot;&gt;here&lt;/a&gt; and continue along. You can view the finished app &lt;a href=&quot;https://elmstagram.benbooth.dev&quot; title=&quot;Elmstagram | Demo&quot;&gt;here&lt;/a&gt; and all of the source code is available &lt;a href=&quot;https://github.com/bkbooth/Elmstagram&quot; title=&quot;Elmstagram | GitHub&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Implement the single post view&lt;/h2&gt;
&lt;p&gt;Now that we can navigate to a new page/view, let’s start building out the view properly. If you recall where we left off, the &lt;code class=&quot;language-text&quot;&gt;SinglePost&lt;/code&gt; case in &lt;code class=&quot;language-text&quot;&gt;View.viewPage&lt;/code&gt; was just rendering the &lt;code class=&quot;language-text&quot;&gt;postId&lt;/code&gt; that was parsed from the URL. We need to use this &lt;code class=&quot;language-text&quot;&gt;postId&lt;/code&gt; to find the right &lt;code class=&quot;language-text&quot;&gt;Post&lt;/code&gt; in &lt;code class=&quot;language-text&quot;&gt;model.posts&lt;/code&gt;. We’ll define a &lt;code class=&quot;language-text&quot;&gt;View.getPost&lt;/code&gt; helper function to do this now.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- View.elm&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;getPost&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Maybe&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;getPost&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;posts&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt;
        &lt;span class=&quot;token hvariable&quot;&gt;postsById&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;List.filter&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;\&lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;posts&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt;
        &lt;span class=&quot;token hvariable&quot;&gt;List.head&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postsById&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We need to return a &lt;code class=&quot;language-text&quot;&gt;Maybe Post&lt;/code&gt; because the &lt;code class=&quot;language-text&quot;&gt;postId&lt;/code&gt; string parsed from the URL might not be a valid &lt;code class=&quot;language-text&quot;&gt;Post.id&lt;/code&gt;, or there might just not be a &lt;code class=&quot;language-text&quot;&gt;Post&lt;/code&gt; in &lt;code class=&quot;language-text&quot;&gt;model.posts&lt;/code&gt; that matches the &lt;code class=&quot;language-text&quot;&gt;postId&lt;/code&gt;. We approach the problem by filtering the list to &lt;code class=&quot;language-text&quot;&gt;Post&lt;/code&gt;s with a &lt;code class=&quot;language-text&quot;&gt;Post.id&lt;/code&gt; matching &lt;code class=&quot;language-text&quot;&gt;postId&lt;/code&gt; which should leave 1 or 0 &lt;code class=&quot;language-text&quot;&gt;Post&lt;/code&gt;s in the &lt;code class=&quot;language-text&quot;&gt;postsById&lt;/code&gt; list (we’re trusting the data source here that &lt;code class=&quot;language-text&quot;&gt;Post.id&lt;/code&gt; is unique), then we take the first item from the filtered list, which will return a &lt;code class=&quot;language-text&quot;&gt;Maybe Post&lt;/code&gt;. Now let’s update the &lt;code class=&quot;language-text&quot;&gt;SinglePost&lt;/code&gt; case of &lt;code class=&quot;language-text&quot;&gt;View.viewPage&lt;/code&gt; to use &lt;code class=&quot;language-text&quot;&gt;View.getPost&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;View.viewPost&lt;/code&gt; to render a single post.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- View.elm&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;viewPage&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Html&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;viewPage&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt;
        &lt;span class=&quot;token constant&quot;&gt;ListOfPosts&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;-- ...&lt;/span&gt;

        &lt;span class=&quot;token constant&quot;&gt;SinglePost&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;getPost&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;posts&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt;
                &lt;span class=&quot;token constant&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
                    &lt;span class=&quot;token hvariable&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;photo-single&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;viewPost&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

                &lt;span class=&quot;token constant&quot;&gt;Nothing&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
                    &lt;span class=&quot;token hvariable&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Post &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot; not found.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You should be able to recompile and open the app in the browser now and the &lt;code class=&quot;language-text&quot;&gt;SinglePost&lt;/code&gt; view will render a single post, which is fun, but no more useful than the &lt;code class=&quot;language-text&quot;&gt;ListOfPosts&lt;/code&gt; view. We’ll load and display the list of comments (if any) on the &lt;code class=&quot;language-text&quot;&gt;SinglePost&lt;/code&gt; view next.&lt;/p&gt;
&lt;h2&gt;Load and display comments&lt;/h2&gt;
&lt;p&gt;We’ve got a bit of work to do in order to load the comments, but thankfully it’s all derivative of things we’ve already done. Firstly, download all of the &lt;em&gt;*.json&lt;/em&gt; files from &lt;a href=&quot;https://github.com/bkbooth/Elmstagram/tree/resources/data&quot;&gt;here&lt;/a&gt; and save them to &lt;em&gt;data/*.json&lt;/em&gt;. If you inspect one of the files you’ll notice that it’s filename is a &lt;em&gt;{Post.id}.json&lt;/em&gt; and the &lt;a href=&quot;https://en.wikipedia.org/wiki/JSON&quot; title=&quot;JSON&quot;&gt;JSON&lt;/a&gt; data looks like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  ...&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;17856770641073526&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;username&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tiktoktikkdotcom&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1478756236&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;This is definitely first rated!&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  ...
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Basically for each &lt;code class=&quot;language-text&quot;&gt;Post&lt;/code&gt; we have a &lt;em&gt;{Post.id}.json&lt;/em&gt; with the list of comments for that post. We only care about the &lt;code class=&quot;language-text&quot;&gt;&quot;username&quot;&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;&quot;text&quot;&lt;/code&gt; properties for now, let’s firstly define a &lt;code class=&quot;language-text&quot;&gt;type alias&lt;/code&gt; in &lt;em&gt;Types.elm&lt;/em&gt; and a decoder in &lt;em&gt;Rest.elm&lt;/em&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Types.elm&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Comment&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;username&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Rest.elm&lt;/span&gt;

&lt;span class=&quot;token import-statement&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Types &lt;span class=&quot;token keyword&quot;&gt;exposing&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Comment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;decodeComments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Json.Decoder&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Comment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;decodeComments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token hvariable&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt;
        &lt;span class=&quot;token hvariable&quot;&gt;map2&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Comment&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;username&quot;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;text&quot;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Most of this is pretty similar to what we already did with with the &lt;code class=&quot;language-text&quot;&gt;Post&lt;/code&gt; type and decoder. Notice that we’ve used &lt;code class=&quot;language-text&quot;&gt;Json.Decoder.map2&lt;/code&gt; to extract two properties from each &lt;a href=&quot;https://en.wikipedia.org/wiki/JSON&quot; title=&quot;JSON&quot;&gt;JSON&lt;/a&gt; object. While we’re in &lt;em&gt;Rest.elm&lt;/em&gt; let’s also add a function that takes a &lt;code class=&quot;language-text&quot;&gt;Post.id&lt;/code&gt; and loads it’s associated &lt;a href=&quot;https://en.wikipedia.org/wiki/JSON&quot; title=&quot;JSON&quot;&gt;JSON&lt;/a&gt; comments file.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Rest.elm&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;getPostComments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Cmd&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;getPostComments&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token hvariable&quot;&gt;Http.send&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;FetchComments&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt;
        &lt;span class=&quot;token hvariable&quot;&gt;Http.get&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;data/&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;decodeComments&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Again this is pretty similar to &lt;code class=&quot;language-text&quot;&gt;Rest.getPosts&lt;/code&gt; that we defined previously, except that we’re taking a &lt;code class=&quot;language-text&quot;&gt;postId&lt;/code&gt; parameter, and we also pass the &lt;code class=&quot;language-text&quot;&gt;postId&lt;/code&gt; through to the &lt;code class=&quot;language-text&quot;&gt;FetchComments&lt;/code&gt; action. We should now add &lt;code class=&quot;language-text&quot;&gt;FetchComments&lt;/code&gt; to the &lt;code class=&quot;language-text&quot;&gt;Types.Msg&lt;/code&gt; union type and while we’re in &lt;em&gt;Types.elm&lt;/em&gt; we should add the lists of &lt;code class=&quot;language-text&quot;&gt;Comment&lt;/code&gt;s to &lt;code class=&quot;language-text&quot;&gt;Types.Model&lt;/code&gt; and update &lt;code class=&quot;language-text&quot;&gt;Types.initialModel&lt;/code&gt; to initialise it. We’ll store the lists of &lt;code class=&quot;language-text&quot;&gt;Comment&lt;/code&gt;s in a &lt;code class=&quot;language-text&quot;&gt;Dict&lt;/code&gt; which is provided by &lt;a href=&quot;https://package.elm-lang.org/packages/elm-lang/core/latest&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;elm-lang/core&lt;/code&gt;&lt;/a&gt;, but we need to &lt;code class=&quot;language-text&quot;&gt;import&lt;/code&gt; it before we can use it. The keys in our &lt;code class=&quot;language-text&quot;&gt;Dict&lt;/code&gt; will be &lt;code class=&quot;language-text&quot;&gt;Post.id&lt;/code&gt;s and the values will be &lt;code class=&quot;language-text&quot;&gt;List Comment&lt;/code&gt;. Note that &lt;code class=&quot;language-text&quot;&gt;Dict.empty&lt;/code&gt; just initialises an empty &lt;code class=&quot;language-text&quot;&gt;Dict&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Types.elm&lt;/span&gt;

&lt;span class=&quot;token import-statement&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Dict &lt;span class=&quot;token keyword&quot;&gt;exposing&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Dict&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;posts&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Dict&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Comment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Page&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;initialModel&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Page&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;initialModel&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;Dict.empty&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;page&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;FetchPosts&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Result&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Http.Error&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;FetchComments&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Result&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Http.Error&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Comment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;-- ...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we should move onto &lt;em&gt;State.elm&lt;/em&gt; to handle the &lt;code class=&quot;language-text&quot;&gt;FetchComments&lt;/code&gt; action in &lt;code class=&quot;language-text&quot;&gt;State.update&lt;/code&gt;, don’t forget to &lt;code class=&quot;language-text&quot;&gt;import Dict&lt;/code&gt; here too.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- State.elm&lt;/span&gt;

&lt;span class=&quot;token import-statement&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Dict &lt;span class=&quot;token keyword&quot;&gt;exposing&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Dict&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Cmd&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;-- ...&lt;/span&gt;

        &lt;span class=&quot;token constant&quot;&gt;FetchComments&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Ok&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;Dict.insert&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;posts&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;List.map&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;setPostComments&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;List.length&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;posts&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

        &lt;span class=&quot;token constant&quot;&gt;FetchComments&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Err&lt;/span&gt; _&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token hvariable&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;FetchComments&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Ok&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;setPostComments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;setPostComments&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;numberOfComments&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;then&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;numberOfComments&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
        &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Just like with &lt;code class=&quot;language-text&quot;&gt;FetchPosts&lt;/code&gt;, we actually get a &lt;code class=&quot;language-text&quot;&gt;Result&lt;/code&gt; and need to handle the &lt;code class=&quot;language-text&quot;&gt;Err&lt;/code&gt; case as well as the &lt;code class=&quot;language-text&quot;&gt;Ok&lt;/code&gt; case. I decided that for the &lt;code class=&quot;language-text&quot;&gt;Err&lt;/code&gt; case we’d just call update again but this time passing &lt;code class=&quot;language-text&quot;&gt;Ok []&lt;/code&gt;, which as we’ll see next will initialise the &lt;code class=&quot;language-text&quot;&gt;Dict&lt;/code&gt; entry for the given &lt;code class=&quot;language-text&quot;&gt;postId&lt;/code&gt; to an empty list of &lt;code class=&quot;language-text&quot;&gt;Comment&lt;/code&gt;s. The &lt;code class=&quot;language-text&quot;&gt;Ok&lt;/code&gt; case needs to do two things, firstly we insert the list of &lt;code class=&quot;language-text&quot;&gt;Comment&lt;/code&gt;s into the &lt;code class=&quot;language-text&quot;&gt;Dict&lt;/code&gt; with &lt;code class=&quot;language-text&quot;&gt;Dict.insert&lt;/code&gt;, then we need to update the counter in the &lt;code class=&quot;language-text&quot;&gt;Post.comments&lt;/code&gt; property of the &lt;code class=&quot;language-text&quot;&gt;Post&lt;/code&gt; with a &lt;code class=&quot;language-text&quot;&gt;Post.id&lt;/code&gt; matching &lt;code class=&quot;language-text&quot;&gt;postId&lt;/code&gt;. Unlike the &lt;code class=&quot;language-text&quot;&gt;IncremementLikes&lt;/code&gt; case where we defined a helper function inside the &lt;code class=&quot;language-text&quot;&gt;case&lt;/code&gt; block, we define &lt;code class=&quot;language-text&quot;&gt;setPostComments&lt;/code&gt; separately because we’ll be reusing this function when we add and remove comments. &lt;code class=&quot;language-text&quot;&gt;setPostComments&lt;/code&gt; takes a &lt;code class=&quot;language-text&quot;&gt;Post.id&lt;/code&gt;, an updated number of &lt;code class=&quot;language-text&quot;&gt;Comment&lt;/code&gt;s and a &lt;code class=&quot;language-text&quot;&gt;Post&lt;/code&gt;, we use it in the &lt;code class=&quot;language-text&quot;&gt;FetchComments&lt;/code&gt; case to &lt;code class=&quot;language-text&quot;&gt;List.map&lt;/code&gt; over &lt;code class=&quot;language-text&quot;&gt;model.posts&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The final change that we need to make in &lt;em&gt;State.elm&lt;/em&gt; is to actually load the &lt;code class=&quot;language-text&quot;&gt;Comment&lt;/code&gt;s by calling &lt;code class=&quot;language-text&quot;&gt;Rest.getPostComments&lt;/code&gt;. In both &lt;code class=&quot;language-text&quot;&gt;State.init&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;State.update&lt;/code&gt; we’ll split the &lt;code class=&quot;language-text&quot;&gt;Just page&lt;/code&gt; case to have slightly different behaviour for &lt;code class=&quot;language-text&quot;&gt;Just ListOfPosts&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;Just SinglePost&lt;/code&gt;. &lt;code class=&quot;language-text&quot;&gt;Just ListOfPosts&lt;/code&gt; will basically be the same as the current &lt;code class=&quot;language-text&quot;&gt;Just page&lt;/code&gt; case in both cases, but for &lt;code class=&quot;language-text&quot;&gt;Just SinglePost&lt;/code&gt; we’ll want to call &lt;code class=&quot;language-text&quot;&gt;Rest.getPostComments&lt;/code&gt; in both cases.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- State.elm&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;init&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;Navigation.location&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Cmd&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;init&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;UrlParser.parseHash&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;pageParser&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt;
        &lt;span class=&quot;token constant&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ListOfPosts&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token hvariable&quot;&gt;initialModel&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ListOfPosts&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;Rest.getPosts&lt;/span&gt;
                  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

        &lt;span class=&quot;token constant&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;SinglePost&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token hvariable&quot;&gt;initialModel&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;SinglePost&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;Rest.getPosts&lt;/span&gt;
                  &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;Rest.getPostComments&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt;
                  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

        &lt;span class=&quot;token constant&quot;&gt;Nothing&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;-- ...&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Cmd&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;-- ...&lt;/span&gt;

        &lt;span class=&quot;token constant&quot;&gt;NavigatedTo&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;maybePage&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;maybePage&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
                &lt;span class=&quot;token constant&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ListOfPosts&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ListOfPosts&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
                        &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

                &lt;span class=&quot;token constant&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;SinglePost&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SinglePost&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
                        &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;Rest.getPostComments&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt;
                          &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

                &lt;span class=&quot;token constant&quot;&gt;Nothing&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
                    &lt;span class=&quot;token comment&quot;&gt;-- ...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we need to actually show the comments. Firstly we’ll define a &lt;code class=&quot;language-text&quot;&gt;getPostComments&lt;/code&gt; helper function to return a &lt;code class=&quot;language-text&quot;&gt;List Comment&lt;/code&gt; from &lt;code class=&quot;language-text&quot;&gt;model.comments&lt;/code&gt;. Because &lt;code class=&quot;language-text&quot;&gt;Dict.get&lt;/code&gt; returns a &lt;code class=&quot;language-text&quot;&gt;Maybe&lt;/code&gt; we need to handle the &lt;code class=&quot;language-text&quot;&gt;Nothing&lt;/code&gt; case, we’ll just return an empty &lt;code class=&quot;language-text&quot;&gt;List&lt;/code&gt;. Don’t forgot to &lt;code class=&quot;language-text&quot;&gt;import Dict&lt;/code&gt; here too.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- View.elm&lt;/span&gt;

&lt;span class=&quot;token import-statement&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Dict &lt;span class=&quot;token keyword&quot;&gt;exposing&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Dict&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;getPostComments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Dict&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Comment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Comment&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;getPostComments&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;Dict.get&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt;
        &lt;span class=&quot;token constant&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postComments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token hvariable&quot;&gt;postComments&lt;/span&gt;

        &lt;span class=&quot;token constant&quot;&gt;Nothing&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next we need to make some changes to the existing &lt;code class=&quot;language-text&quot;&gt;View.viewPost&lt;/code&gt; function. We’ll determine if we should show the list of &lt;code class=&quot;language-text&quot;&gt;Comment&lt;/code&gt;s by inspecting &lt;code class=&quot;language-text&quot;&gt;model.page&lt;/code&gt;, we only want to show them for the &lt;code class=&quot;language-text&quot;&gt;SinglePost&lt;/code&gt; case, so we’ll just show an empty &lt;code class=&quot;language-text&quot;&gt;div&lt;/code&gt; for the &lt;code class=&quot;language-text&quot;&gt;ListOfPosts&lt;/code&gt; case. We’ll add the comments directly after &lt;code class=&quot;language-text&quot;&gt;p.photo-caption&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- View.elm&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;viewPost&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Html&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;viewPost&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt;
        &lt;span class=&quot;token hvariable&quot;&gt;displayComments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt;
                &lt;span class=&quot;token constant&quot;&gt;SinglePost&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
                    &lt;span class=&quot;token hvariable&quot;&gt;viewComments&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt;

                &lt;span class=&quot;token constant&quot;&gt;ListOfPosts&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
                    &lt;span class=&quot;token hvariable&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;-- ...&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;photo-caption&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;displayComments&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;-- ...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally we’ll define the &lt;code class=&quot;language-text&quot;&gt;viewComments&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;viewComment&lt;/code&gt; functions. &lt;code class=&quot;language-text&quot;&gt;viewComment&lt;/code&gt; defines the bulk of the &lt;a href=&quot;https://en.wikipedia.org/wiki/Document_Object_Model&quot; title=&quot;DOM&quot;&gt;DOM&lt;/a&gt; structure, but returns a &lt;code class=&quot;language-text&quot;&gt;(String, Html Msg)&lt;/code&gt; which if you recall is used by &lt;code class=&quot;language-text&quot;&gt;Html.Keyed.node&lt;/code&gt;. In &lt;code class=&quot;language-text&quot;&gt;viewComments&lt;/code&gt; we’ll use &lt;code class=&quot;language-text&quot;&gt;List.indexedMap&lt;/code&gt; to pass an &lt;code class=&quot;language-text&quot;&gt;Int&lt;/code&gt; index as well as the &lt;code class=&quot;language-text&quot;&gt;Comment&lt;/code&gt; through to &lt;code class=&quot;language-text&quot;&gt;viewComment&lt;/code&gt;. &lt;code class=&quot;language-text&quot;&gt;viewComments&lt;/code&gt; then just returns a &lt;code class=&quot;language-text&quot;&gt;Html.Keyed.node&lt;/code&gt; using the list of &lt;a href=&quot;https://en.wikipedia.org/wiki/Document_Object_Model&quot; title=&quot;DOM&quot;&gt;DOM&lt;/a&gt; returned by the &lt;code class=&quot;language-text&quot;&gt;viewComment&lt;/code&gt; calls for each &lt;code class=&quot;language-text&quot;&gt;Comment&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- View.elm&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;viewComments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Html&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;viewComments&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt;
        &lt;span class=&quot;token hvariable&quot;&gt;listOfComments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
            &lt;span class=&quot;token hvariable&quot;&gt;List.indexedMap&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;viewComment&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt;
                &lt;span class=&quot;token hvariable&quot;&gt;getPostComments&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt;
        &lt;span class=&quot;token hvariable&quot;&gt;Html.Keyed.node&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;div&quot;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;comments&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt;
            &lt;span class=&quot;token hvariable&quot;&gt;listOfComments&lt;/span&gt;


&lt;span class=&quot;token hvariable&quot;&gt;viewComment&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Comment&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Html&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;viewComment&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comment&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;toString&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;index&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;comment&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;strong&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;username&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;At this stage you should be able to recompile and test the app in the browser again. When you click through to any of the &lt;code class=&quot;language-text&quot;&gt;SinglePost&lt;/code&gt; views you should see a list of &lt;code class=&quot;language-text&quot;&gt;Comment&lt;/code&gt;s! Let’s remove some of those comments next.&lt;/p&gt;
&lt;h2&gt;Implement the remove comment button&lt;/h2&gt;
&lt;p&gt;We’ll add the ability to remove comments by adding a little inline “x” button after each comment. Using our established pattern we’ll firstly add the &lt;code class=&quot;language-text&quot;&gt;RemoveComment&lt;/code&gt; action to &lt;code class=&quot;language-text&quot;&gt;Types.Msg&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Types.elm&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;-- ...&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;RemoveComment&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Int&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;String&lt;/code&gt; will be a &lt;code class=&quot;language-text&quot;&gt;Post.id&lt;/code&gt; and the &lt;code class=&quot;language-text&quot;&gt;Int&lt;/code&gt; will be an index representing the location of the &lt;code class=&quot;language-text&quot;&gt;Comment&lt;/code&gt; in the &lt;code class=&quot;language-text&quot;&gt;List&lt;/code&gt;. Let’s add the handler for this action in &lt;code class=&quot;language-text&quot;&gt;State.update&lt;/code&gt; now. We’re going to use a function from &lt;code class=&quot;language-text&quot;&gt;List.Extra&lt;/code&gt; which is provided by &lt;a href=&quot;https://package.elm-lang.org/packages/elm-community/list-extra/latest&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;elm-community/list-extra&lt;/code&gt;&lt;/a&gt;, so install it now with &lt;code class=&quot;language-text&quot;&gt;elm package install elm-community/list-extra&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;import List.Extra&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- State.elm&lt;/span&gt;

&lt;span class=&quot;token import-statement&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; List.Extra&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Cmd&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;-- ...&lt;/span&gt;

        &lt;span class=&quot;token constant&quot;&gt;RemoveComment&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt;
                &lt;span class=&quot;token hvariable&quot;&gt;removePostComment&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Maybe&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Comment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Maybe&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Comment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token hvariable&quot;&gt;removePostComment&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
                    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt;
                        &lt;span class=&quot;token constant&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
                            &lt;span class=&quot;token constant&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;List.Extra.removeAt&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt;

                        &lt;span class=&quot;token constant&quot;&gt;Nothing&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
                            &lt;span class=&quot;token constant&quot;&gt;Nothing&lt;/span&gt;

                &lt;span class=&quot;token hvariable&quot;&gt;numberOfPostComments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
                    &lt;span class=&quot;token hvariable&quot;&gt;getNumberOfPostComments&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;
                    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;Dict.update&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;removePostComment&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;posts&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;List.map&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;setPostComments&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;numberOfPostComments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;posts&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;getNumberOfPostComments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Dict&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Comment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Int&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;getNumberOfPostComments&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;Dict.get&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt;
        &lt;span class=&quot;token constant&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postComments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token hvariable&quot;&gt;List.length&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postComments&lt;/span&gt;

        &lt;span class=&quot;token constant&quot;&gt;Nothing&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We need the handler to firstly remove the &lt;code class=&quot;language-text&quot;&gt;Comment&lt;/code&gt; from the right location in &lt;code class=&quot;language-text&quot;&gt;model.comments&lt;/code&gt;, which is determined by the index in the &lt;code class=&quot;language-text&quot;&gt;List Comment&lt;/code&gt; where the &lt;code class=&quot;language-text&quot;&gt;Dict&lt;/code&gt; key matches the passed in &lt;code class=&quot;language-text&quot;&gt;postId&lt;/code&gt;, then it needs to update the comments counter for the right &lt;code class=&quot;language-text&quot;&gt;Post&lt;/code&gt; in &lt;code class=&quot;language-text&quot;&gt;model.posts&lt;/code&gt;. We’ve defined a couple of helper functions for this, firstly &lt;code class=&quot;language-text&quot;&gt;getNumberOfPostComments&lt;/code&gt; which we’ve defined independently because we’ll use it again soon when we want to add a new &lt;code class=&quot;language-text&quot;&gt;Comment&lt;/code&gt;, it just gets the &lt;code class=&quot;language-text&quot;&gt;List Comment&lt;/code&gt; by using &lt;code class=&quot;language-text&quot;&gt;Dict.get&lt;/code&gt; with the passed in &lt;code class=&quot;language-text&quot;&gt;postId&lt;/code&gt;, then either returns the length of the list, or 0 if the &lt;code class=&quot;language-text&quot;&gt;Dict&lt;/code&gt; doesn’t have an entry matching the &lt;code class=&quot;language-text&quot;&gt;postId&lt;/code&gt;. &lt;code class=&quot;language-text&quot;&gt;removePostComment&lt;/code&gt; is defined in the &lt;code class=&quot;language-text&quot;&gt;RemoveComment&lt;/code&gt; handler because it’s only ever used here. We use &lt;code class=&quot;language-text&quot;&gt;List.Extra.removeAt&lt;/code&gt; to attempt to remove from the provided &lt;code class=&quot;language-text&quot;&gt;List&lt;/code&gt; of &lt;code class=&quot;language-text&quot;&gt;Comment&lt;/code&gt;s the item at the provided &lt;code class=&quot;language-text&quot;&gt;index&lt;/code&gt;, it returns the updated &lt;code class=&quot;language-text&quot;&gt;List&lt;/code&gt;. In the &lt;code class=&quot;language-text&quot;&gt;model&lt;/code&gt; record update statement we use &lt;code class=&quot;language-text&quot;&gt;Dict.update&lt;/code&gt; with the &lt;code class=&quot;language-text&quot;&gt;removePostComment&lt;/code&gt; function, then similar to the &lt;code class=&quot;language-text&quot;&gt;FetchComments&lt;/code&gt; handler we use &lt;code class=&quot;language-text&quot;&gt;List.map&lt;/code&gt; with &lt;code class=&quot;language-text&quot;&gt;setPostComments&lt;/code&gt; to update the number of &lt;code class=&quot;language-text&quot;&gt;Comment&lt;/code&gt;s for the given &lt;code class=&quot;language-text&quot;&gt;Post&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Finally let’s add the actual “x” button into the view, just add the following line to &lt;code class=&quot;language-text&quot;&gt;View.viewComment&lt;/code&gt; immediately after &lt;code class=&quot;language-text&quot;&gt;, text comment.text&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- View.elm&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;viewComment&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Comment&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Html&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;viewComment&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comment&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;-- ...&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;onClick&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;RemoveComment&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;remove-comment&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;×&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;-- ...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Recompile and open the app in your browser, click through to one of the &lt;code class=&quot;language-text&quot;&gt;SinglePost&lt;/code&gt; views and remove comments to your heart’s content by clicking the little “x” button next to each comment. You might notice that if you remove some comments, navigate back to the &lt;code class=&quot;language-text&quot;&gt;ListOfPosts&lt;/code&gt; view and then back to the same &lt;code class=&quot;language-text&quot;&gt;SinglePost&lt;/code&gt; view, the comments that you just removed will all be back! This is because we always load the list of &lt;code class=&quot;language-text&quot;&gt;Comment&lt;/code&gt;s when we navigate to the &lt;code class=&quot;language-text&quot;&gt;SinglePost&lt;/code&gt; view. To fix it we’ll update the &lt;code class=&quot;language-text&quot;&gt;Ok&lt;/code&gt; case of &lt;code class=&quot;language-text&quot;&gt;FetchComments&lt;/code&gt; in &lt;code class=&quot;language-text&quot;&gt;State.update&lt;/code&gt; to check if there’s an existing entry in &lt;code class=&quot;language-text&quot;&gt;Dict&lt;/code&gt; for the &lt;code class=&quot;language-text&quot;&gt;postId&lt;/code&gt; and only update the &lt;code class=&quot;language-text&quot;&gt;model&lt;/code&gt; if it’s a new entry in the &lt;code class=&quot;language-text&quot;&gt;Dict&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- State.elm&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Cmd&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;-- ...&lt;/span&gt;

        &lt;span class=&quot;token constant&quot;&gt;FetchComments&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Ok&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;Dict.get&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt;
                &lt;span class=&quot;token constant&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;existingComments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
                    &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

                &lt;span class=&quot;token constant&quot;&gt;Nothing&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;
                        &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;Dict.insert&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;updatedComments&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;posts&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;List.map&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;setPostComments&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;List.length&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;updatedComments&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;posts&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Recompile and test it in the browser. Removed comments now stay removed! …until you refresh the page, but that’s another story. Let’s move onto the final piece of this puzzle, adding a new comment.&lt;/p&gt;
&lt;h2&gt;Implement the add comment form&lt;/h2&gt;
&lt;p&gt;This last step will require updating text in some input fields. Starting in &lt;em&gt;Types.elm&lt;/em&gt;, we will add and initialise a &lt;code class=&quot;language-text&quot;&gt;newComment&lt;/code&gt; property to the &lt;code class=&quot;language-text&quot;&gt;Model&lt;/code&gt; record and we’ll need 3 new actions in &lt;code class=&quot;language-text&quot;&gt;Msg&lt;/code&gt;, one for each of the two input fields, and one for actually adding the comment.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;--Types.elm&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;posts&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Dict&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Comment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Page&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;newComment&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Comment&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;initialModel&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Page&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;initialModel&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;Dict.empty&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Comment&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;-- ...&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;UpdateCommentUsername&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;UpdateCommentText&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;AddComment&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Comment&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Moving to &lt;em&gt;State.elm&lt;/em&gt;, the two &lt;code class=&quot;language-text&quot;&gt;UpdateComment...&lt;/code&gt; actions are quite simple and basically the same, they just update the corresponding property in &lt;code class=&quot;language-text&quot;&gt;model.newComment&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- State.elm&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Cmd&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;-- ...&lt;/span&gt;

        &lt;span class=&quot;token constant&quot;&gt;UpdateCommentUsername&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;username&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt;
                &lt;span class=&quot;token hvariable&quot;&gt;comment&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;newComment&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;
                    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;newComment&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comment&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;username&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;username&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

        &lt;span class=&quot;token constant&quot;&gt;UpdateCommentText&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt;
                &lt;span class=&quot;token hvariable&quot;&gt;comment&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;newComment&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;
                    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;newComment&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comment&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;AddComment&lt;/code&gt; action is more complex than these, but quite similar to the &lt;code class=&quot;language-text&quot;&gt;RemoveComment&lt;/code&gt; action. The &lt;code class=&quot;language-text&quot;&gt;addPostComment&lt;/code&gt; helper function that we’ll define is also used by &lt;code class=&quot;language-text&quot;&gt;Dict.update&lt;/code&gt;, but either concatenates the new &lt;code class=&quot;language-text&quot;&gt;Comment&lt;/code&gt; onto the existing &lt;code class=&quot;language-text&quot;&gt;List&lt;/code&gt; of &lt;code class=&quot;language-text&quot;&gt;Comment&lt;/code&gt;s or returns a new &lt;code class=&quot;language-text&quot;&gt;List&lt;/code&gt; containing just the new &lt;code class=&quot;language-text&quot;&gt;Comment&lt;/code&gt;. We also need to reset the two input fields after adding the comment.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- State.elm&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Cmd&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;-- ...&lt;/span&gt;

        &lt;span class=&quot;token constant&quot;&gt;AddComment&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comment&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt;
                &lt;span class=&quot;token hvariable&quot;&gt;addPostComment&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Maybe&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Comment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Maybe&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Comment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token hvariable&quot;&gt;addPostComment&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
                    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt;
                        &lt;span class=&quot;token constant&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
                            &lt;span class=&quot;token constant&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comment&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

                        &lt;span class=&quot;token constant&quot;&gt;Nothing&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
                            &lt;span class=&quot;token constant&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comment&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

                &lt;span class=&quot;token hvariable&quot;&gt;numberOfPostComments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
                    &lt;span class=&quot;token hvariable&quot;&gt;getNumberOfPostComments&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;
                    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;Dict.update&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;addPostComment&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;posts&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;List.map&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;setPostComments&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;numberOfPostComments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;posts&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;newComment&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Comment&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finishing up with &lt;em&gt;View.elm&lt;/em&gt; we need to define &lt;code class=&quot;language-text&quot;&gt;View.viewCommentForm&lt;/code&gt; to build the actual form &lt;a href=&quot;https://en.wikipedia.org/wiki/Document_Object_Model&quot; title=&quot;DOM&quot;&gt;DOM&lt;/a&gt;, then use it in &lt;code class=&quot;language-text&quot;&gt;View.viewComments&lt;/code&gt;. We actually append the comment form to the list of comments, so it also needs to return a &lt;code class=&quot;language-text&quot;&gt;(String, Html Msg)&lt;/code&gt; tuple for the &lt;code class=&quot;language-text&quot;&gt;Html.Keyed.node&lt;/code&gt;. Remember to expose &lt;code class=&quot;language-text&quot;&gt;onInput&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;onSubmit&lt;/code&gt; from the &lt;code class=&quot;language-text&quot;&gt;Html.Events&lt;/code&gt; import.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- View.elm&lt;/span&gt;

&lt;span class=&quot;token import-statement&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Html.Events &lt;span class=&quot;token keyword&quot;&gt;exposing&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;onInput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;onSubmit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;viewComments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Html&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;viewComments&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;-- ...&lt;/span&gt;
        &lt;span class=&quot;token hvariable&quot;&gt;Html.Keyed.node&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;div&quot;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;comments&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt;
            &lt;span class=&quot;token hvariable&quot;&gt;listOfComments&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;viewCommentForm&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;viewCommentForm&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Html&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;viewCommentForm&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;comment-form&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;Html.form&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;onSubmit&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;AddComment&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;newComment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;comment-form&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;input&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;type_&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;text&quot;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;newComment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;username&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;onInput&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;UpdateCommentUsername&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;placeholder&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;author...&quot;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;input&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;type_&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;text&quot;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;newComment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;onInput&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;UpdateCommentText&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;placeholder&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;comment...&quot;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;input&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;type_&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;submit&quot;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;hidden&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;True&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;By now this should all look pretty straight-forward. We bind the &lt;code class=&quot;language-text&quot;&gt;value&lt;/code&gt; of each &lt;code class=&quot;language-text&quot;&gt;input&lt;/code&gt; to properties in &lt;code class=&quot;language-text&quot;&gt;model.newComment&lt;/code&gt; and we trigger &lt;code class=&quot;language-text&quot;&gt;UpdateComment...&lt;/code&gt; actions when either of the &lt;code class=&quot;language-text&quot;&gt;input&lt;/code&gt;s change. We trigger the &lt;code class=&quot;language-text&quot;&gt;AddComment&lt;/code&gt; action with the &lt;code class=&quot;language-text&quot;&gt;form&lt;/code&gt;s &lt;code class=&quot;language-text&quot;&gt;onSubmit&lt;/code&gt; event.&lt;/p&gt;
&lt;p&gt;Recompile and open the app in your browser and you should now be able to leave any nasty comments that you want anonymously without anybody else ever seeing them!&lt;/p&gt;
&lt;h2&gt;The end!&lt;/h2&gt;
&lt;p&gt;You can view the code that we’ve built &lt;a href=&quot;https://github.com/bkbooth/Elmstagram/tree/part3&quot;&gt;here&lt;/a&gt;. We’ve covered quite a lot in building this example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bootstrap an &lt;a href=&quot;https://elm-lang.org/&quot; title=&quot;Elm&quot;&gt;Elm&lt;/a&gt; application&lt;/li&gt;
&lt;li&gt;Define and handle changes to the &lt;code class=&quot;language-text&quot;&gt;model&lt;/code&gt; state object&lt;/li&gt;
&lt;li&gt;Define a DOM structure which responds to changes in the &lt;code class=&quot;language-text&quot;&gt;model&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Get data with HTTP requests and decode a &lt;a href=&quot;https://en.wikipedia.org/wiki/JSON&quot; title=&quot;JSON&quot;&gt;JSON&lt;/a&gt; response&lt;/li&gt;
&lt;li&gt;Add navigation with multiple pages/views, run commands after navigating to a new page&lt;/li&gt;
&lt;li&gt;Define and handle changes to forms&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This doesn’t solve all of the problems that you’ll face trying to build a front-end web application with &lt;a href=&quot;https://elm-lang.org/&quot; title=&quot;Elm&quot;&gt;Elm&lt;/a&gt;, but these foundations should give you enough to build most of what you require. Hopefully this has been an interesting exercise for you and encourages you to try and build something interesting with &lt;a href=&quot;https://elm-lang.org/&quot; title=&quot;Elm&quot;&gt;Elm&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you missed one of the earlier parts, feel free to go back and read them too:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/building-a-basic-ui-clone-of-instagram-using-elm-part-1/&quot;&gt;Part 1&lt;/a&gt; - Setup an &lt;a href=&quot;https://elm-lang.org/&quot; title=&quot;Elm&quot;&gt;Elm&lt;/a&gt; app and load posts from a &lt;a href=&quot;https://en.wikipedia.org/wiki/JSON&quot; title=&quot;JSON&quot;&gt;JSON&lt;/a&gt; file&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/building-a-basic-ui-clone-of-instagram-using-elm-part-2/&quot;&gt;Part 2&lt;/a&gt; - Build the main list view and add navigation&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Building a basic UI-clone of Instagram using Elm - Part 2]]></title><description><![CDATA[I've had a fascination with functional programming for a few years but never really jumped in with any language. Elm seems like a good jumping on point so follow along as I learn Elm while building a basic web app. Here I build the main list view and add navigation.]]></description><link>https://benbooth.dev/building-a-basic-ui-clone-of-instagram-using-elm-part-2</link><guid isPermaLink="false">https://benbooth.dev/building-a-basic-ui-clone-of-instagram-using-elm-part-2</guid><dc:creator><![CDATA[Ben Booth]]></dc:creator><pubDate>Fri, 02 Dec 2016 12:32:00 GMT</pubDate><content:encoded>&lt;p&gt;This article is a part of a series, you should read &lt;a href=&quot;/building-a-basic-ui-clone-of-instagram-using-elm-part-1/&quot;&gt;part 1&lt;/a&gt; if you haven’t already. Alternatively you can get the code from the end of the last article &lt;a href=&quot;https://github.com/bkbooth/Elmstagram/tree/part1&quot;&gt;here&lt;/a&gt; and continue along. You can view the finished app &lt;a href=&quot;https://elmstagram.benbooth.dev&quot; title=&quot;Elmstagram | Demo&quot;&gt;here&lt;/a&gt; and all of the source code is available &lt;a href=&quot;https://github.com/bkbooth/Elmstagram&quot; title=&quot;Elmstagram | GitHub&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Implement the main list of posts view&lt;/h2&gt;
&lt;p&gt;Getting a list of posts is all well and good, but not particularly exciting if we’re just going to show a count of the number of posts. We’ll build the UI for the main list of posts now, and as you might have guessed, most of the work for this step will be in &lt;em&gt;View.elm&lt;/em&gt;. First we’ll get some house-keeping out of the way. We want more control over &lt;em&gt;index.html&lt;/em&gt; so add or replace your &lt;em&gt;index.html&lt;/em&gt; with this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token doctype&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;!&lt;/span&gt;&lt;span class=&quot;token doctype-tag&quot;&gt;DOCTYPE&lt;/span&gt; &lt;span class=&quot;token name&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;charset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;utf-8&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;viewport&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;width=device-width, initial-scale=1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Elmstagram&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;css/styles.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;

    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;js/app.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;
      Elm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;App&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;embed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;app&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Download and save the final &lt;a href=&quot;https://en.wikipedia.org/wiki/Cascading_Style_Sheets&quot;&gt;CSS&lt;/a&gt; from &lt;a href=&quot;https://raw.githubusercontent.com/bkbooth/Elmstagram/resources/css/styles.css&quot;&gt;here&lt;/a&gt; to &lt;em&gt;css/styles.css&lt;/em&gt;, then download all of the fonts from &lt;a href=&quot;https://github.com/bkbooth/Elmstagram/tree/resources/fonts&quot;&gt;here&lt;/a&gt; to &lt;em&gt;fonts/*&lt;/em&gt;. Next, move &lt;em&gt;posts.json&lt;/em&gt; to &lt;em&gt;data/posts.json&lt;/em&gt; and update the URL in &lt;code class=&quot;language-text&quot;&gt;Rest.getPosts&lt;/code&gt; to &lt;code class=&quot;language-text&quot;&gt;&quot;data/posts.json&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We’re no longer inlining the compiled &lt;a href=&quot;https://en.wikipedia.org/wiki/JavaScript&quot; title=&quot;JavaScript&quot;&gt;JavaScript&lt;/a&gt; code, so we need to manually bootstrap it after the script loads. We’ll need to build &lt;em&gt;js/app.js&lt;/em&gt; and with &lt;code class=&quot;language-text&quot;&gt;elm make&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ elm &lt;span class=&quot;token function&quot;&gt;make&lt;/span&gt; App.elm --output js/app.js&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You should be able to start or restart your static HTTP server and see that everything is still working.&lt;/p&gt;
&lt;p&gt;OK, onto the view changes. The &lt;code class=&quot;language-text&quot;&gt;View.rootView&lt;/code&gt; is, as the name suggests, going to be the root view. When we have multiple pages the structure defined here will be common to all pages. Change it to look as follows then download and save &lt;a href=&quot;https://raw.githubusercontent.com/bkbooth/Elmstagram/resources/img/logo.svg&quot;&gt;this logo&lt;/a&gt; to &lt;em&gt;img/logo.svg&lt;/em&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- View.elm&lt;/span&gt;

&lt;span class=&quot;token import-statement&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Html.Attributes &lt;span class=&quot;token keyword&quot;&gt;exposing&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;rootView&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Html&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;rootView&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token hvariable&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;app-root&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;main_&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;photo-list&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt;
                &lt;span class=&quot;token hvariable&quot;&gt;List.map&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;viewPost&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;posts&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;nav&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;nav-inner&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;href&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;nav-logo&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;src&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./img/logo.svg&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Elmstagram&quot;&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;footer&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;footer-inner&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;href&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://github.com/bkbooth/Elmstagram.git&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;View Source&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;|&quot;&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;href&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Elmstagram&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We’ve added &lt;code class=&quot;language-text&quot;&gt;Html.Attributes&lt;/code&gt; as another import where we expose everything, this is because similar to &lt;code class=&quot;language-text&quot;&gt;Http&lt;/code&gt; we will end up using a large number of the functions. This should all be fairly self-explanatory, each &lt;a href=&quot;https://en.wikipedia.org/wiki/Document_Object_Model&quot; title=&quot;DOM&quot;&gt;DOM&lt;/a&gt; node takes a list of attributes followed by a list of child nodes. The only other item of interest is where we &lt;code class=&quot;language-text&quot;&gt;List.map&lt;/code&gt; with a view function over our list of &lt;code class=&quot;language-text&quot;&gt;Post&lt;/code&gt;s in &lt;code class=&quot;language-text&quot;&gt;model.post&lt;/code&gt;. We’ll define &lt;code class=&quot;language-text&quot;&gt;View.viewPost&lt;/code&gt; now, we want &lt;code class=&quot;language-text&quot;&gt;viewPost&lt;/code&gt; to be reusable for each post in the main list and for when we click through to a single post. The function will look like this (don’t forget to add &lt;code class=&quot;language-text&quot;&gt;Post&lt;/code&gt; to the &lt;code class=&quot;language-text&quot;&gt;import Types&lt;/code&gt; line).&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- View.elm&lt;/span&gt;

&lt;span class=&quot;token import-statement&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Types &lt;span class=&quot;token keyword&quot;&gt;exposing&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;viewPost&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Html&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;viewPost&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token hvariable&quot;&gt;figure&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;photo-figure&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;photo-wrap&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;href&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;src&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;media&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;alt&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;photo&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;figcaption&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;caption-button&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;like-button&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;♡&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;caption-content&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;photo-stats&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;strong&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;toString&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;likes&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot; likes, &quot;&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;strong&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;toString&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot; comments&quot;&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;photo-caption&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Again, this is fairly straight-forward building of a &lt;a href=&quot;https://en.wikipedia.org/wiki/Document_Object_Model&quot; title=&quot;DOM&quot;&gt;DOM&lt;/a&gt; tree, note where we access the properties of the &lt;code class=&quot;language-text&quot;&gt;Post&lt;/code&gt; that is passed into the function (this function is called for every &lt;code class=&quot;language-text&quot;&gt;Post&lt;/code&gt; in &lt;code class=&quot;language-text&quot;&gt;model.posts&lt;/code&gt;). At this stage you should be able to rebuild &lt;em&gt;js/app.js&lt;/em&gt; with &lt;code class=&quot;language-text&quot;&gt;elm make App.elm --output js/app.js&lt;/code&gt;, start your static HTTP server if it isn’t still running and reload &lt;a href=&quot;http://localhost:8080&quot;&gt;http://localhost:8080&lt;/a&gt; in your browser to see the layout and list of posts.&lt;/p&gt;
&lt;p&gt;An optimisation that we can and should make is to use &lt;code class=&quot;language-text&quot;&gt;Html.Keyed&lt;/code&gt; to turn each node in our list of &lt;code class=&quot;language-text&quot;&gt;Post&lt;/code&gt;s into a keyed node to help with &lt;a href=&quot;https://elm-lang.org/&quot; title=&quot;Elm&quot;&gt;Elm&lt;/a&gt;’s rendering. This is important for lists where items are getting added, moved, removed, etc. but also when we add navigation between views that are using similar elements. In an early version of this app before adding &lt;code class=&quot;language-text&quot;&gt;Html.Keyed&lt;/code&gt;, whenever I navigated back to the main list view from a single post view, the first item in the list was always the post that I’d just been looking at momentarily. Using &lt;code class=&quot;language-text&quot;&gt;Html.Keyed&lt;/code&gt; fixes problems like these, so lets use it now. Because we want to make use of the current &lt;code class=&quot;language-text&quot;&gt;View.viewPost&lt;/code&gt; implementation on the single post view, we’ll keep it as is and create a wrapper function that returns a keyed node. Add &lt;code class=&quot;language-text&quot;&gt;View.viewKeyedPost&lt;/code&gt; like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- View.elm&lt;/span&gt;

&lt;span class=&quot;token import-statement&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Html.Keyed&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;viewKeyedPost&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Html&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;viewKeyedPost&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;id&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;viewPost&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As you can see, a keyed node is a &lt;code class=&quot;language-text&quot;&gt;(String, Html Msg)&lt;/code&gt; tuple instead of just a &lt;code class=&quot;language-text&quot;&gt;Html Msg&lt;/code&gt; node, the string is the unique identifier for that node, in this case the &lt;code class=&quot;language-text&quot;&gt;post.id&lt;/code&gt;. Change &lt;code class=&quot;language-text&quot;&gt;div.photo-list&lt;/code&gt; to a keyed node which uses &lt;code class=&quot;language-text&quot;&gt;viewKeyedPost&lt;/code&gt; like this &lt;code class=&quot;language-text&quot;&gt;View.rootView&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- View.elm&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;Html.Keyed.node&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;div&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;photo-list&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;List.map&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;viewKeyedPost&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;posts&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Recompile and reload to see that everything should still be working.&lt;/p&gt;
&lt;h2&gt;Implement the “Like” button&lt;/h2&gt;
&lt;p&gt;Now let’s implement the functionality for the “like” button which is the heart next to the number of likes and comments on each post. It would be fairly easy to implement double-click to like similar to &lt;a href=&quot;https://www.instagram.com/&quot; title=&quot;Instagram&quot;&gt;Instagram&lt;/a&gt;, but I’ve decided to reserve clicking on the image for navigating to the single post view. A general procedure which we’ll follow now for adding a new action is to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;add the new action to the &lt;code class=&quot;language-text&quot;&gt;Types.Msg&lt;/code&gt; union type&lt;/li&gt;
&lt;li&gt;handle the action in &lt;code class=&quot;language-text&quot;&gt;State.update&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;use/call the action somewhere in the &lt;code class=&quot;language-text&quot;&gt;View&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Firstly, update &lt;code class=&quot;language-text&quot;&gt;Types.Msg&lt;/code&gt; to look like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Types.elm&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;FetchPosts&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Result&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Http.Error&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;IncrementLikes&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;String&lt;/code&gt; parameter after &lt;code class=&quot;language-text&quot;&gt;IncrementLikes&lt;/code&gt; will be a &lt;code class=&quot;language-text&quot;&gt;Post.id&lt;/code&gt;. Next add this to the &lt;code class=&quot;language-text&quot;&gt;State.update&lt;/code&gt; case statement after the two &lt;code class=&quot;language-text&quot;&gt;FetchPosts&lt;/code&gt; cases:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- State.elm&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Cmd&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;-- ...&lt;/span&gt;

        &lt;span class=&quot;token constant&quot;&gt;IncrementLikes&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt;
                &lt;span class=&quot;token hvariable&quot;&gt;incrementPostLikes&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt;
                &lt;span class=&quot;token hvariable&quot;&gt;incrementPostLikes&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
                    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;then&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;likes&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;likes&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
                    &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
                        &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;
                    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;posts&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;List.map&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;incrementPostLikes&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;posts&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This looks significantly more complex than the previous &lt;code class=&quot;language-text&quot;&gt;State.update&lt;/code&gt; cases, but most of it is the definition of the &lt;code class=&quot;language-text&quot;&gt;incrementPostLikes&lt;/code&gt; function. We could move this function out but this is the only place where the function is used, so I find it simpler to just keep it defined here. The function itself just takes a &lt;code class=&quot;language-text&quot;&gt;String&lt;/code&gt; representing a &lt;code class=&quot;language-text&quot;&gt;Post.id&lt;/code&gt; and a &lt;code class=&quot;language-text&quot;&gt;Post&lt;/code&gt;, if the passed in &lt;code class=&quot;language-text&quot;&gt;postId&lt;/code&gt; matches the passed in &lt;code class=&quot;language-text&quot;&gt;post.id&lt;/code&gt; we increment the &lt;code class=&quot;language-text&quot;&gt;likes&lt;/code&gt; property and return the updated &lt;code class=&quot;language-text&quot;&gt;post&lt;/code&gt;, otherwise we just return the &lt;code class=&quot;language-text&quot;&gt;post&lt;/code&gt; as is. We use this function in the &lt;code class=&quot;language-text&quot;&gt;model&lt;/code&gt; update to &lt;code class=&quot;language-text&quot;&gt;List.map&lt;/code&gt; over the &lt;code class=&quot;language-text&quot;&gt;model.posts&lt;/code&gt;. Basically all this does is return a new &lt;code class=&quot;language-text&quot;&gt;model&lt;/code&gt;, with an updated &lt;code class=&quot;language-text&quot;&gt;posts&lt;/code&gt; property, where any &lt;code class=&quot;language-text&quot;&gt;Post&lt;/code&gt; with the same &lt;code class=&quot;language-text&quot;&gt;Post.id&lt;/code&gt; will have it’s &lt;code class=&quot;language-text&quot;&gt;likes&lt;/code&gt; property incremented.&lt;/p&gt;
&lt;p&gt;Finally, we need to update &lt;code class=&quot;language-text&quot;&gt;View.viewPost&lt;/code&gt;. In &lt;em&gt;View.elm&lt;/em&gt;, you should still have &lt;code class=&quot;language-text&quot;&gt;import Html.Events exposing (onClick)&lt;/code&gt; from the starting example, if not add it back in now. Find &lt;code class=&quot;language-text&quot;&gt;button.like-button&lt;/code&gt; in &lt;code class=&quot;language-text&quot;&gt;View.viewPost&lt;/code&gt; and add an &lt;code class=&quot;language-text&quot;&gt;onClick&lt;/code&gt; handler like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- View.elm&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;onClick&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;IncrementLikes&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;like-button&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;♡&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now you should be able to recompile and test the app in the browser. Click any of the heart icon “like” buttons and the likes counter for the corresponding post will increment, exciting!&lt;/p&gt;
&lt;h2&gt;Add a second page and navigation&lt;/h2&gt;
&lt;p&gt;Just about any reasonably complex web application will contain multiple views and manage the navigation between those views by using the URL. Storing some of the application state in the URL also makes it easier to share a link to a particular page or view. There are two libraries provided by &lt;a href=&quot;https://elm-lang.org/&quot; title=&quot;Elm&quot;&gt;Elm&lt;/a&gt; for handling changes in the URL, namely &lt;a href=&quot;https://package.elm-lang.org/packages/elm-lang/navigation/latest/&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;elm-lang/navigation&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://package.elm-lang.org/packages/elm-lang/navigation/latest/&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;evancz/url-parser&lt;/code&gt;&lt;/a&gt;. Go ahead and install both of them now with &lt;code class=&quot;language-text&quot;&gt;elm package install elm-lang/navigation&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;elm package install evancz/url-parser&lt;/code&gt;. It’s worth noting that &lt;a href=&quot;https://elm-lang.org/&quot; title=&quot;Elm&quot;&gt;Elm&lt;/a&gt; has been deliberate about calling this set of behaviours “navigation” and not “routing” as you would see in most front-end libraries and frameworks.&lt;/p&gt;
&lt;p&gt;The first change required to introduce navigation to an &lt;a href=&quot;https://elm-lang.org/&quot; title=&quot;Elm&quot;&gt;Elm&lt;/a&gt; app is right at the top in &lt;em&gt;App.elm&lt;/em&gt;, &lt;a href=&quot;https://package.elm-lang.org/packages/elm-lang/navigation/latest/&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;elm-lang/navigation&lt;/code&gt;&lt;/a&gt; provides &lt;code class=&quot;language-text&quot;&gt;Navigation.program&lt;/code&gt; which we use to create &lt;code class=&quot;language-text&quot;&gt;App.main&lt;/code&gt; instead of &lt;code class=&quot;language-text&quot;&gt;Html.app&lt;/code&gt;. Replace &lt;code class=&quot;language-text&quot;&gt;import Html&lt;/code&gt; with &lt;code class=&quot;language-text&quot;&gt;import Navigation&lt;/code&gt;, then replace &lt;code class=&quot;language-text&quot;&gt;Html.program&lt;/code&gt; with &lt;code class=&quot;language-text&quot;&gt;Navigation.program&lt;/code&gt; and pass &lt;code class=&quot;language-text&quot;&gt;State.hashParser&lt;/code&gt; is the first parameter before the record definition, we’ll define &lt;code class=&quot;language-text&quot;&gt;State.hashParser&lt;/code&gt; shortly. &lt;code class=&quot;language-text&quot;&gt;App.main&lt;/code&gt; should now look like this.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- App.elm&lt;/span&gt;

&lt;span class=&quot;token import-statement&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Navigation&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Program&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Never&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token hvariable&quot;&gt;Navigation.program&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;State.hashParser&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;init&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;State.init&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;State.update&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;subscriptions&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;State.subscriptions&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;view&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;View.rootView&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next we need to update &lt;em&gt;Types.elm&lt;/em&gt;, we’ll need &lt;code class=&quot;language-text&quot;&gt;Model&lt;/code&gt; to keep track of the current page. Firstly define a new union type &lt;code class=&quot;language-text&quot;&gt;Page&lt;/code&gt; with the pages that you need, in this case &lt;code class=&quot;language-text&quot;&gt;ListOfPosts&lt;/code&gt; for the main list of posts, and &lt;code class=&quot;language-text&quot;&gt;SinglePost String&lt;/code&gt; for the single post view where the &lt;code class=&quot;language-text&quot;&gt;String&lt;/code&gt; will be a &lt;code class=&quot;language-text&quot;&gt;Post.id&lt;/code&gt;. We then need to add a new &lt;code class=&quot;language-text&quot;&gt;page&lt;/code&gt; property to the &lt;code class=&quot;language-text&quot;&gt;Model&lt;/code&gt; record. We’ll also need to update &lt;code class=&quot;language-text&quot;&gt;Types.initialModel&lt;/code&gt; to set the initial &lt;code class=&quot;language-text&quot;&gt;Page&lt;/code&gt;, but we’ll take the initial &lt;code class=&quot;language-text&quot;&gt;Page&lt;/code&gt; as a parameter because we’ll parse the initial URL to work out what the initial &lt;code class=&quot;language-text&quot;&gt;Page&lt;/code&gt; should be in &lt;code class=&quot;language-text&quot;&gt;State.init&lt;/code&gt;. We also need to add a new action to the &lt;code class=&quot;language-text&quot;&gt;Msg&lt;/code&gt; union type to handle navigation changes, we’ll call it &lt;code class=&quot;language-text&quot;&gt;NavigatedTo&lt;/code&gt; and it will take a single &lt;code class=&quot;language-text&quot;&gt;Maybe Page&lt;/code&gt; parameter.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Types.elm&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;posts&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Page&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;initialModel&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Page&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;initialModel&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;page&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;-- ...&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NavigatedTo&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Maybe&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Page&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Page&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ListOfPosts&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SinglePost&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next up is &lt;em&gt;State.elm&lt;/em&gt; and we’ve got a few changes that we need to make. We need to define some utility functions that map URL’s to a &lt;code class=&quot;language-text&quot;&gt;Page&lt;/code&gt; and vice-versa:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- State.elm&lt;/span&gt;

&lt;span class=&quot;token import-statement&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Navigation&lt;/span&gt;
&lt;span class=&quot;token import-statement&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; UrlParser &lt;span class=&quot;token keyword&quot;&gt;exposing&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;hashParser&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Navigation.Location&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;hashParser&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;NavigatedTo&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt;
        &lt;span class=&quot;token hvariable&quot;&gt;UrlParser.parseHash&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;pageParser&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;location&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;pageParser&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Parser&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Page&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;a&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;pageParser&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token hvariable&quot;&gt;oneOf&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ListOfPosts&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SinglePost&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;view&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;/&gt;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;string&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;toUrl&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Page&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;toUrl&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt;
        &lt;span class=&quot;token constant&quot;&gt;ListOfPosts&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;/&quot;&lt;/span&gt;

        &lt;span class=&quot;token constant&quot;&gt;SinglePost&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;/view/&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;State.hashParser&lt;/code&gt; is the function that we passed as the first argument to &lt;code class=&quot;language-text&quot;&gt;App.main&lt;/code&gt; earlier. It’s role is to translate changes in &lt;code class=&quot;language-text&quot;&gt;Navigation.Location&lt;/code&gt; to messages that &lt;code class=&quot;language-text&quot;&gt;State.update&lt;/code&gt; can handle, in this case &lt;code class=&quot;language-text&quot;&gt;NavigatedTo&lt;/code&gt; which we defined in the last step. To do this it uses &lt;code class=&quot;language-text&quot;&gt;UrlParser.parseHash&lt;/code&gt; which takes a &lt;code class=&quot;language-text&quot;&gt;UrlParser.Parser&lt;/code&gt; and a &lt;code class=&quot;language-text&quot;&gt;Navigation.Location&lt;/code&gt; record. &lt;code class=&quot;language-text&quot;&gt;UrlParser&lt;/code&gt; exports a number of functions to help with building an &lt;code class=&quot;language-text&quot;&gt;UrlParser.Parser&lt;/code&gt; which matches the expected URL’s in the app and maps them to &lt;code class=&quot;language-text&quot;&gt;Page&lt;/code&gt;s. &lt;code class=&quot;language-text&quot;&gt;UrlParser.parseHash&lt;/code&gt; actually returns a &lt;code class=&quot;language-text&quot;&gt;Maybe Page&lt;/code&gt; because it might not be able to map the URL to one of the known states of the app, you’ll need to handle this case too. Note that there is also a &lt;code class=&quot;language-text&quot;&gt;UrlParser.parsePath&lt;/code&gt; function that will run a &lt;code class=&quot;language-text&quot;&gt;UrlParser.Parser&lt;/code&gt; against the path part of the URL instead of the hash. I’ve actually used &lt;code class=&quot;language-text&quot;&gt;UrlParser.parsePath&lt;/code&gt; in the &lt;a href=&quot;https://github.com/bkbooth/Elmstagram&quot; title=&quot;Elmstagram | GitHub&quot;&gt;repository&lt;/a&gt;, but using URL paths with a single-page web application requires some server-side support, &lt;code class=&quot;language-text&quot;&gt;UrlParser.parseHash&lt;/code&gt; is easier for examples because we can just use a simple HTTP server. Finally &lt;code class=&quot;language-text&quot;&gt;State.toUrl&lt;/code&gt; just returns a URL &lt;code class=&quot;language-text&quot;&gt;String&lt;/code&gt; based on a &lt;code class=&quot;language-text&quot;&gt;Page&lt;/code&gt;. Now we need to replace &lt;code class=&quot;language-text&quot;&gt;State.init&lt;/code&gt; with this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- State.elm&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;init&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Navigation.Location&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Cmd&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;init&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;UrlParser.parseHash&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;pageParser&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt;
        &lt;span class=&quot;token constant&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token hvariable&quot;&gt;initialModel&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;page&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;Rest.getPosts&lt;/span&gt;
                  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

        &lt;span class=&quot;token constant&quot;&gt;Nothing&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token hvariable&quot;&gt;initialModel&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ListOfPosts&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;Rest.getPosts&lt;/span&gt;
                  &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;Navigation.modifyUrl&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;toUrl&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ListOfPosts&lt;/span&gt;
                  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Because we’re using &lt;code class=&quot;language-text&quot;&gt;Navigation.program&lt;/code&gt;, our &lt;code class=&quot;language-text&quot;&gt;State.init&lt;/code&gt; function now gets passed a &lt;code class=&quot;language-text&quot;&gt;Navigation.Location&lt;/code&gt; which is the URL at the time that the application is initialised. We parse this to a &lt;code class=&quot;language-text&quot;&gt;Maybe Page&lt;/code&gt; using &lt;code class=&quot;language-text&quot;&gt;UrlParser.parseHash&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;State.pageParser&lt;/code&gt;. If it matches a page we pass the page to &lt;code class=&quot;language-text&quot;&gt;Types.initialModel&lt;/code&gt;, otherwise we explicitly set the page to &lt;code class=&quot;language-text&quot;&gt;ListOfPosts&lt;/code&gt; and update the URL with &lt;code class=&quot;language-text&quot;&gt;Navigation.modifyUrl&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;State.toUrl&lt;/code&gt;. You might want to redirect to a &lt;a href=&quot;https://en.wikipedia.org/wiki/HTTP_404&quot;&gt;404 Not Found&lt;/a&gt; page instead. In each case we still call &lt;code class=&quot;language-text&quot;&gt;Rest.getPosts&lt;/code&gt; to load the post data. To finish up the changes in &lt;em&gt;State.elm&lt;/em&gt;, we need to add the &lt;code class=&quot;language-text&quot;&gt;NavigatedTo&lt;/code&gt; case to &lt;code class=&quot;language-text&quot;&gt;State.update&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- State.elm&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;-- ...&lt;/span&gt;

        &lt;span class=&quot;token constant&quot;&gt;NavigatedTo&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;maybePage&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;maybePage&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt;
                &lt;span class=&quot;token constant&quot;&gt;Just&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
                        &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

                &lt;span class=&quot;token constant&quot;&gt;Nothing&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
                    &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;
                        &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;Navigation.newUrl&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;toUrl&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ListOfPosts&lt;/span&gt;
                          &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is pretty similar to what we just did in &lt;code class=&quot;language-text&quot;&gt;State.init&lt;/code&gt;, except that we don’t need to trigger another action if &lt;code class=&quot;language-text&quot;&gt;maybePage&lt;/code&gt; is a known &lt;code class=&quot;language-text&quot;&gt;Page&lt;/code&gt;, just update &lt;code class=&quot;language-text&quot;&gt;model.page&lt;/code&gt;. If it’s not a known &lt;code class=&quot;language-text&quot;&gt;Page&lt;/code&gt;, we redirect to the &lt;code class=&quot;language-text&quot;&gt;ListOfPosts&lt;/code&gt; page using &lt;code class=&quot;language-text&quot;&gt;Navigation.newUrl&lt;/code&gt;. &lt;code class=&quot;language-text&quot;&gt;Navigation.newUrl&lt;/code&gt; updates the state and write a new URL into the browser history, whereas &lt;code class=&quot;language-text&quot;&gt;Navigation.modifyUrl&lt;/code&gt; updates the URL without adding a new state to the browser history.&lt;/p&gt;
&lt;p&gt;We’ll add the proper UI for the single post view in the next part, for now we’ll just show the &lt;code class=&quot;language-text&quot;&gt;Post.postId&lt;/code&gt;. We’ll create a new &lt;code class=&quot;language-text&quot;&gt;View.viewPage&lt;/code&gt; function to change the view based on the current page. Replace &lt;code class=&quot;language-text&quot;&gt;Html.Keyed.node ...&lt;/code&gt; in &lt;code class=&quot;language-text&quot;&gt;View.rootView&lt;/code&gt; with just &lt;code class=&quot;language-text&quot;&gt;viewPage model&lt;/code&gt; and move the &lt;code class=&quot;language-text&quot;&gt;Html.Keyed.node ...&lt;/code&gt; block to &lt;code class=&quot;language-text&quot;&gt;View.viewPage&lt;/code&gt; under the &lt;code class=&quot;language-text&quot;&gt;ListOfPosts&lt;/code&gt; case. We’ll just put a dummy view in for the &lt;code class=&quot;language-text&quot;&gt;SinglePost&lt;/code&gt; case for now. Don’t forget to expose &lt;code class=&quot;language-text&quot;&gt;Page(..)&lt;/code&gt; from the &lt;code class=&quot;language-text&quot;&gt;Types&lt;/code&gt; import, or you might want to just expose everything from &lt;code class=&quot;language-text&quot;&gt;Types&lt;/code&gt; now.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- View.elm&lt;/span&gt;

&lt;span class=&quot;token import-statement&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Types &lt;span class=&quot;token keyword&quot;&gt;exposing&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;rootView&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Html&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;rootView&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token hvariable&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;app-root&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;main_&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;viewPage&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;-- ...&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;viewPage&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Html&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;viewPage&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt;
        &lt;span class=&quot;token constant&quot;&gt;ListOfPosts&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token hvariable&quot;&gt;Html.Keyed.node&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;div&quot;&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;photo-list&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;List.map&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;viewKeyedPost&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;posts&lt;/span&gt;

        &lt;span class=&quot;token constant&quot;&gt;SinglePost&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token hvariable&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;photo-single&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Post: &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;postId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally we need to update the links in &lt;em&gt;View.elm&lt;/em&gt; to use &lt;code class=&quot;language-text&quot;&gt;State.toUrl&lt;/code&gt;. Import &lt;code class=&quot;language-text&quot;&gt;State&lt;/code&gt; and then replace both of the &lt;code class=&quot;language-text&quot;&gt;href &quot;./&quot;&lt;/code&gt;’s in &lt;code class=&quot;language-text&quot;&gt;View.rootView&lt;/code&gt; with &lt;code class=&quot;language-text&quot;&gt;href (State.toUrl ListOfPosts)&lt;/code&gt;, then replace the &lt;code class=&quot;language-text&quot;&gt;href &quot;#&quot;&lt;/code&gt; in &lt;code class=&quot;language-text&quot;&gt;View.viewPost&lt;/code&gt; with &lt;code class=&quot;language-text&quot;&gt;href (State.toUrl SinglePost post.id)&lt;/code&gt;. You should be able to recompile &lt;em&gt;js/app.js&lt;/em&gt; now, start your static HTTP server and view the app in the browser.&lt;/p&gt;
&lt;h2&gt;That’s all (for now)&lt;/h2&gt;
&lt;p&gt;You can view the code that we’ve built so far &lt;a href=&quot;https://github.com/bkbooth/Elmstagram/tree/part2&quot;&gt;here&lt;/a&gt;. We’ll continue building the app in Part 3:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/building-a-basic-ui-clone-of-instagram-using-elm-part-1/&quot;&gt;Part 1&lt;/a&gt; - Setup an &lt;a href=&quot;https://elm-lang.org/&quot; title=&quot;Elm&quot;&gt;Elm&lt;/a&gt; app and load posts from a &lt;a href=&quot;https://en.wikipedia.org/wiki/JSON&quot; title=&quot;JSON&quot;&gt;JSON&lt;/a&gt; file&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/building-a-basic-ui-clone-of-instagram-using-elm-part-3/&quot;&gt;Part 3&lt;/a&gt; - Build the single post view and add the comments form&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Building a basic UI-clone of Instagram using Elm - Part 1]]></title><description><![CDATA[I've had a fascination with functional programming for a few years but never really jumped in with any language. Elm seems like a good jumping on point so follow along as I learn Elm while building a basic web app. Here I setup an Elm app and load posts from a JSON file.]]></description><link>https://benbooth.dev/building-a-basic-ui-clone-of-instagram-using-elm-part-1</link><guid isPermaLink="false">https://benbooth.dev/building-a-basic-ui-clone-of-instagram-using-elm-part-1</guid><dc:creator><![CDATA[Ben Booth]]></dc:creator><pubDate>Thu, 01 Dec 2016 02:14:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve had a fascination with &lt;a href=&quot;https://en.wikipedia.org/wiki/Functional_programming&quot;&gt;functional programming&lt;/a&gt; for a few years now, but despite taking a quick look at &lt;a href=&quot;https://www.haskell.org/&quot;&gt;Haskell&lt;/a&gt; I’ve not invested much time actually learning a functional language. I’ve generally tried to approach my front-end development from a functional mindset, keeping functions &lt;a href=&quot;https://en.wikipedia.org/wiki/Pure_function&quot;&gt;pure&lt;/a&gt;, trying not to mutate objects, always using things like &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;map&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;filter&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;reduce&lt;/code&gt;&lt;/a&gt; to manipulate collections. One of my main complaints/observations with functional languages is that they don’t seem to be immediately practical, there seems to be a big step between picking up the fundamentals and basics of the language, and actually building something useful with it. Sometime recently I became aware of &lt;a href=&quot;https://elm-lang.org/&quot; title=&quot;Elm&quot;&gt;Elm&lt;/a&gt; and after looking into it quickly, it seemed to address exactly this complaint of mine. There seemed to be a quick turnaround from picking up the basics of the language and being able to actually build something with it, specifically a front-end web application. I read through the &lt;a href=&quot;https://guide.elm-lang.org/&quot; title=&quot;An Introduction to Elm&quot;&gt;&lt;em&gt;An Introduction to Elm&lt;/em&gt;&lt;/a&gt; book and wanted to build one of my side project ideas with &lt;a href=&quot;https://elm-lang.org/&quot; title=&quot;Elm&quot;&gt;Elm&lt;/a&gt;, but I decided that to avoid the possibility of getting overwhelmed and frustrated trying to build something ambitious with a new language, I’d build an example app that covered a lot of what I’d need for a bigger app. So, inspired by &lt;a href=&quot;https://twitter.com/wesbos&quot;&gt;Wes Bos’&lt;/a&gt; great &lt;a href=&quot;https://learnredux.com/&quot;&gt;Learn Redux course&lt;/a&gt;, I decided I’d build a simple UI-clone of &lt;a href=&quot;https://www.instagram.com/&quot; title=&quot;Instagram&quot;&gt;Instagram&lt;/a&gt;. You can view the finished app &lt;a href=&quot;https://elmstagram.benbooth.dev&quot; title=&quot;Elmstagram | Demo&quot;&gt;here&lt;/a&gt; and all of the source code is available &lt;a href=&quot;https://github.com/bkbooth/Elmstagram&quot; title=&quot;Elmstagram | GitHub&quot;&gt;here&lt;/a&gt;. Also a big shout out to my friend Sam Gates for letting me use data from his &lt;a href=&quot;https://www.instagram.com/samgatesphotography/&quot;&gt;@samgatesphotography&lt;/a&gt; account for this example app and articles.&lt;/p&gt;
&lt;h2&gt;Setting up a basic &lt;a href=&quot;https://elm-lang.org/&quot; title=&quot;Elm&quot;&gt;Elm&lt;/a&gt; app&lt;/h2&gt;
&lt;p&gt;Most of the simple examples that you see for &lt;a href=&quot;https://elm-lang.org/&quot; title=&quot;Elm&quot;&gt;Elm&lt;/a&gt; seem to have the entire codebase in a single &lt;em&gt;.elm&lt;/em&gt; file, this is great to demonstrate how little is required to get up and running with &lt;a href=&quot;https://elm-lang.org/&quot; title=&quot;Elm&quot;&gt;Elm&lt;/a&gt;, and the advice seems to be to only break your app into separate files when you need to. I had a look around at some articles and examples and I settled on the following app structure:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;none&quot;&gt;&lt;pre class=&quot;language-none&quot;&gt;&lt;code class=&quot;language-none&quot;&gt;project-directory/
├─ elm-package.json ─ project metadata and dependencies
├─ App.elm          ─ bootstrap app using The Elm Architecture
├─ Types.elm        ─ define Model, Msg and any other types
├─ State.elm        ─ handle all changes to state
├─ View.elm         ─ all view rendering and logic
├─ Rest.elm         ─ HTTP requests and JSON parsing
└─ Feature/         ─ a feature sub-directory
   ├─ Types.elm
   ├─ State.elm
   ├─ View.elm
   └─ Rest.elm&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This should scale reasonably well, you would mostly re-use the same files as necessary in feature sub-directories. We’ll only use the top-level files for this example, but for anything more complex you would probably need to break the app into smaller features, similar to how you would compose the UI out of separate small components in other frameworks.&lt;/p&gt;
&lt;p&gt;The first steps to get started with &lt;a href=&quot;https://elm-lang.org/&quot; title=&quot;Elm&quot;&gt;Elm&lt;/a&gt; are to install &lt;code class=&quot;language-text&quot;&gt;elm&lt;/code&gt;, create a new project directory and initialise an &lt;a href=&quot;https://elm-lang.org/&quot; title=&quot;Elm&quot;&gt;Elm&lt;/a&gt; project inside of it. Installing &lt;a href=&quot;https://package.elm-lang.org/packages/elm-lang/core/latest/&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;elm-lang/core&lt;/code&gt;&lt;/a&gt; will include &lt;a href=&quot;https://package.elm-lang.org/packages/elm-lang/html/latest/&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;elm-lang/html&lt;/code&gt;&lt;/a&gt; and initialise an &lt;em&gt;elm-package.json&lt;/em&gt; file for the project.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; -g elm
$ &lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; Elmstagram
$ &lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; Elmstagram
$ elm package &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; elm-lang/core&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://guide.elm-lang.org/architecture/&quot; title=&quot;The Elm Architecture&quot;&gt;The Elm Architecture&lt;/a&gt; is one of &lt;a href=&quot;https://elm-lang.org/&quot; title=&quot;Elm&quot;&gt;Elm&lt;/a&gt;’s great contributions to the front-end ecosystem, the concept of a single immutable state object has been used by &lt;a href=&quot;https://redux.js.org/&quot;&gt;Redux&lt;/a&gt; and many other similar libraries. The following files implement a very basic &lt;a href=&quot;https://elm-lang.org/&quot; title=&quot;Elm&quot;&gt;Elm&lt;/a&gt; example, and we’ll use this as a starting point for the app. Note that we won’t need &lt;em&gt;Rest.elm&lt;/em&gt; just yet.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Types.elm&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Types&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;exposing&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;Int&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;initialModel&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;initialModel&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;IncrementLikes&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- State.elm&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;State&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;exposing&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token import-statement&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Types &lt;span class=&quot;token keyword&quot;&gt;exposing&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;init&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Cmd&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;init&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token hvariable&quot;&gt;initialModel&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Cmd&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt;
        &lt;span class=&quot;token constant&quot;&gt;IncrementLikes&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;subscriptions&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Sub&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;subscriptions&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token hvariable&quot;&gt;Sub.none&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- View.elm&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;View&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;exposing&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token import-statement&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Html &lt;span class=&quot;token keyword&quot;&gt;exposing&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token import-statement&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Html.Events &lt;span class=&quot;token keyword&quot;&gt;exposing&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token import-statement&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Types &lt;span class=&quot;token keyword&quot;&gt;exposing&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;rootView&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Html&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;rootView&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token hvariable&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;h1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Elmstagram&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Likes: &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;toString&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;onClick&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;IncrementLikes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Like!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- App.elm&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;App&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;exposing&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token import-statement&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Html&lt;/span&gt;
&lt;span class=&quot;token import-statement&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Types &lt;span class=&quot;token keyword&quot;&gt;exposing&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token import-statement&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; State&lt;/span&gt;
&lt;span class=&quot;token import-statement&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; View&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Program&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Never&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token hvariable&quot;&gt;Html.program&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;init&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;State.init&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;State.update&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;subscriptions&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;State.subscriptions&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;view&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;View.rootView&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I don’t want to go into explaining this too much because this is all pretty thoroughly covered in the &lt;a href=&quot;https://elm-lang.org/&quot; title=&quot;Elm&quot;&gt;Elm&lt;/a&gt; introductory &lt;a href=&quot;https://guide.elm-lang.org/&quot; title=&quot;An Introduction to Elm&quot;&gt;tutorials&lt;/a&gt; and &lt;a href=&quot;https://elm-lang.org/examples&quot;&gt;examples&lt;/a&gt;. Basically the &lt;em&gt;App.elm&lt;/em&gt; file is the entry point into the application, it must expose a &lt;code class=&quot;language-text&quot;&gt;main&lt;/code&gt; function which returns a &lt;code class=&quot;language-text&quot;&gt;Program&lt;/code&gt; as defined by &lt;a href=&quot;https://guide.elm-lang.org/architecture/&quot; title=&quot;The Elm Architecture&quot;&gt;The Elm Architecture&lt;/a&gt;. The &lt;code class=&quot;language-text&quot;&gt;Program&lt;/code&gt; requires:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;an &lt;code class=&quot;language-text&quot;&gt;init&lt;/code&gt; function which provides an initial &lt;code class=&quot;language-text&quot;&gt;model&lt;/code&gt; and optionally some initial commands to run. We’ll use this next to load the list of posts.&lt;/li&gt;
&lt;li&gt;an &lt;code class=&quot;language-text&quot;&gt;update&lt;/code&gt; function which responds to commands and updates the &lt;code class=&quot;language-text&quot;&gt;model&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;a &lt;code class=&quot;language-text&quot;&gt;subscriptions&lt;/code&gt; function which is used to respond to external updates such as messages on a web socket. We won’t require any subscriptions for this example.&lt;/li&gt;
&lt;li&gt;a &lt;code class=&quot;language-text&quot;&gt;view&lt;/code&gt; function which returns the UI based on the current &lt;code class=&quot;language-text&quot;&gt;model&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you’ve only looked at basic &lt;a href=&quot;https://elm-lang.org/&quot; title=&quot;Elm&quot;&gt;Elm&lt;/a&gt; examples so far, the &lt;code class=&quot;language-text&quot;&gt;model ! [ cmd ]&lt;/code&gt; syntax might look a little strange, but all it does is return a &lt;code class=&quot;language-text&quot;&gt;(model, cmd)&lt;/code&gt; tuple, where it’s easy to provide a list of commands instead of just one. It also means we can just past an empty list as &lt;code class=&quot;language-text&quot;&gt;[]&lt;/code&gt; instead of explicitly using &lt;code class=&quot;language-text&quot;&gt;Cmd.none&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;At this point you should be able to run &lt;code class=&quot;language-text&quot;&gt;elm make App.elm&lt;/code&gt; which will compile everything and produce an &lt;em&gt;index.html&lt;/em&gt; which you can open in a browser. Click the “Like!” button to your hearts content, then we’ll move on with making things a little more interesting.&lt;/p&gt;
&lt;h2&gt;Load posts from a &lt;a href=&quot;https://en.wikipedia.org/wiki/JSON&quot; title=&quot;JSON&quot;&gt;JSON&lt;/a&gt; file&lt;/h2&gt;
&lt;p&gt;Loading data from an external resource is actually fairly straight-forward, though if you’re coming from &lt;a href=&quot;https://en.wikipedia.org/wiki/JavaScript&quot; title=&quot;JavaScript&quot;&gt;JavaScript&lt;/a&gt; you might find it a little tedious having to define &lt;a href=&quot;https://guide.elm-lang.org/types/&quot;&gt;types&lt;/a&gt; and &lt;a href=&quot;https://guide.elm-lang.org/interop/json.html&quot;&gt;decoders&lt;/a&gt;. It definitely becomes easier after a little practice and I believe the extra effort trade-off is worth it. You’ll basically need to define &lt;code class=&quot;language-text&quot;&gt;type alias&lt;/code&gt;es and decoders for all of the types that you’re expecting in your &lt;a href=&quot;https://en.wikipedia.org/wiki/JSON&quot; title=&quot;JSON&quot;&gt;JSON&lt;/a&gt;-returning HTTP requests.&lt;/p&gt;
&lt;p&gt;Download and save &lt;a href=&quot;https://raw.githubusercontent.com/bkbooth/Elmstagram/resources/data/posts.json&quot;&gt;&lt;em&gt;posts.json&lt;/em&gt;&lt;/a&gt; into your project directory. The JSON data looks like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  ...&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;BLvMFSVB8mQ&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;likes&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;91&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;comments&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;The description or caption of the post #plusprobablysomehashtags&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;media&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://url.to/post.image.jpg&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  ...
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In &lt;em&gt;Types.elm&lt;/em&gt; we need to add a new &lt;code class=&quot;language-text&quot;&gt;type alias Post&lt;/code&gt; to map the &lt;a href=&quot;https://en.wikipedia.org/wiki/JSON&quot; title=&quot;JSON&quot;&gt;JSON&lt;/a&gt; data into. The type properties don’t have to match exactly to the &lt;a href=&quot;https://en.wikipedia.org/wiki/JSON&quot; title=&quot;JSON&quot;&gt;JSON&lt;/a&gt; property names, but keeping them the same is the simplest for now. The type should look like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Types.elm&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;likes&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Int&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;comments&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Int&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;media&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;String&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;While we’re in &lt;em&gt;Types.elm&lt;/em&gt;, we’ll update the &lt;code class=&quot;language-text&quot;&gt;Model&lt;/code&gt; type and the &lt;code class=&quot;language-text&quot;&gt;initialModel&lt;/code&gt; function to contain a list of &lt;code class=&quot;language-text&quot;&gt;Post&lt;/code&gt;s. Note that when we define a type in &lt;a href=&quot;https://elm-lang.org/&quot; title=&quot;Elm&quot;&gt;Elm&lt;/a&gt; we get a constructor function of the same name that creates and returns a new value of that type, the function takes the same number of arguments as properties declared in the type definition and in the same order that they’re declared. So far we just have a single &lt;code class=&quot;language-text&quot;&gt;posts&lt;/code&gt; property which we’ll initialise to an empty list.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Types.elm&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;posts&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;initialModel&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;initialModel&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next we need to define a decoder that instructs &lt;a href=&quot;https://elm-lang.org/&quot; title=&quot;Elm&quot;&gt;Elm&lt;/a&gt; how to parse &lt;a href=&quot;https://en.wikipedia.org/wiki/JSON&quot; title=&quot;JSON&quot;&gt;JSON&lt;/a&gt; into types that it knows about. We need to use methods defined in &lt;a href=&quot;https://package.elm-lang.org/packages/elm-lang/core/latest/Json-Decode&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Json.Decode&lt;/code&gt;&lt;/a&gt; from &lt;a href=&quot;https://package.elm-lang.org/packages/elm-lang/core/latest&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;elm-lang/core&lt;/code&gt;&lt;/a&gt; to create the decoder. The &lt;a href=&quot;https://en.wikipedia.org/wiki/JSON&quot; title=&quot;JSON&quot;&gt;JSON&lt;/a&gt; structure is an array of objects, each representing a single post. So we’ll define the &lt;code class=&quot;language-text&quot;&gt;decodePosts&lt;/code&gt; function as returning a &lt;code class=&quot;language-text&quot;&gt;Json.Decode.Decoder (List Post)&lt;/code&gt;. We’ll need to create the &lt;em&gt;Rest.elm&lt;/em&gt; file now and it will look like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Rest.elm&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Rest&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;exposing&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token import-statement&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Json.Decode &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; Json &lt;span class=&quot;token keyword&quot;&gt;exposing&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token import-statement&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Types &lt;span class=&quot;token keyword&quot;&gt;exposing&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;decodePosts&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Json.Decoder&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;decodePosts&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token hvariable&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt;
        &lt;span class=&quot;token hvariable&quot;&gt;map5&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;likes&quot;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;comments&quot;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;text&quot;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;media&quot;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that we’ve imported &lt;code class=&quot;language-text&quot;&gt;Json.Decode as Json exposing(..)&lt;/code&gt;. This means that in the annotation we can simplify &lt;code class=&quot;language-text&quot;&gt;Json.Decode.Decoder&lt;/code&gt; to &lt;code class=&quot;language-text&quot;&gt;Json.Decoder&lt;/code&gt;. We could simplify it further to just &lt;code class=&quot;language-text&quot;&gt;Decoder&lt;/code&gt; because we’ve exposed everything from &lt;code class=&quot;language-text&quot;&gt;Json.Decode&lt;/code&gt;, but I prefer to be explicit here. To avoid exposing everything from &lt;code class=&quot;language-text&quot;&gt;Json.Decode&lt;/code&gt; we’d have to either explicitly refer to each of &lt;code class=&quot;language-text&quot;&gt;list&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;map5&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;field&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;string&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;int&lt;/code&gt; as &lt;code class=&quot;language-text&quot;&gt;Json.list&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;Json.map&lt;/code&gt;, etc. Or list just the functions that we’re actually using in the &lt;code class=&quot;language-text&quot;&gt;import&lt;/code&gt; statement: &lt;code class=&quot;language-text&quot;&gt;exposing(list, map5, field, string, int)&lt;/code&gt;. The same goes for exposing functions from &lt;code class=&quot;language-text&quot;&gt;Html&lt;/code&gt; in &lt;em&gt;View.elm&lt;/em&gt;. I generally prefer to be explicit about only importing what I need, but for &lt;em&gt;Rest.elm&lt;/em&gt; I’m OK with exposing everything from &lt;code class=&quot;language-text&quot;&gt;Json.Decode&lt;/code&gt; and for &lt;em&gt;View.elm&lt;/em&gt; I’m OK with exposing everything from &lt;code class=&quot;language-text&quot;&gt;Html&lt;/code&gt; because you generally need a number of functions from both.&lt;/p&gt;
&lt;p&gt;Reading the decoder as we’ve defined it, we want to decode the &lt;a href=&quot;https://en.wikipedia.org/wiki/JSON&quot; title=&quot;JSON&quot;&gt;JSON&lt;/a&gt; into a list of &lt;code class=&quot;language-text&quot;&gt;Post&lt;/code&gt;s. We use the &lt;code class=&quot;language-text&quot;&gt;map5&lt;/code&gt; function here because we want to take 5 properties from the &lt;a href=&quot;https://en.wikipedia.org/wiki/JSON&quot; title=&quot;JSON&quot;&gt;JSON&lt;/a&gt; object. There are a number of &lt;code class=&quot;language-text&quot;&gt;Json.Decode.mapx&lt;/code&gt; functions to decode different sized &lt;a href=&quot;https://en.wikipedia.org/wiki/JSON&quot; title=&quot;JSON&quot;&gt;JSON&lt;/a&gt; objects. &lt;code class=&quot;language-text&quot;&gt;map5&lt;/code&gt; takes a function that takes 5 parameters to produce a value (in this case the default &lt;code class=&quot;language-text&quot;&gt;Post&lt;/code&gt; constructor function), followed by 5 decoders. The 5 &lt;code class=&quot;language-text&quot;&gt;field&lt;/code&gt; decoders that we’re using each take a property name to extract from the &lt;a href=&quot;https://en.wikipedia.org/wiki/JSON&quot; title=&quot;JSON&quot;&gt;JSON&lt;/a&gt; object, followed by a type decoder which needs to match the &lt;a href=&quot;https://en.wikipedia.org/wiki/JSON&quot; title=&quot;JSON&quot;&gt;JSON&lt;/a&gt; property type.&lt;/p&gt;
&lt;p&gt;To load the &lt;a href=&quot;https://en.wikipedia.org/wiki/JSON&quot; title=&quot;JSON&quot;&gt;JSON&lt;/a&gt; file we’ll need to install &lt;a href=&quot;https://package.elm-lang.org/packages/elm-lang/http/latest&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;elm-lang/http&lt;/code&gt;&lt;/a&gt; (&lt;code class=&quot;language-text&quot;&gt;elm package install elm-lang/http&lt;/code&gt;) and &lt;code class=&quot;language-text&quot;&gt;import Http&lt;/code&gt; in &lt;em&gt;Rest.elm&lt;/em&gt;. The &lt;code class=&quot;language-text&quot;&gt;getPosts&lt;/code&gt; function will look like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Rest.elm&lt;/span&gt;

&lt;span class=&quot;token import-statement&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Http&lt;/span&gt;
&lt;span class=&quot;token import-statement&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Types &lt;span class=&quot;token keyword&quot;&gt;exposing&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;getPosts&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Cmd&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;getPosts&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token hvariable&quot;&gt;Http.send&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;FetchPosts&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt;
        &lt;span class=&quot;token hvariable&quot;&gt;Http.get&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;posts.json&quot;&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;decodePosts&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;Http.get&lt;/code&gt; takes a URL as a string and a &lt;code class=&quot;language-text&quot;&gt;Json.Decode.Decoder&lt;/code&gt; and returns a &lt;code class=&quot;language-text&quot;&gt;Http.Request&lt;/code&gt;. &lt;code class=&quot;language-text&quot;&gt;Http.send&lt;/code&gt; takes a &lt;code class=&quot;language-text&quot;&gt;Msg&lt;/code&gt; and a &lt;code class=&quot;language-text&quot;&gt;Http.Request&lt;/code&gt;, it performs the HTTP request and sends the success/fail as a &lt;code class=&quot;language-text&quot;&gt;Result&lt;/code&gt; to the specified &lt;code class=&quot;language-text&quot;&gt;Msg&lt;/code&gt;. To actually run all of this, we need to call &lt;code class=&quot;language-text&quot;&gt;Rest.getPosts&lt;/code&gt; from somewhere in the app. We could either do it in response to another &lt;code class=&quot;language-text&quot;&gt;Msg&lt;/code&gt; (such as clicking a button), or as a part of the initialisation. Because we always want to retrieve the list of posts before the app is able to do anything interesting, we’ll do it as a part of the initialisation. In &lt;em&gt;State.elm&lt;/em&gt; modify the &lt;code class=&quot;language-text&quot;&gt;init&lt;/code&gt; function to look like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- State.elm&lt;/span&gt;

&lt;span class=&quot;token import-statement&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Rest&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;init&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Cmd&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;init&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token hvariable&quot;&gt;initialModel&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;Rest.getPosts&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We’ll also need to update the &lt;code class=&quot;language-text&quot;&gt;Types.Msg&lt;/code&gt; type to include the &lt;code class=&quot;language-text&quot;&gt;FetchPosts&lt;/code&gt; message and handle the message in the &lt;code class=&quot;language-text&quot;&gt;State.update&lt;/code&gt; function. Note that we’ve removed the &lt;code class=&quot;language-text&quot;&gt;IncrementLikes&lt;/code&gt; message.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Types.elm&lt;/span&gt;

&lt;span class=&quot;token import-statement&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Http&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;FetchPosts&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Result&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Http.Error&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- State.elm&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Cmd&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt;
        &lt;span class=&quot;token constant&quot;&gt;FetchPosts&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Ok&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;posts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;posts&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;posts&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;Cmd.none&lt;/span&gt;

        &lt;span class=&quot;token constant&quot;&gt;FetchPosts&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;Err&lt;/span&gt; _&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
            &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;Cmd.none&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;{ model | posts = posts }&lt;/code&gt; syntax is how you update a record in &lt;a href=&quot;https://elm-lang.org/&quot; title=&quot;Elm&quot;&gt;Elm&lt;/a&gt;. It returns a new record, starting from the old record specified before the pipe, updated with any property changes after the pipe.&lt;/p&gt;
&lt;p&gt;We’ll update the view in the next part to show the actual posts, but for now just change &lt;code class=&quot;language-text&quot;&gt;View.rootView&lt;/code&gt; to show a count of the number of posts so that we can compile and check that everything still works.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;elm&quot;&gt;&lt;pre class=&quot;language-elm&quot;&gt;&lt;code class=&quot;language-elm&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- View.elm&lt;/span&gt;

&lt;span class=&quot;token hvariable&quot;&gt;rootView&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Html&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;Msg&lt;/span&gt;
&lt;span class=&quot;token hvariable&quot;&gt;rootView&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;token hvariable&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;h1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Elmstagram&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Posts: &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;toString&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;|&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;List.length&lt;/span&gt; &lt;span class=&quot;token hvariable&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token hvariable&quot;&gt;posts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Go ahead and recompile the app with &lt;code class=&quot;language-text&quot;&gt;elm make App.elm&lt;/code&gt;. Because we’ve introduced a HTTP request you won’t be able to just open the created &lt;em&gt;index.html&lt;/em&gt; file in a browser anymore, the browser will show a &lt;a href=&quot;https://en.wikipedia.org/wiki/Cross-origin_resource_sharing&quot;&gt;CORS&lt;/a&gt; error when attempting to load &lt;em&gt;posts.json&lt;/em&gt;. You’ll need to use a HTTP server to serve the example, but a static server such as &lt;a href=&quot;https://www.npmjs.com/package/http-server&quot;&gt;http-server&lt;/a&gt; will be good enough for now, just install and run it in your project directory, then open &lt;a href=&quot;http://localhost:8080&quot;&gt;http://localhost:8080&lt;/a&gt; in your browser.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ elm &lt;span class=&quot;token function&quot;&gt;make&lt;/span&gt; App.elm
$ &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; -g http-server
$ http-server&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;That’s all (for now)&lt;/h2&gt;
&lt;p&gt;You can view the code that we’ve built so far &lt;a href=&quot;https://github.com/bkbooth/Elmstagram/tree/part1&quot;&gt;here&lt;/a&gt;. We’ll continue building the app in the following articles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/building-a-basic-ui-clone-of-instagram-using-elm-part-2/&quot;&gt;Part 2&lt;/a&gt; - Build the main list view and add navigation&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/building-a-basic-ui-clone-of-instagram-using-elm-part-3/&quot;&gt;Part 3&lt;/a&gt; - Build the single post view and add the comments form&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Running Ghost with PM2 under a different user account on a Linux server]]></title><description><![CDATA[Create a new user on a Linux server with it's own Node.js version and globals and have your Ghost application run with PM2 under that new account.]]></description><link>https://benbooth.dev/running-ghost-under-a-different-user-account-on-a-linux-server</link><guid isPermaLink="false">https://benbooth.dev/running-ghost-under-a-different-user-account-on-a-linux-server</guid><dc:creator><![CDATA[Ben Booth]]></dc:creator><pubDate>Mon, 15 Jun 2015 03:17:00 GMT</pubDate><content:encoded>&lt;p&gt;When I first setup my &lt;a href=&quot;https://ghost.org&quot;&gt;Ghost&lt;/a&gt; blog on my own server (a self-managed &lt;a href=&quot;https://www.linode.com/?r=92a203d4e391cd917cd9c6e351e7c2e3c2ddd294&quot;&gt;Linode&lt;/a&gt; which has been great and I highly recommend them), I installed &lt;a href=&quot;https://nodejs.org/&quot;&gt;Node.js&lt;/a&gt; directly under my main user account. I eventually ran into the problem of needing/wanting to use different versions of &lt;a href=&quot;https://nodejs.org/&quot;&gt;Node.js&lt;/a&gt; for different applications, so I uninstalled &lt;a href=&quot;https://nodejs.org/&quot;&gt;Node.js&lt;/a&gt; and installed/used &lt;a href=&quot;https://github.com/creationix/nvm&quot;&gt;nvm&lt;/a&gt; instead. It occurred to me that I might be better off running the &lt;a href=&quot;https://ghost.org&quot;&gt;Ghost&lt;/a&gt; application under a different user account, so that it could manage it’s own &lt;a href=&quot;https://github.com/creationix/nvm&quot;&gt;nvm&lt;/a&gt;/&lt;a href=&quot;https://nodejs.org/&quot;&gt;Node.js&lt;/a&gt; versions and global &lt;a href=&quot;https://www.npmjs.com/&quot;&gt;npm&lt;/a&gt; packages. I did nothing about it at the time, but I recently wanted to be able to run two applications which needed different &lt;a href=&quot;https://nodejs.org/&quot;&gt;Node.js&lt;/a&gt; versions simultaneously.&lt;/p&gt;
&lt;p&gt;My &lt;a href=&quot;https://www.linode.com/?r=92a203d4e391cd917cd9c6e351e7c2e3c2ddd294&quot;&gt;Linode&lt;/a&gt; is running &lt;a href=&quot;https://www.centos.org/&quot;&gt;CentOS&lt;/a&gt; 7, but the process should be pretty similar across Linux distributions, this is an overview of how I’m setup to run &lt;a href=&quot;https://ghost.org&quot;&gt;Ghost&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/&quot;&gt;Node.js&lt;/a&gt; and &lt;a href=&quot;https://www.npmjs.com/&quot;&gt;npm&lt;/a&gt; are installed and managed by &lt;a href=&quot;https://github.com/creationix/nvm&quot;&gt;nvm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://ghost.org&quot;&gt;Ghost&lt;/a&gt; application is setup under &lt;code class=&quot;language-text&quot;&gt;/var/www/benbooth.co&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nginx.org/en/&quot;&gt;nginx&lt;/a&gt; is being used as a reverse proxy to forward requests to the &lt;a href=&quot;https://ghost.org&quot;&gt;Ghost&lt;/a&gt; application&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://ghost.org&quot;&gt;Ghost&lt;/a&gt; application is always running and starts on server start using &lt;a href=&quot;https://github.com/Unitech/pm2&quot;&gt;PM2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://app.keymetrics.io/#/register&quot;&gt;Keymetrics&lt;/a&gt; monitoring through &lt;a href=&quot;https://github.com/Unitech/pm2&quot;&gt;PM2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Create the new user&lt;/h2&gt;
&lt;p&gt;Let’s get started, firstly you’ll need to create the new user:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useradd&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;username&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I’m creating a user called &lt;code class=&quot;language-text&quot;&gt;ghost&lt;/code&gt; to run my blog, so I’d run &lt;code class=&quot;language-text&quot;&gt;sudo useradd ghost&lt;/code&gt; (tip: to fully delete the user including home directory, use &lt;code class=&quot;language-text&quot;&gt;sudo userdel -r ghost&lt;/code&gt;). If you want to set a password for the new user type &lt;code class=&quot;language-text&quot;&gt;passwd [username]&lt;/code&gt;. I don’t want to be able to login directly to this user, so I’m not going to set a password, we can switch to the new user by typing:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;su&lt;/span&gt; ghost&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which switches to the new user, but stays in the same working directory. Pass the &lt;code class=&quot;language-text&quot;&gt;-l&lt;/code&gt; (or just &lt;code class=&quot;language-text&quot;&gt;-&lt;/code&gt;) option to login to the new users’ home directory (eg. &lt;code class=&quot;language-text&quot;&gt;sudo su - ghost&lt;/code&gt;).&lt;/p&gt;
&lt;h2&gt;Setup &lt;a href=&quot;https://nodejs.org/&quot;&gt;Node.js&lt;/a&gt; using &lt;a href=&quot;https://github.com/creationix/nvm&quot;&gt;nvm&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Next we need to install &lt;a href=&quot;https://github.com/creationix/nvm&quot;&gt;nvm&lt;/a&gt; and then install &lt;a href=&quot;https://nodejs.org/&quot;&gt;Node.js&lt;/a&gt;. Download and run the &lt;a href=&quot;https://github.com/creationix/nvm&quot;&gt;nvm&lt;/a&gt; installer script (this is the latest version at the time of writing, check the &lt;a href=&quot;https://github.com/creationix/nvm&quot;&gt;nvm GitHub repo&lt;/a&gt; for the latest version). If you haven’t already, change to the new user first &lt;code class=&quot;language-text&quot;&gt;sudo su - ghost&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ghost&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;bash&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then install a &lt;a href=&quot;https://nodejs.org/&quot;&gt;Node.js&lt;/a&gt; version and tag it as &lt;code class=&quot;language-text&quot;&gt;default&lt;/code&gt;. (You might need to &lt;code class=&quot;language-text&quot;&gt;source ~/.bashrc&lt;/code&gt; before you use &lt;a href=&quot;https://github.com/creationix/nvm&quot;&gt;nvm&lt;/a&gt; if you just installed it):&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ghost&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ nvm &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.10&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ghost&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ nvm &lt;span class=&quot;token builtin class-name&quot;&gt;alias&lt;/span&gt; default &lt;span class=&quot;token number&quot;&gt;0.10&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;At the time of writing, &lt;a href=&quot;https://ghost.org&quot;&gt;Ghost&lt;/a&gt; requires &lt;a href=&quot;https://nodejs.org/&quot;&gt;Node.js&lt;/a&gt; version &lt;code class=&quot;language-text&quot;&gt;0.10.*&lt;/code&gt; (&lt;code class=&quot;language-text&quot;&gt;0.10.38&lt;/code&gt; is the latest at the time of writing).&lt;/p&gt;
&lt;h2&gt;Install &lt;a href=&quot;https://github.com/Unitech/pm2&quot;&gt;PM2&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Installing &lt;a href=&quot;https://github.com/Unitech/pm2&quot;&gt;PM2&lt;/a&gt; is a straight-forward &lt;a href=&quot;https://www.npmjs.com/&quot;&gt;npm&lt;/a&gt; global install:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ghost&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; -g pm2&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;Stop the existing &lt;a href=&quot;https://ghost.org&quot;&gt;Ghost&lt;/a&gt; instance&lt;/h1&gt;
&lt;p&gt;Next, if you haven’t already, stop the existing &lt;a href=&quot;https://ghost.org&quot;&gt;Ghost&lt;/a&gt; instance running under your user account (&lt;code class=&quot;language-text&quot;&gt;exit&lt;/code&gt; the &lt;code class=&quot;language-text&quot;&gt;ghost&lt;/code&gt; user shell to take you back to your user shell):&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ pm2 stop ghost
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ pm2 delete ghost
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ pm2 save&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is assuming you were already running the blog using &lt;a href=&quot;https://github.com/Unitech/pm2&quot;&gt;PM2&lt;/a&gt; with the name &lt;code class=&quot;language-text&quot;&gt;ghost&lt;/code&gt;. &lt;code class=&quot;language-text&quot;&gt;pm2 save&lt;/code&gt; dumps the list of currently running processes to file so it can be restored later, this is one part of keeping &lt;a href=&quot;https://ghost.org&quot;&gt;Ghost&lt;/a&gt; running even after the server restarts. To cleanup the rest, run these commands too (we’ll set these up again with the new user account):&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;chkconfig&lt;/span&gt; --del pm2-init.sh
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; /etc/init.d/pm2-init.sh
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; /var/lock/subsys/pm2-init.sh&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Run the &lt;a href=&quot;https://ghost.org&quot;&gt;Ghost&lt;/a&gt; application under the new user account&lt;/h2&gt;
&lt;p&gt;Next you’ll need to get &lt;a href=&quot;https://ghost.org&quot;&gt;Ghost&lt;/a&gt; running under the new user account. Firstly, change the ownership of all files (my &lt;a href=&quot;https://ghost.org&quot;&gt;Ghost&lt;/a&gt; instance is installed to &lt;code class=&quot;language-text&quot;&gt;/var/www/benbooth.co&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ &lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; /var/www/
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;chown&lt;/span&gt; -R ghost:ghost benbooth.co/&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I don’t think it would be necessary, but just to be sure, I cleared out the &lt;code class=&quot;language-text&quot;&gt;node_modules&lt;/code&gt; and re-installed the dependencies under the new user account (remember to change to the new user account):&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;su&lt;/span&gt; ghost
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ghost&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ &lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; benbooth.co/
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ghost&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ &lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; -rf node_modules/*
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ghost&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; --production&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, run the &lt;a href=&quot;https://ghost.org&quot;&gt;Ghost&lt;/a&gt; application using &lt;a href=&quot;https://github.com/Unitech/pm2&quot;&gt;PM2&lt;/a&gt; and save the running &lt;a href=&quot;https://github.com/Unitech/pm2&quot;&gt;PM2&lt;/a&gt; processes to file:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ghost&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ &lt;span class=&quot;token assign-left variable&quot;&gt;NODE_ENV&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;production pm2 start index.js --name &lt;span class=&quot;token string&quot;&gt;&quot;ghost&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ghost&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ pm2 save&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Persist &lt;a href=&quot;https://ghost.org&quot;&gt;Ghost&lt;/a&gt; application across server restarts&lt;/h2&gt;
&lt;p&gt;Keeping &lt;a href=&quot;https://github.com/Unitech/pm2&quot;&gt;PM2&lt;/a&gt; and your &lt;a href=&quot;https://ghost.org&quot;&gt;Ghost&lt;/a&gt; application running across server restarts is a little different depending on your OS/distribution, but &lt;a href=&quot;https://github.com/Unitech/pm2&quot;&gt;PM2&lt;/a&gt; will try to help you as much as possible. Just run:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ghost&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ pm2 startup &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;platform&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For me, running &lt;a href=&quot;https://www.centos.org/&quot;&gt;CentOS&lt;/a&gt;, I run &lt;code class=&quot;language-text&quot;&gt;pm2 startup centos&lt;/code&gt;. This will not work because it needs to be run using &lt;code class=&quot;language-text&quot;&gt;sudo&lt;/code&gt; and I don’t want to give my &lt;code class=&quot;language-text&quot;&gt;ghost&lt;/code&gt; user &lt;code class=&quot;language-text&quot;&gt;sudo&lt;/code&gt; permission. It will give you a full command that you can run using &lt;code class=&quot;language-text&quot;&gt;sudo&lt;/code&gt; but linked to the &lt;code class=&quot;language-text&quot;&gt;ghost&lt;/code&gt; user, copy that command. Now &lt;code class=&quot;language-text&quot;&gt;exit&lt;/code&gt; from the &lt;code class=&quot;language-text&quot;&gt;ghost&lt;/code&gt; shell back to your user shell and either run the copied command using &lt;code class=&quot;language-text&quot;&gt;sudo&lt;/code&gt;, or &lt;code class=&quot;language-text&quot;&gt;sudo su&lt;/code&gt; to get a &lt;code class=&quot;language-text&quot;&gt;root&lt;/code&gt; shell, and then run the copied command.&lt;/p&gt;
&lt;p&gt;At this stage I found that the startup script wasn’t actually bringing up the &lt;a href=&quot;https://github.com/Unitech/pm2&quot;&gt;PM2&lt;/a&gt; daemon, I had to manually edit the &lt;code class=&quot;language-text&quot;&gt;/etc/init.d/pm2-init.sh&lt;/code&gt; file to fix an issue (I’m assuming this is a bug, so should be temporary):&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;vim&lt;/span&gt; /etc/init.d/pm2-init.sh&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Look for the line &lt;code class=&quot;language-text&quot;&gt;USER=[username]&lt;/code&gt;. In my case, this was set to &lt;code class=&quot;language-text&quot;&gt;USER=root&lt;/code&gt; and I just had to change it to &lt;code class=&quot;language-text&quot;&gt;USER=ghost&lt;/code&gt; and save the file.&lt;/p&gt;
&lt;h2&gt;Extra: Add &lt;a href=&quot;https://app.keymetrics.io/#/register&quot;&gt;Keymetrics&lt;/a&gt; monitoring&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://app.keymetrics.io/#/register&quot;&gt;Keymetrics&lt;/a&gt; offers good &lt;em&gt;free&lt;/em&gt; monitoring for &lt;a href=&quot;https://github.com/Unitech/pm2&quot;&gt;PM2&lt;/a&gt; applications, if you haven’t already, &lt;a href=&quot;https://github.com/Unitech/pm2&quot;&gt;register&lt;/a&gt; for an account. You’ll get a &lt;strong&gt;private key&lt;/strong&gt; and a &lt;strong&gt;secret key&lt;/strong&gt;. Linking it to your &lt;a href=&quot;https://github.com/Unitech/pm2&quot;&gt;PM2&lt;/a&gt; instance is super-simple:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ghost&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ pm2 &lt;span class=&quot;token function&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;YOUR_SECRET_KEY&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;YOUR_PUBLIC_KEY&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you keep an eye on the &lt;a href=&quot;https://app.keymetrics.io/#/register&quot;&gt;Keymetrics&lt;/a&gt; dashboard, you should start seeing a heartbeat from your server shortly.&lt;/p&gt;
&lt;p&gt;If you already had &lt;a href=&quot;https://app.keymetrics.io/#/register&quot;&gt;Keymetrics&lt;/a&gt; running under your user account, and aren’t running any other &lt;a href=&quot;https://github.com/Unitech/pm2&quot;&gt;PM2&lt;/a&gt; applications, feel free to delete the &lt;a href=&quot;https://app.keymetrics.io/#/register&quot;&gt;Keymetrics&lt;/a&gt; link:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;$ pm2 &lt;span class=&quot;token function&quot;&gt;link&lt;/span&gt; delete &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;YOUR_PUBLIC_KEY&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[Writing a JavaScript Promises Library]]></title><description><![CDATA[Write an implementation of a JavaScript Promises library, and hopefully help you reading it and me writing this to better understand the workings of Promises.]]></description><link>https://benbooth.dev/writing-a-javascript-promises-library</link><guid isPermaLink="false">https://benbooth.dev/writing-a-javascript-promises-library</guid><dc:creator><![CDATA[Ben Booth]]></dc:creator><pubDate>Mon, 04 May 2015 12:16:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;#update20150529&quot;&gt;Updated 29/05/2015&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My first exposure to JavaScript Promises was at a JavaScript &lt;a href=&quot;https://www.sydjs.com/&quot;&gt;meetup&lt;/a&gt; a couple of years ago and despite being a talk by a very good presenter, it was an early stage in my JavaScript understanding and most of the topic went over my head. Nowadays Promises are quite common and most developers will probably have had some level of exposure, whether they understand them or not. They’re part of the EcmaScript 6 (ES6) specification so if you don’t understand them, now is a great time to learn.&lt;/p&gt;
&lt;p&gt;We’re going to write an implementation of a JavaScript Promises library, and hopefully this helps you reading it and me writing it to better understand the workings of Promises. Let’s dive right into the example and a bit of an explanation of how Promises are used. For more information, check out &lt;a href=&quot;https://twitter.com/rauschma&quot;&gt;Dr. Axel Rauschmayer&lt;/a&gt;’s article on &lt;a href=&quot;http://www.2ality.com/2014/10/es6-promises-api.html&quot;&gt;ES6 Promises&lt;/a&gt; or &lt;a href=&quot;https://twitter.com/jaffathecake&quot;&gt;Jake Archibald&lt;/a&gt;’s article on &lt;a href=&quot;https://developers.google.com/web/fundamentals/primers/promises&quot;&gt;Javascript Promises&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Using Promises and the demo app&lt;/h2&gt;
&lt;p&gt;The basic usage of Promises is something like below, so that’s where we’re going to start. &lt;code class=&quot;language-text&quot;&gt;doSomething()&lt;/code&gt; is going to do something asynchronous and then if it succeeds, we want to be able to use or manipulate the resulting value (if any) from &lt;code class=&quot;language-text&quot;&gt;doSomething()&lt;/code&gt; in the success function. If something goes wrong in &lt;code class=&quot;language-text&quot;&gt;doSomething()&lt;/code&gt; we want to be able to handle the error in the failure function.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// success&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// failure&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Take a look at &lt;a href=&quot;https://github.com/bkbooth/promise/blob/step0/js/script.js&quot;&gt;script.js&lt;/a&gt; in the demonstration repository at branch &lt;code class=&quot;language-text&quot;&gt;step0&lt;/code&gt; for how we’ll use the Promise library for the initial implementation.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;button&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;click&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;clickListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;setLoading&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;imgUrl&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; responseType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;blob&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;setLoading&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      img&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createObjectURL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;setLoading&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Got no image!&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We’re fetching an image, then on success we stop the loading spinner and set the &lt;code class=&quot;language-text&quot;&gt;&amp;lt;img&gt;.src&lt;/code&gt; to an Object URL containing the loaded image data. On failure we still stop the loading spinner and log the error. We’ll improve on this and remove the duplication as we improve the Promise library.&lt;/p&gt;
&lt;p&gt;Inside &lt;code class=&quot;language-text&quot;&gt;doSomething()&lt;/code&gt; is where we’ll actually setup our Promise, start an asynchronous task and then ‘resolve’ (execute the success handler function) or ‘reject’ (execute the failure handler function) the Promise. A Promise can only be ‘settled’ (either ‘resolved’ or ‘rejected’) once. For the ES6 standard of Promises, we pass a function to the &lt;code class=&quot;language-text&quot;&gt;new Promise()&lt;/code&gt; constructor. The function has two parameters &lt;code class=&quot;language-text&quot;&gt;resolve&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;reject&lt;/code&gt; which are both functions that we use to resolve or reject the Promise after our asynchronous task. In the example below, &lt;code class=&quot;language-text&quot;&gt;AsyncTask()&lt;/code&gt; is a fictional utility that we can attach success and error handler functions to the &lt;code class=&quot;language-text&quot;&gt;onSuccess&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;onError&lt;/code&gt; properties.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; task &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AsyncTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    task&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onSuccess&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    task&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onError&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    task&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Looking at &lt;a href=&quot;https://github.com/bkbooth/promise/blob/step0/js/fetch.js&quot;&gt;fetch.js&lt;/a&gt; in the demonstration repository at branch &lt;code class=&quot;language-text&quot;&gt;step0&lt;/code&gt; you’ll see how I’ve wrapped an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest&quot;&gt;XMLHttpRequest&lt;/a&gt; with an asynchronous &lt;code class=&quot;language-text&quot;&gt;fetch()&lt;/code&gt; function that returns a Promise. I won’t explain this in any detail and it won’t be changing through this article, just take note of where we create the &lt;code class=&quot;language-text&quot;&gt;new Promise()&lt;/code&gt; and where we &lt;code class=&quot;language-text&quot;&gt;resolve&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;reject&lt;/code&gt; the Promise.&lt;/p&gt;
&lt;p&gt;The demonstration is just a placeholder image and a ‘Get Random Image!’ button. Clicking the button downloads a random 500x500 image from &lt;a href=&quot;https://lorempixel.com/&quot;&gt;lorempixel.com&lt;/a&gt; and replaces the placeholder image with the downloaded image data.&lt;/p&gt;
&lt;p&gt;To run the demonstration you’ll need to clone the git repository, &lt;code class=&quot;language-text&quot;&gt;git checkout&lt;/code&gt; the correct branch (in this case &lt;code class=&quot;language-text&quot;&gt;step0&lt;/code&gt;) and then serve the files using a HTTP server. If you have &lt;a href=&quot;https://www.python.org/downloads/&quot;&gt;Python 2&lt;/a&gt; or &lt;a href=&quot;https://www.python.org/downloads/&quot;&gt;Python 3&lt;/a&gt; installed, the easiest is to just run &lt;code class=&quot;language-text&quot;&gt;python -m SimpleHTTPServer&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;python3 -m http.server&lt;/code&gt; respectively from the command line inside the cloned git repository.&lt;/p&gt;
&lt;h2&gt;Basic success/failure handling&lt;/h2&gt;
&lt;p&gt;If you try running the demonstration now, you’ll get an error because &lt;a href=&quot;https://github.com/bkbooth/promise/blob/step0/js/promise.js&quot;&gt;promise.js&lt;/a&gt; is just an empty stub at the moment. To get the demonstration working, we’ll need to flesh out the constructor function and implement the &lt;code class=&quot;language-text&quot;&gt;.then()&lt;/code&gt; method. The constructor just needs to initialise two internal properties to store the success and failure handler functions that are passed into &lt;code class=&quot;language-text&quot;&gt;.then()&lt;/code&gt;, and then it needs to call the deferred function that is passed into the constructor. We’ll need to provide the &lt;code class=&quot;language-text&quot;&gt;resolve&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;reject&lt;/code&gt; methods that will be called from inside the deferred function that was passed into the constructor. Our initial, very basic implementation looks like this.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// promise.js&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;deferred&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_success &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_failure &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;deferred&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_success&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_success&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_failure&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_failure&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;success&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; failure&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;success&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_success &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; success&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;failure&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_failure &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; failure&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will get the current demonstration application working. In the demo repository, &lt;code class=&quot;language-text&quot;&gt;git checkout step1&lt;/code&gt; to see it working. At the moment, you can only place a single &lt;code class=&quot;language-text&quot;&gt;.then()&lt;/code&gt; after the returned Promise from &lt;code class=&quot;language-text&quot;&gt;fetch()&lt;/code&gt;, so we just log the error if you have no network connection or request a bad URL. Change &lt;code class=&quot;language-text&quot;&gt;fetch(imgUrl, { responseType: &apos;blob&apos; });&lt;/code&gt; to &lt;code class=&quot;language-text&quot;&gt;fetch(errorUrl, { responseType: &apos;blob&apos; });&lt;/code&gt; to demonstrate this. Don’t forget to change it back!&lt;/p&gt;
&lt;h2&gt;Handler chaining&lt;/h2&gt;
&lt;p&gt;One of the great strengths of the Promise pattern is being able to chain operations to happen after an asynchronous operation, and eventually be able to perform a number of asynchronous operations in a style that looks synchronous, or is at least easier for us to understand and reason with. We want to be able to do something like this.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Have a quick look at &lt;a href=&quot;https://github.com/bkbooth/promise/blob/step2/js/script.js&quot;&gt;script.js&lt;/a&gt; on branch &lt;code class=&quot;language-text&quot;&gt;step2&lt;/code&gt; to see how the demo has been changed. We don’t need to duplicate the &lt;code class=&quot;language-text&quot;&gt;setLoading(false)&lt;/code&gt; calls anymore, we can do that at the end of the chain. We’ve separated some of the processing and notice the new &lt;code class=&quot;language-text&quot;&gt;.catch()&lt;/code&gt; method. We’ll start by quickly implementing &lt;code class=&quot;language-text&quot;&gt;.catch()&lt;/code&gt; in the Promise library, it’s just a convenience function for &lt;code class=&quot;language-text&quot;&gt;.then(undefined, failure())&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;failure&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; failure&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;Promise()&lt;/code&gt; constructor doesn’t need to change at all, we’ll even keep the &lt;code class=&quot;language-text&quot;&gt;if (this._success) { ... }&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;if (this._failure) { ... }&lt;/code&gt; checks around the handler calls because at the end of the chain the handler functions won’t be defined. Our &lt;code class=&quot;language-text&quot;&gt;.then()&lt;/code&gt; method needs to change quite substantially, the first and most important change is that to facilitate chaining &lt;code class=&quot;language-text&quot;&gt;.then()&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;.catch()&lt;/code&gt; handlers, we must always return a &lt;code class=&quot;language-text&quot;&gt;new Promise()&lt;/code&gt;. Next we’ll always need to define &lt;code class=&quot;language-text&quot;&gt;this._success()&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;this._failure()&lt;/code&gt; methods. If &lt;code class=&quot;language-text&quot;&gt;.then()&lt;/code&gt; provides a success handler we’ll call &lt;code class=&quot;language-text&quot;&gt;success()&lt;/code&gt; with the passed in value, then resolve the new Promise with the result of &lt;code class=&quot;language-text&quot;&gt;success(value)&lt;/code&gt;, otherwise we’ll just resolve the new Promise with the passed in value which just hands the passed in value along to the next handler in the chain. If &lt;code class=&quot;language-text&quot;&gt;.then()&lt;/code&gt; provides a failure handler the processing is quite similar, we’ll call &lt;code class=&quot;language-text&quot;&gt;failure()&lt;/code&gt; with the passed in error and then because the error should be handled after the failure handler, we resolve the new Promise with the result of &lt;code class=&quot;language-text&quot;&gt;failure(error)&lt;/code&gt;. If there’s not a failure handler provide, we just pass the error down the chain. The revised &lt;code class=&quot;language-text&quot;&gt;.then()&lt;/code&gt; method looks like this.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;success&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; failure&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// Always define this._success() to forward success value if not handled locally&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;_success&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;success&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token comment&quot;&gt;// Handle success value locally, then pass on new success value&lt;/span&gt;
          &lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token comment&quot;&gt;// No local success handler, pass on success value&lt;/span&gt;
          &lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;token comment&quot;&gt;// Always define this._failure() to forward error if not handled locally&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;_failure&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;failure&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token comment&quot;&gt;// Handle error locally, then pass on new success value&lt;/span&gt;
          &lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;failure&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token comment&quot;&gt;// No local failure handler, pass on error&lt;/span&gt;
          &lt;span class=&quot;token function&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you &lt;code class=&quot;language-text&quot;&gt;git checkout step2&lt;/code&gt; and run the demonstration now, the functionality is unchanged, but the code to achieve it is a bit nicer.&lt;/p&gt;
&lt;h2&gt;Promises in the handler chain&lt;/h2&gt;
&lt;p&gt;One of the best things you can do with Promises is return a Promise within a handler, this lets you flatten out a chain of asynchronous operations. Take a look at &lt;a href=&quot;https://github.com/bkbooth/promise/blob/step3/js/script.js&quot;&gt;script.js&lt;/a&gt; on branch &lt;code class=&quot;language-text&quot;&gt;step3&lt;/code&gt; and you’ll notice that we’ve moved the &lt;code class=&quot;language-text&quot;&gt;.catch()&lt;/code&gt; handler to the top of the chain and we’re returning a new Promise via another call to &lt;code class=&quot;language-text&quot;&gt;fetch()&lt;/code&gt;, this time fetching a local fallback image.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;imgUrl&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; responseType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;blob&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Got no image!&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Getting default image&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;defaultImgUrl&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; responseType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;blob&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We only need to make one change to our &lt;code class=&quot;language-text&quot;&gt;this._success()&lt;/code&gt; handler inside the &lt;code class=&quot;language-text&quot;&gt;.this()&lt;/code&gt; method. It now needs to check if the passed in value is an instance of &lt;code class=&quot;language-text&quot;&gt;Promise&lt;/code&gt;, call &lt;code class=&quot;language-text&quot;&gt;.then()&lt;/code&gt; on it if it is a Promise and resolve/reject the outer Promise based on the result/error of the passed in Promise. Replace the line &lt;code class=&quot;language-text&quot;&gt;resolve(success(value));&lt;/code&gt; with the following block to handle Promises as a value.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Resolve/reject this Promise after the passed in Promise is resolved/rejected&lt;/span&gt;
  value&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// Handle resulting value locally, then pass on new success value&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// Pass on resulting error&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Handle success value locally, then pass on new success value&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you &lt;code class=&quot;language-text&quot;&gt;git checkout step3&lt;/code&gt; and run the demonstration now, there’s one major change to the functionality. If the initial request to fetch &lt;code class=&quot;language-text&quot;&gt;imgUrl&lt;/code&gt; fails, the &lt;code class=&quot;language-text&quot;&gt;.catch()&lt;/code&gt; handler returns a new fetch request for &lt;code class=&quot;language-text&quot;&gt;defaultImgUrl&lt;/code&gt;, this is a local fallback image so loading it shouldn’t fail. Try replacing the first &lt;code class=&quot;language-text&quot;&gt;fetch(imgUrl, { responseType: &apos;blob&apos; });&lt;/code&gt; with &lt;code class=&quot;language-text&quot;&gt;fetch(errorUrl, { responseType: &apos;blob&apos; });&lt;/code&gt; to demonstrate loading the fallback image and then continuing down the chain of handlers.&lt;/p&gt;
&lt;h2&gt;Slightly more advanced&lt;/h2&gt;
&lt;p&gt;Two very useful utility functions that a Promise library should provide are &lt;code class=&quot;language-text&quot;&gt;Promise.race()&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;Promise.all()&lt;/code&gt;. Both of these functions take an array of Promises and return a single Promise. &lt;code class=&quot;language-text&quot;&gt;Promise.race()&lt;/code&gt; resolves or rejects it’s single returned Promise with the result or error from the first of it’s passed in Promises to resolve or reject. The rest of the passed in Promises are ignored, regardless if they resolve or reject. &lt;code class=&quot;language-text&quot;&gt;Promise.all()&lt;/code&gt; resolves it’s single returned Promise with an array of results resolved from all of the passed in Promises. The indexes of the results array match the index of the Promise that resolved the result from the passed in array of Promises. If any of the Promises passed into &lt;code class=&quot;language-text&quot;&gt;Promise.all()&lt;/code&gt; are rejected, the single returned Promise is immediately rejected with the error and all other passed in Promises are ignored, regardless if they are resolved or rejected. &lt;code class=&quot;language-text&quot;&gt;Promise.all()&lt;/code&gt; looks like this.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;imgUrl&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; responseType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;blob&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// fetch 0&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;imgUrl&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; responseType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;blob&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// fetch 1&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// results[0] will contain the result of fetch 0&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// results[1] will contain the result of fetch 1&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Try and think about how you might implement &lt;code class=&quot;language-text&quot;&gt;Promise.race()&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;Promise.all()&lt;/code&gt;. Take a look at &lt;a href=&quot;https://github.com/bkbooth/promise/blob/step4/js/script.js&quot;&gt;script.js&lt;/a&gt; at branches &lt;a href=&quot;https://github.com/bkbooth/promise/blob/step4/js/script.js&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;step4&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://github.com/bkbooth/promise/blob/step5/js/script.js&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;step5&lt;/code&gt;&lt;/a&gt; for the demonstration examples of &lt;code class=&quot;language-text&quot;&gt;Promise.race()&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;Promise.all()&lt;/code&gt; respectively. (&lt;code class=&quot;language-text&quot;&gt;git checkout step4&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;git checkout step5&lt;/code&gt;) to run them. Below are my implementations.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;Promise.race()&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;race&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;promises&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; settled &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Keep track if any Promises have been settled&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    promises&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;settled&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;// First Promise to resolve/reject, resolve with result and set settled flag&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            settled &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;settled&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;// First Promise to resolve/reject, reject with error and set settled flag&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            settled &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;Promise.all()&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;all&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;promises&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; settled &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Keep track of the number of Promises settled&lt;/span&gt;
    results &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Keep track of Promise resolutions&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    promises&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;promise&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token comment&quot;&gt;// Add resolution to the same index as the Promises array&lt;/span&gt;
          results&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;token comment&quot;&gt;// Increment number of settled Promises, resolve when all are resolved&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;settled &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; promises&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;results&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token comment&quot;&gt;// Reject immediately if any Promises reject&lt;/span&gt;
          &lt;span class=&quot;token function&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a name=&quot;update20150529&quot;&gt;&lt;/a&gt;&lt;strong&gt;Update 29/05/2015&lt;/strong&gt; &lt;a href=&quot;https://me.getify.com/&quot;&gt;Kyle Simpson&lt;/a&gt; (&lt;a href=&quot;https://twitter.com/getify&quot;&gt;@getify&lt;/a&gt;) took some time to review this article and gave some awesome feedback. I’ve been slowly rewriting my Promises implementation, but I haven’t had as much time to work on it as I’d like so I thought I should post an update in the meantime. Firstly, this implementation isn’t currently &lt;a href=&quot;https://promisesaplus.com/&quot;&gt;Promises/A+&lt;/a&gt; compliant, that was never an original goal, but it is something I’m working towards now. Kyle has a lightweight Promises/A+ compliant implementation called &lt;a href=&quot;https://github.com/getify/native-promise-only&quot;&gt;Native Promises Only (NPO)&lt;/a&gt;. Two very important things to note about my current implementation:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;My handlers aren’t async! This is a big no-no, but relatively easily fixed by wrapping their execution in &lt;code class=&quot;language-text&quot;&gt;setTimeout(..., 0)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Promises should recursively resolve to eventually return a non-Promise value&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[Beware the DOM Reflow]]></title><description><![CDATA[Don't ever use a CSS transition with any CSS property that causes a DOM reflow, you will never get smooth transitions. Try to use CSS transform properties for transitions.]]></description><link>https://benbooth.dev/beware-the-dom-reflow</link><guid isPermaLink="false">https://benbooth.dev/beware-the-dom-reflow</guid><dc:creator><![CDATA[Ben Booth]]></dc:creator><pubDate>Fri, 14 Mar 2014 06:17:00 GMT</pubDate><content:encoded>&lt;h2&gt;TL;DR&lt;/h2&gt;
&lt;p&gt;Don’t &lt;em&gt;ever&lt;/em&gt; use a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Using_CSS_transitions&quot; title=&quot;CSS Transition&quot;&gt;CSS transition&lt;/a&gt; with any CSS property that causes a &lt;a href=&quot;https://stackoverflow.com/questions/510213/when-does-reflow-happen-in-a-dom-environment&quot; title=&quot;DOM Reflow&quot;&gt;DOM reflow&lt;/a&gt;, you will never get smooth transitions, even if you attempt to use a &lt;a href=&quot;https://stackoverflow.com/questions/10814178/css-performance-relative-to-translatez0&quot; title=&quot;translate3D hack&quot;&gt;common hack&lt;/a&gt; to force GPU rendering of the transitioning DOM element. Try to use the CSS &lt;code class=&quot;language-text&quot;&gt;transform&lt;/code&gt; property instead of something like &lt;code class=&quot;language-text&quot;&gt;left&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;width&lt;/code&gt; for transitions.&lt;/p&gt;
&lt;h2&gt;A little background&lt;/h2&gt;
&lt;p&gt;I’ve been working on a mobile app using &lt;a href=&quot;https://cordova.apache.org&quot; title=&quot;Apache Cordova&quot;&gt;Cordova&lt;/a&gt; (&lt;a href=&quot;https://phonegap.com&quot; title=&quot;Adobe PhoneGap&quot;&gt;PhoneGap&lt;/a&gt;) and &lt;a href=&quot;https://angularjs.org&quot; title=&quot;AngularJS&quot;&gt;AngularJS&lt;/a&gt; which has been quite fun to work with so far. I haven’t done any proper performance optimising yet, I’ve just been trying to stay on top of things as I notice them. One particular issue had been bothering me enough that I ended up looking into (and solving) it outside of work.&lt;/p&gt;
&lt;p&gt;A little while ago I added a simple CSS slide animation between the app states/views but the animation was terribly choppy when testing in a browser and when testing on my phone (Xperia Z1 which isn’t exactly a slow device). It was so bad that there’s no way it could be put into a finished app, but I left it in there planning to look into eventually. My suspicion was that it was due to a &lt;a href=&quot;https://stackoverflow.com/questions/510213/when-does-reflow-happen-in-a-dom-environment&quot; title=&quot;DOM Reflow&quot;&gt;DOM reflow&lt;/a&gt; but I had thought that the problem was refreshed data coming back from the server mid-animation causing a DOM update, reflow and the choppiness.&lt;/p&gt;
&lt;p&gt;Recently I added a slide out menu similar to many modern mobile apps which included another CSS transition, again terribly choppy but this time it was happening on an element that was already in the DOM and was not getting refreshed data from the server each time it appeared. The slide out menu looked great and was behaving just like I’d planned but the animation choppiness was killing it so I had to investigate further.&lt;/p&gt;
&lt;h2&gt;A false solution&lt;/h2&gt;
&lt;p&gt;The first solution I ran into and seemed to be recommended (even if sparingly) by a number of sources was to use a CSS 3D transform that would have no visual effect but would theoretically offload the rendering of that element to the GPU in modern browsers.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;css&quot;&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translate3D&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I wasn’t really happy with the idea of using a &lt;a href=&quot;https://stackoverflow.com/questions/10814178/css-performance-relative-to-translatez0&quot; title=&quot;translate3D hack&quot;&gt;hack solution&lt;/a&gt; but I gave it a try and it didn’t even seem to be having any effect in my situation.&lt;/p&gt;
&lt;h2&gt;The solution&lt;/h2&gt;
&lt;p&gt;Finally I came across another explanation that made much more sense, I was transitioning using the &lt;code class=&quot;language-text&quot;&gt;left&lt;/code&gt; CSS property which was triggering a &lt;a href=&quot;https://stackoverflow.com/questions/510213/when-does-reflow-happen-in-a-dom-environment&quot; title=&quot;DOM Reflow&quot;&gt;DOM reflow&lt;/a&gt; each time it changed. The solution was to use a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Using_CSS_transforms&quot; title=&quot;CSS Transform&quot;&gt;CSS transform&lt;/a&gt; properly instead of as a hack, so in my case where I was basically wanting to transition the element along the x-axis I changed my start and end states from:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;css&quot;&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* start */&lt;/span&gt;
&lt;span class=&quot;token property&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* end */&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;css&quot;&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translateX&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;100%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* start */&lt;/span&gt;
&lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;translateX&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* end */&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Notes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You may need to include browser targeted CSS properties such as &lt;code class=&quot;language-text&quot;&gt;-webkit-transform&lt;/code&gt; depending on your application.&lt;/li&gt;
&lt;li&gt;This also produced the added benefit that I no longer needed to absolutely position the element that I was transitioning.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This produced silky smooth animations in both of my testing environments (browser and phone). Using a combination of the various CSS transforms (&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Using_CSS_transforms&quot; title=&quot;CSS Transform&quot;&gt;read up on them&lt;/a&gt; for more information) and standard CSS properties that do not cause a DOM reflow (such as &lt;code class=&quot;language-text&quot;&gt;opacity&lt;/code&gt;) I’ve been able to produce a several subtle animations in my app that are also perfectly smooth.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Pregnancy Risk Factors]]></title><description><![CDATA[Musings about some of the public perceptions associated with the various eating and lifestyle guidelines given to pregnant women.]]></description><link>https://benbooth.dev/pregnancy-risk-factors</link><guid isPermaLink="false">https://benbooth.dev/pregnancy-risk-factors</guid><dc:creator><![CDATA[Ben Booth]]></dc:creator><pubDate>Tue, 11 Mar 2014 21:56:00 GMT</pubDate><content:encoded>&lt;p&gt;So I’m a guy, not a medical professional and I’m going to talk about pregnancy, this is probably one of the few seasons in life where a guy can get away with it so let me just get up on my soap box.&lt;/p&gt;
&lt;p&gt;One of the things that has surprised me most talking to various people throughout my wife’s pregnancy is how there’s almost a negative reaction from older generations (and to a lesser extent others in the same generation) when my wife tells them that she’s following the various eating and lifestyle guidelines that are given to pregnant women. “Back in my days we never had all of these guidelines and we still managed to have children fine,” is along the lines of the average reaction.&lt;/p&gt;
&lt;p&gt;So just in case you’re not fully aware, as a pregnant mother there are certain &lt;em&gt;risk factors&lt;/em&gt; which you are advised to steer clear of during your pregnancy. These include obvious things like drinking alcohol, smoking and less obvious things like eating soft cheeses, eating food that’s been sitting out in a buffet or eating under-cooked meat. I’d like to acknowledge that yes, pregnant mothers have done many of these things for centuries and have still managed to have healthy babies. It is for this reason that I emphasised the phrase “risk factors” because I think it’s important that this is the reason why my wife and many other’s choose to follow the guidelines.&lt;/p&gt;
&lt;p&gt;Pregnancy just like everything else health-related is the subject of regular and ongoing scientific study. Only with pregnancy you’re dealing with the life of a tiny, developing human. Most of us wouldn’t question when medical professionals give us a list of risk factors for something like the days leading up to a surgical procedure so why is it that many immediately question and then downplay the risk factors when dealing with pregnancy and new life?&lt;/p&gt;
&lt;p&gt;I have a few theories, so make what you will of them…&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;There almost seems to be a kind of one upmanship associated with pregnancy, as if somehow mother’s want to do pregnancy &lt;em&gt;better&lt;/em&gt; than others. This is a season of life where I’m seeing and hearing about a lot of pregnancies and I think the only thing you can be guaranteed no matter how many precautions you ignore or adhere to is that there are no guarantees how your pregnancy will go.&lt;/li&gt;
&lt;li&gt;I think there is a generational factor to this problem where older generations talk of how they did pregnancy without all of the modern guidelines and I think in some cases this puts pressure on the younger generation of mother’s to ignore the guidelines to live up to the expectations of the older generation. I definitely don’t want to disrespect the older generations, giving birth to and raising children is a great privilege and blessing and I know that every mother seeks to do the best by their children. I’ve visited third world villages and have seen that children are both born and raised in the most desperate conditions so I think the point is that if you have access to the latest medical attention and advice you’d be unwise to ignore it.&lt;/li&gt;
&lt;li&gt;Finally I think there is a lifestyle problem here, mother’s don’t want to give up doing, eating or drinking things that they love for the better part of a year. I think our society has a little to blame for this, we probably should honour and revere pregnancy more so that giving up luxuries for a few months doesn’t seem like such a big sacrifice.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I had very little to do with my wife making the decision that she would try to adhere to the guidelines and if I’m honest I was probably a little negative about all of the guidelines being a little over the top myself. I was incredibly proud of her making that decision though and while she hasn’t stuck to them 100% she has tried to be sensible about it. A point that she made to me at the time and I think really brings this home is that in most cases you could probably get away with not following the guidelines but imagine the devastation you would feel as a mother if you had a pregnancy where there were complications that arose that could have been avoided just by following the guidelines?&lt;/p&gt;
&lt;p&gt;So here’s to pregnant mother’s, you’re doing something truly amazing. Try to find some time to appreciate that with everything that’s going on. No matter how you’re feeling know that you look amazing too.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Simple JavaScript template engine]]></title><description><![CDATA[I wrote a simple JavaScript template engine to load and parse templates from HTML files for a HTML/CSS/JS version of Tetris.]]></description><link>https://benbooth.dev/simple-javascript-template-engine</link><guid isPermaLink="false">https://benbooth.dev/simple-javascript-template-engine</guid><dc:creator><![CDATA[Ben Booth]]></dc:creator><pubDate>Sun, 29 Dec 2013 13:11:00 GMT</pubDate><content:encoded>&lt;p&gt;Around 6 months ago while learning JavaScript properly and looking for work as a JavaScript developer I started working on a pure HTML/CSS/JS version of Tetris (&lt;a href=&quot;https://blockdrop.benbooth.dev&quot;&gt;BlockDrop&lt;/a&gt; - &lt;a href=&quot;https://github.com/bkbooth/BlockDrop&quot;&gt;github&lt;/a&gt;) to experiment and play with my new skills. It’s been a while since I’ve touched it but I just started looking at it again recently and there’s quite a lot that I’d do differently now so I started rewriting it from the ground up. I haven’t got that far with the actual rewrite but one of the things I really wanted to do differently and therefore implemented it first was a simple templating engine so that I could get all the HTML out of my JavaScript.&lt;/p&gt;
&lt;h2&gt;Setting up a module&lt;/h2&gt;
&lt;p&gt;First things first, another issue I wanted to resolve from my original BlockDrop implementation was to make the code a little more modular so here’s a little boilerplate I’ve been using to setup my modules.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; TemplateEngine &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// private stuff here&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// public stuff in here&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All we’re doing here is putting the module into an &lt;a href=&quot;https://en.wikipedia.org/wiki/Immediately-invoked_function_expression&quot;&gt;IIFE&lt;/a&gt; (immediately-invoked function expression) and assigning it to the global TemplateEngine variable.&lt;/p&gt;
&lt;h2&gt;Loading local files&lt;/h2&gt;
&lt;p&gt;The first thing the template engine needs to be able to do is load the HTML templates/partials. The way I chose to do this was using an &lt;code class=&quot;language-text&quot;&gt;XMLHttpRequest&lt;/code&gt;, to get this to work you’ll need your templates to be served by some kind of web server.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; TemplateEngine &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; xhr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;XMLHttpRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;fileName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; contents &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      xhr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onreadystatechange&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;xhr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;readyState &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; xhr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          contents &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; xhr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;responseText&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      xhr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;GET&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fileName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      xhr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; contents&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is all pretty straight-forward if you’ve done any work with AJAX in native JS, we’re basically just setting up an XHR object and returning the contents of the requested file as a string. One thing to note here is the third &lt;code class=&quot;language-text&quot;&gt;false&lt;/code&gt; parameter to the &lt;code class=&quot;language-text&quot;&gt;xhr.open()&lt;/code&gt; call, this means we’re not actually doing an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#open()&quot;&gt;asynchronous request&lt;/a&gt;. Since we’re just requesting local files this shouldn’t cause much delay, also for my particular application all of the templates will be loaded once during the first initialisation. For a more robust solution you might want to keep the request asynchronous and return a promise instead of the actual file contents.&lt;/p&gt;
&lt;h2&gt;Caching loaded templates&lt;/h2&gt;
&lt;p&gt;For my application the most common template I’ll be using are the actual pieces (shapes of 4 blocks). We wouldn’t want to make a new XHR every time we need a new piece, especially since my current implementation doesn’t make the requests asynchronously. A simple solution is to store loaded templates into a cache object the first time they’re loaded and then simply retrieve them from the cache for subsequent requests. We can even take advantage of &lt;code class=&quot;language-text&quot;&gt;localStorage&lt;/code&gt; to cache the templates in the user’s browser for future usage. Here’s my modifications to include caching.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; TemplateEngine &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; xhr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;XMLHttpRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    cache &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;localStorage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;yourapp.cache.template&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;fileName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; contents &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Utils&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hashCode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fileName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;contents&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        contents &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// XHR unchanged from previous step&lt;/span&gt;

        cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Utils&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hashCode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fileName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; contents&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        localStorage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;yourapp.cache.template&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cache&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; contents&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We try to initialise our cache object from &lt;code class=&quot;language-text&quot;&gt;localStorage&lt;/code&gt; but if it doesn’t exist yet we intialise it to an empty object. You can use whatever key you want when getting the cache object, just make sure you use the same key when setting the cache later. &lt;code class=&quot;language-text&quot;&gt;Utils.hashCode()&lt;/code&gt; is just a simple hashing function that I &lt;a href=&quot;https://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/&quot;&gt;borrowed&lt;/a&gt;. I chose to use a hash because the template key in the cache object needs to be unique and needs to be based on the template filename so we can retrieve it when requesting the same filename later.&lt;/p&gt;
&lt;h2&gt;Simple tag replacements&lt;/h2&gt;
&lt;p&gt;The most basic thing we’ll need to do with a template engine is find and replace data from the template file with our actual application data. I opted for double-curlies (eg. &lt;code class=&quot;language-text&quot;&gt;{{ dataItem }}&lt;/code&gt;) in the templates to define areas that should be replaced with application data. In JavaScript the simplest way to represent this is an object where the key matches the double-curly bracket fields in the template and the value is the actual data you want inserted (eg. &lt;code class=&quot;language-text&quot;&gt;{ dataItem: &quot;dataValue&quot; }&lt;/code&gt;).&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;replaceTags&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;templateString&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; replaceMap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; templateString&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;\{\{\s*([a-zA-Z0-9\.\$_]+)\s*\}\}&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;match&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; p1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; replaceMap&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;p1&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; replaceMap&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;p1&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The heavy-lifting here is all done with a &lt;code class=&quot;language-text&quot;&gt;RegExp&lt;/code&gt; String replace. I won’t go into the details of regular expressions here but it’s worth noting that my allowed character set &lt;code class=&quot;language-text&quot;&gt;[a-zA-Z0-9\.\$_]&lt;/code&gt; might be too restrictive or too liberal for your application, I’ve been modifying this set as needed. We’re capturing the set and can access it as the 2nd parameter in the replace function.&lt;/p&gt;
&lt;h2&gt;Parsing the transformed string&lt;/h2&gt;
&lt;p&gt;Now that we’ve got a string representing some HTML which has all of the template tags replaced with actual application data we’ll want to parse it into a DOM object so that we can add it into an application’s DOM. There’s some existing functionality to handle that.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; TemplateEngine &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; parser &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DOMParser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;parse&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;templateString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; parser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parseFromString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;templateString&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;text/xml&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;childNodes&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;parseFromString()&lt;/code&gt; function provided by &lt;code class=&quot;language-text&quot;&gt;DOMParser()&lt;/code&gt; returns a root DOM node so we’ll need to get the first child node of the returned object so that we can attach that node into an application’s DOM.&lt;/p&gt;
&lt;h2&gt;Moving forward&lt;/h2&gt;
&lt;p&gt;What I’ve detailed here was my starting point but I’ve since found the need for my template engine to be able to handle loops which adds some more complexity which I won’t cover here. I also refactored a little so that &lt;code class=&quot;language-text&quot;&gt;load()&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;transform()&lt;/code&gt; (which calls &lt;code class=&quot;language-text&quot;&gt;replaceTags()&lt;/code&gt; as well as handling repeating sections in the templates) and &lt;code class=&quot;language-text&quot;&gt;parse()&lt;/code&gt; are all private functions of the &lt;code class=&quot;language-text&quot;&gt;TemplateEngine&lt;/code&gt; object. The only public functions are &lt;code class=&quot;language-text&quot;&gt;get()&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;getString()&lt;/code&gt; which both load and transform the templates, &lt;code class=&quot;language-text&quot;&gt;get()&lt;/code&gt; additionally parses the strings while &lt;code class=&quot;language-text&quot;&gt;getString()&lt;/code&gt; does not, this was required so that I could use templates within templates.&lt;/p&gt;</content:encoded></item></channel></rss>