<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Zaptic</title>
    <description>The latest articles on DEV Community by Zaptic (@zaptic).</description>
    <link>https://dev.to/zaptic</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F42%2F85595744-ab7e-4235-9ba9-d94b33d8757e.png</url>
      <title>DEV Community: Zaptic</title>
      <link>https://dev.to/zaptic</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zaptic"/>
    <language>en</language>
    <item>
      <title>Moving from elm-validate to elm-verify</title>
      <dc:creator>Michael Jones</dc:creator>
      <pubDate>Fri, 16 Feb 2018 14:50:06 +0000</pubDate>
      <link>https://dev.to/zaptic/moving-from-elm-validate-to-elm-verify--19pc</link>
      <guid>https://dev.to/zaptic/moving-from-elm-validate-to-elm-verify--19pc</guid>
      <description>&lt;p&gt;At &lt;a href="https://www.zaptic.com"&gt;Zaptic&lt;/a&gt;, we use Elm for our business administration website to allow customers to configure the processes that they want to carry out. The site contains a number of different forms for adding &amp;amp; editing various entities in our system. All of these forms benefit from client side validation before the data is submitted to our servers. &lt;/p&gt;

&lt;p&gt;When we started writing our Elm code, the recommended approach to form validation was the &lt;a href="https://github.com/rtfeldman/elm-validate"&gt;rtfeldman/elm-validate&lt;/a&gt; library. For a form backed by a data structure like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="kt"&gt;ProductGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt; &lt;span class="kt"&gt;Mode&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;selectedProducts&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Dict&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="kt"&gt;Product&lt;/span&gt;

    &lt;span class="c1"&gt;-- Used for storing validation errors&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Field&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We might have a validation function like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;validateProductGroup&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Validator&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Field&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;ProductGroup&lt;/span&gt;
&lt;span class="n"&gt;validateProductGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;Validate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ifBlank&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;NameField&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Please provide a name"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ifNothing&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;ModeField&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Please select a mode"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;selectedProducts&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ifEmptyDict&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;ProductsField&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Please select at least one product"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This checks that the &lt;code&gt;name&lt;/code&gt; field isn't blank, that a &lt;code&gt;mode&lt;/code&gt; has been selected and that some products have been selected. The result is a list of errors corresponding to the criteria that aren't met:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;validateProductGroup&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="kt"&gt;MultiMode&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;selectedProducts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Dict&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;-- [(NameField, "Please provide a name"), (ProductsField, "Please select at least one product")] &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The list can be saved in the model and then the view searches the list for relevant entries when displaying the various input fields in order to display the error state to the user if there is one.&lt;/p&gt;

&lt;p&gt;With this in mind, we can create our form to send a &lt;code&gt;SaveProductGroup&lt;/code&gt; message when the form is submitted and we can handle this message in our &lt;code&gt;update&lt;/code&gt; function with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;        &lt;span class="kt"&gt;SaveProductGroup&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;validateProductGroup&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;productGroupData&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;
                &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;productGroupData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;productGroupData&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Nothing&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
                        &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;postProductGroup&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;productGroupData&lt;/span&gt;
                          &lt;span class="p"&gt;]&lt;/span&gt;

                &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;productGroupData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;productGroupData&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we run the &lt;code&gt;validateProductGroup&lt;/code&gt; function and if we get an empty list then we know that there are no errors and we can post our data to the server using &lt;code&gt;postProductGroup&lt;/code&gt; that will create a command for us to carry out the necessary HTTP request.&lt;/p&gt;

&lt;p&gt;The problem we encounter is that the &lt;code&gt;postProductGroup&lt;/code&gt; needs to encode the &lt;code&gt;ProductGroup&lt;/code&gt; structure to JSON and when it does that it has to navigate the data that we've given it. We know that the &lt;code&gt;mode&lt;/code&gt; value is a &lt;code&gt;Just&lt;/code&gt; because we've validated it but the convert to JSON function cannot take any shortcuts because Elm doesn't let us (which is a good thing!) We can try to write the encoding function like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;encodeProductGroup&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ProductGroup&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Encode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Value&lt;/span&gt;
&lt;span class="n"&gt;encodeProductGroup&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;selectedProducts&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Encode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Encode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mode"&lt;/span&gt;
          &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;
                &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
                    &lt;span class="n"&gt;encodeMode&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;

                &lt;span class="kt"&gt;Nothing&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
                    &lt;span class="c1"&gt;-- Help! What do we put here?&lt;/span&gt;
          &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;products"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Encode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="n"&gt;encodeProduct&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;Dict&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="n"&gt;selectedProducts&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see from the comment, it is hard to figure out what to write there. Elm gives us some escape hatches like &lt;code&gt;Debug.crash&lt;/code&gt; but that feels wrong. We could not include the &lt;code&gt;mode&lt;/code&gt; key if we don't have a value but then we're knowingly allowing a code path that sends incorrect data to the server.&lt;/p&gt;

&lt;p&gt;So what do we do? Well, we need to recognise that this function shouldn't be making this decision. It shouldn't have to deal with the &lt;code&gt;Maybe&lt;/code&gt;, especially when we have already validated that it has a &lt;code&gt;Just&lt;/code&gt; value.&lt;/p&gt;

&lt;p&gt;So we create a new type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="kt"&gt;ProductGroupUploadData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Mode&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;selectedProducts&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt; &lt;span class="kt"&gt;Product&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which is the same data that we're interested in but with the &lt;code&gt;Maybe&lt;/code&gt; resolved to an actual value and the &lt;code&gt;Dict.values&lt;/code&gt; transformation already applied to &lt;code&gt;selectedProducts&lt;/code&gt;. If we change our &lt;code&gt;encodeProductGroup&lt;/code&gt; function to expect this type then the implementation becomes trivial:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;encodeProductGroup&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ProductGroupUploadData&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Encode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Value&lt;/span&gt;
&lt;span class="n"&gt;encodeProductGroup&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;selectedProducts&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Encode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Encode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mode"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encodeMode&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;products"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Encode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="n"&gt;encodeProduct&lt;/span&gt; &lt;span class="n"&gt;selectedProducts&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But how do we convert our &lt;code&gt;ProductGroup&lt;/code&gt; to &lt;code&gt;ProductGroupUploadData&lt;/code&gt;? This is where the &lt;a href="https://github.com/stoeffel/elm-verify"&gt;stoeffel/elm-verify&lt;/a&gt; library comes in. It allows us to both validate our data and transform it to another structure in the same operation. It does this by using the &lt;code&gt;Result&lt;/code&gt; type to allow it to report validation errors, if any are encountered, or the new data structure for us to use. And it does this with a &lt;code&gt;Json.Decode.Pipeline&lt;/code&gt;-like interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;validateProductGroup&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ProductGroup&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Result&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Field&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="kt"&gt;ProductGroupUploadData&lt;/span&gt;
&lt;span class="n"&gt;validateProductGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt;
        &lt;span class="n"&gt;validateProducts&lt;/span&gt; &lt;span class="n"&gt;productGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="kt"&gt;Dict&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isEmpty&lt;/span&gt; &lt;span class="n"&gt;productGroup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;selectedProducts&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
                &lt;span class="kt"&gt;Err&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;ProductsField&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Please select at least one product"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;
                &lt;span class="kt"&gt;Ok&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Dict&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="n"&gt;productGroup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;selectedProducts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="kt"&gt;V&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;validate&lt;/span&gt; &lt;span class="kt"&gt;ProductGroupUploadData&lt;/span&gt;
        &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;V&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verify&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Verify&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notBlank&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;NameField&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Please provide a name"&lt;/span&gt; &lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;V&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verify&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Maybe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Verify&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isJust&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;ConfigField&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Please select a mode"&lt;/span&gt; &lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;V&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;custom&lt;/span&gt; &lt;span class="n"&gt;validateProducts&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where &lt;code&gt;V&lt;/code&gt; is the result of &lt;code&gt;import Verify as V&lt;/code&gt;. You can see the "pipeline" approach that might be familiar from &lt;code&gt;Json.Decode.Pipeline&lt;/code&gt;. That means we're using &lt;code&gt;ProductGroupUploadData&lt;/code&gt; as a constructor and each step of the pipeline is providing an argument to complete the data. We use &lt;code&gt;String.Verify&lt;/code&gt; to check that the &lt;code&gt;name&lt;/code&gt; isn't blank and &lt;code&gt;Maybe.Verify&lt;/code&gt; to check that the &lt;code&gt;mode&lt;/code&gt; is specified. Then we use &lt;code&gt;Verify.custom&lt;/code&gt; to provide a slight more complex check for the &lt;code&gt;selectedProducts&lt;/code&gt;. &lt;code&gt;Verify.custom&lt;/code&gt; allows us to write a function that takes the incoming data and returns a &lt;a href="http://package.elm-lang.org/packages/elm-lang/core/latest/Result"&gt;&lt;code&gt;Result&lt;/code&gt;&lt;/a&gt; with either an &lt;code&gt;Err&lt;/code&gt; with an array of errors or an &lt;code&gt;Ok&lt;/code&gt; with the valid value. We use it to not only check that the dictionary is empty but also extract just the values from the dictionary. We don't have to run &lt;code&gt;Dict.values&lt;/code&gt; here, we could also do that in the &lt;code&gt;encodeProductGroup&lt;/code&gt; function when generating the JSON but I have a personal preference for the &lt;code&gt;UploadData&lt;/code&gt; to match the JSON closely if possible.&lt;/p&gt;

&lt;p&gt;With that in place, we can change our &lt;code&gt;SaveProductGroup&lt;/code&gt; case in our &lt;code&gt;update&lt;/code&gt; function to look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;        &lt;span class="kt"&gt;SaveProductGroup&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;validateProductGroup&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;productGroupData&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;
                &lt;span class="kt"&gt;Ok&lt;/span&gt; &lt;span class="n"&gt;uploadData&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;productGroupData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;productGroupData&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Nothing&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
                        &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;postProductGroup&lt;/span&gt; &lt;span class="n"&gt;uploadData&lt;/span&gt;
                          &lt;span class="p"&gt;]&lt;/span&gt;

                &lt;span class="kt"&gt;Err&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;productGroupData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;productGroupData&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which means that the &lt;code&gt;postProductGroup&lt;/code&gt; is given a nice &lt;code&gt;ProductGroupUploadData&lt;/code&gt; record and no longer has to worry about the &lt;code&gt;Maybe&lt;/code&gt; type.&lt;/p&gt;

&lt;p&gt;Prior to using the &lt;code&gt;elm-verify&lt;/code&gt; library, we used a separate function to convert between the types and we only called &lt;code&gt;postProductGroup&lt;/code&gt; if both the validation &amp;amp; the conversion functions were successful. The conversion function always felt a little strange though and switching to &lt;code&gt;elm-verify&lt;/code&gt; cleans that up nicely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Further note&lt;/strong&gt;: Whilst the &lt;code&gt;elm-verify&lt;/code&gt; interface is similar to &lt;code&gt;Json.Decode.Pipeline&lt;/code&gt; it isn't quite the same. It has a version of &lt;code&gt;andThen&lt;/code&gt; but it doesn't provide some ways to combine operations like &lt;code&gt;Json.Decode.oneOf&lt;/code&gt; or helper functions like &lt;code&gt;Json.Decode.map&lt;/code&gt;. This is partly to keep the interface simple and partly because it is always manipulating &lt;code&gt;Result&lt;/code&gt; values so with a bit of thought you can use helper functions like &lt;code&gt;Result.map&lt;/code&gt; quite easily. &lt;/p&gt;

&lt;p&gt;I only include this as originally sought to use &lt;code&gt;elm-verify&lt;/code&gt; exactly as I would &lt;code&gt;Json.Decode.Pipeline&lt;/code&gt; and ended up writing a bunch of unnecessary functions in order to allow me to do just that. I should have spent more time understanding the types in the interface and working with those.&lt;/p&gt;

</description>
      <category>elm</category>
      <category>validation</category>
    </item>
    <item>
      <title>How To: GitLab and Docker Registry</title>
      <dc:creator>cazgp</dc:creator>
      <pubDate>Fri, 05 Jan 2018 15:51:59 +0000</pubDate>
      <link>https://dev.to/zaptic/how-to-gitlab-and-docker-registry-2moh</link>
      <guid>https://dev.to/zaptic/how-to-gitlab-and-docker-registry-2moh</guid>
      <description>&lt;h1&gt;
  
  
  How To: GitLab and Docker Registry
&lt;/h1&gt;

&lt;p&gt;I (and one other engineer) spent rather too much time the other afternoon trying to work out how to set up a self-hosted Docker registry on a self-hosted GitLab site.&lt;/p&gt;

&lt;p&gt;What we discovered (that the documentation really doesn't explain very well) is that GitLab becomes responsible for running the Docker registry and ensuring that it's accessible on whichever port you configure. That is, all you really need to do is to install Docker and change a couple of things in the GitLab config and everything happens like magic.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Set-Up
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;We assume that you have a self-hosted GitLab EE site somewhere, accessible by gitlab.example.com.&lt;/li&gt;
&lt;li&gt;We assume that this is on an Ubuntu (16.04) machine.&lt;/li&gt;
&lt;li&gt;We also assume that you want to set up a self-hosted Docker registry and that you know what that means.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Install Docker on your GitLab server
&lt;/h3&gt;

&lt;p&gt;Follow the instructions &lt;a href="https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/"&gt;here&lt;/a&gt; to install Docker.&lt;/p&gt;

&lt;p&gt;I'll copy out the commands to run to save you from the pain, but do check that link in case you don't know what any of these commands are doing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo apt-get update

$ sudo apt-get install \
  apt-transport-https \
  ca-certificates \
  curl \
  software-properties-common

$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

$ sudo apt-key fingerprint 0EBFCD88

$ sudo add-apt-repository \
 "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
 $(lsb_release -cs) \
 stable"

$ sudo apt-get update

$ sudo apt-get install docker-ce
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify that docker installed properly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo docker run hello-world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Make changes to GitLab config
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.gitlab.com/ce/administration/container_registry.html#enable-the-container-registry"&gt;The container docs&lt;/a&gt; say "All you have to do is configure the domain name under which the Container Registry will listen to. Read #container-registry-domain-configuration and pick one of the two options that fits your case."&lt;/p&gt;

&lt;p&gt;Click on the link they provide and you reach &lt;a href="https://docs.gitlab.com/ce/administration/container_registry.html#container-registry-domain-configuration"&gt;here&lt;/a&gt; which says "There are two ways you can configure the Registry's external domain. Either use the existing GitLab domain where in that case the Registry will have to listen on a port and reuse GitLab's TLS certificate, or use a completely separate domain with a new TLS certificate for that domain."&lt;/p&gt;

&lt;p&gt;What we are trying to do is use the existing GitLab domain name because -- how cool is this? -- Docker registry login with GitLab credentials!&lt;/p&gt;

&lt;p&gt;So, click the link that takes us &lt;a href="https://docs.gitlab.com/ce/administration/container_registry.html#configure-container-registry-under-an-existing-gitlab-domain"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;... and it says "If the Registry is configured to use the existing GitLab domain, you can expose the Registry on a port so that you can reuse the existing GitLab TLS certificate."&lt;/p&gt;

&lt;p&gt;So, to summarise. The docs say "configure the domain name [for] the Container Registry ... If the Registry is configured [with] the existing [domain name]". But they completely fail to tell you how to configure the domain name! This is the part that confused us a lot.&lt;/p&gt;

&lt;h4&gt;
  
  
  The missing link
&lt;/h4&gt;

&lt;p&gt;We assume that you don't care what port you want to run Docker registry on, and so use 4567. If you do care, change that value.&lt;/p&gt;

&lt;p&gt;Edit &lt;code&gt;/etc/gitlab/gitlab.rb&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Find the line which contains &lt;code&gt;registry_external_url&lt;/code&gt; and change it to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;registry_external_url 'https://gitlab.example.com:4567'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enable the registry in nginx:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;registry_nginx['enable'] = true
registry_nginx['listen_port'] = 4567
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also copy in the TLS certificate lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;registry_nginx['ssl_certificate'] = "/path/to/certificate.pem"
registry_nginx['ssl_certificate_key'] = "/path/to/certificate.key"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save and reconfigure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gitlab-ctl reconfigure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitLab will automatically open the ports up and allow you to login to the registry with &lt;code&gt;docker login&lt;/code&gt; and your GitLab credentials / 2fa keys (if you use 2fa).&lt;/p&gt;

&lt;p&gt;That should be it! Happy GitLabing :)&lt;/p&gt;

</description>
      <category>docker</category>
      <category>gitlab</category>
    </item>
    <item>
      <title>Right clicks &amp; Elm</title>
      <dc:creator>Michael Jones</dc:creator>
      <pubDate>Fri, 08 Dec 2017 14:04:08 +0000</pubDate>
      <link>https://dev.to/zaptic/right-clicks--elm-2ll</link>
      <guid>https://dev.to/zaptic/right-clicks--elm-2ll</guid>
      <description>&lt;p&gt;At &lt;a href="https://www.zaptic.com"&gt;Zaptic&lt;/a&gt;, we allow our customers to create a flow chart describing the business processes that they would like to complete. We draw the flow chart in SVG using a pan &amp;amp; zoom interface to make it easy to look around. We track mouse down, mouse drag &amp;amp; mouse up events to manage this UI.&lt;/p&gt;

&lt;p&gt;Unfortunately, in development, the experience was a little annoying as every time we loaded the browser's inspector on an element the &lt;code&gt;mousedown&lt;/code&gt; of the right-click would be tracked by the UI but the &lt;code&gt;mouseup&lt;/code&gt; would be over the context menu and so would not register. The result? The UI gets left in "pan" mode and attempts to follow your mouse everywhere even though you don't have any mouse buttons pressed any more.&lt;/p&gt;

&lt;p&gt;To overcome this, we needed to look into tracking which mouse button was being used so that we could ignore the right-clicks. We are using the &lt;a href="http://package.elm-lang.org/packages/elm-lang/mouse/latest"&gt;elm-lang/mouse&lt;/a&gt; package which includes a &lt;code&gt;position&lt;/code&gt; decoder that can be used for &lt;code&gt;mousedown&lt;/code&gt; events. That decoder only provides the mouse location as &lt;code&gt;pageX&lt;/code&gt; and &lt;code&gt;pageY&lt;/code&gt;, it doesn't provide any information about which button was pressed so we need to go a little deeper.&lt;/p&gt;

&lt;p&gt;If we take a look at the &lt;a href="https://github.com/elm-lang/mouse/blob/1.0.1/src/Mouse.elm"&gt;source code&lt;/a&gt; for the module we can see that the position decoder is doing the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Decoder&lt;/span&gt; &lt;span class="kt"&gt;Position&lt;/span&gt;
&lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map2&lt;/span&gt; &lt;span class="kt"&gt;Position&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pageX"&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pageY"&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is looking for the &lt;code&gt;pageX&lt;/code&gt; and &lt;code&gt;pageY&lt;/code&gt; properties, as we suspected, and it expects them to be integers. If we look at the lovely &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Events/mousedown"&gt;MDN documentation&lt;/a&gt; for a mousedown event we can see that it has lots of other properties including a integer &lt;code&gt;button&lt;/code&gt; property which contains some indication of which button is being used. We can set up our own type &amp;amp; decoder as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="kt"&gt;MouseClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;pageX&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pageY&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;button&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="n"&gt;mouseClickDecoder&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Decode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Decoder&lt;/span&gt; &lt;span class="kt"&gt;PFM&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;MouseClick&lt;/span&gt;
&lt;span class="n"&gt;mouseClickDecoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Decode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map3&lt;/span&gt; &lt;span class="kt"&gt;PFM&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;MouseClick&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Decode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pageX"&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Decode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Decode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pageY"&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Decode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Decode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button"&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Decode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And adapt our event handler to use it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="kt"&gt;Msg&lt;/span&gt;
    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;DragStart&lt;/span&gt; &lt;span class="kt"&gt;MouseClick&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="n"&gt;onMouseDown&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Attribute&lt;/span&gt; &lt;span class="kt"&gt;Msg&lt;/span&gt;
&lt;span class="n"&gt;onMouseDown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mousedown"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Decode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="kt"&gt;DragStart&lt;/span&gt; &lt;span class="n"&gt;mouseClickDecoder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then in our &lt;code&gt;update&lt;/code&gt; function that is going to handle the &lt;code&gt;DragStart&lt;/code&gt; message we can check the value of &lt;code&gt;button&lt;/code&gt; and ignore right-clicks. There are some inconsistencies between browsers on how different buttons are represented as integers which you can read about on &lt;a href="https://www.quirksmode.org/js/events_properties.html#button"&gt;quirksmode&lt;/a&gt;. Fortunately they all align for the 'right-click' which is represented as &lt;code&gt;2&lt;/code&gt;. So we can ignore that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="kt"&gt;DragStart&lt;/span&gt; &lt;span class="n"&gt;click&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;-- Ignore right-clicks which are given value '2' by browsers&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;click&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;button&lt;/span&gt; &lt;span class="o"&gt;/=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt;
            &lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;click&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pageX&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;click&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pageY&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;in&lt;/span&gt;
        &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;drag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;none&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;none&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And there we have it! We're free of the right-clicks and can happily jump into the browser dev-tools whenever we like.&lt;/p&gt;

&lt;p&gt;If you have any thoughts or advice, please let me know! Always happy to learn.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update&lt;/em&gt;: Checkout Ilias' comment below. It really cleans up the message handling in the update:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;-        DragStart click -&amp;gt;
-            -- Ignore right-clicks which are given value '2' by browsers
-            if click.button /= 2 then
-                let
-                    pos =
-                        { x = click.pageX, y = click.pageY }
-                in
-                { model | drag = Just { start = pos, current = pos } } ! []
-            else
-                model ! []
&lt;/span&gt;&lt;span class="gi"&gt;+        DragStart pos -&amp;gt;
+            { model | drag = Just { start = pos, current = pos } } ! []
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>elm</category>
    </item>
  </channel>
</rss>
