<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="https://illuminatedcomputing.com/">
  <id>https://illuminatedcomputing.com/</id>
  <title>Illuminated Computing</title>
  <updated>2019-01-09T00:00:00Z</updated>
  <link rel="alternate" href="https://illuminatedcomputing.com/" type="text/html"/>
  <link rel="self" href="https://illuminatedcomputing.com/tags/react/atom.xml" type="application/atom+xml"/>
  <author>
    <name>Paul A. Jungwirth</name>
    <uri>https://illuminatedcommputing.com/</uri>
  </author>
  <entry>
    <id>tag:illuminatedcomputing.com,2019-01-09:/posts/2019/01/drawing-redux-form-fieldarrays-with-pug/</id>
    <title type="html">Drawing Redux Form FieldArrays with Pug</title>
    <published>2019-01-09T00:00:00Z</published>
    <updated>2019-01-09T00:00:00Z</updated>
    <link rel="alternate" href="https://illuminatedcomputing.com/posts/2019/01/drawing-redux-form-fieldarrays-with-pug/" type="text/html"/>
    <content type="html">
&lt;p&gt;Having been spoiled by the Rails &lt;a href="https://steveklabnik.com/writing/rails-has-two-default-stacks/"&gt;Prime Stack&lt;/a&gt; for nearly a decade, in my React projects I prefer using &lt;a href="https://pugjs.org/api/getting-started.html"&gt;Pug&lt;/a&gt; (née Jade) instead of JSX for its Haml-like syntax. A lot of people praise Pug and Haml for saving them typing, and while that’s nice, the real appeal to me is how easy they are to read. You spend a lot more time reading code than writing it, and Pug/Haml make the document structure immediately obvious. Making closing-tag errors obsolete is pretty nice, too.&lt;/p&gt;

&lt;p&gt;With the &lt;a href="https://github.com/pugjs/babel-plugin-transform-react-pug"&gt;&lt;code&gt;babel-plugin-transform-react-pug&lt;/code&gt; package&lt;/a&gt;, you can replace your JSX with something like this:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;&lt;span class="reserved"&gt;class&lt;/span&gt; MyApp &lt;span class="reserved"&gt;extends&lt;/span&gt; React.Component {
  render() {
    &lt;span class="keyword"&gt;return&lt;/span&gt; pug&lt;span class="error"&gt;`&lt;/span&gt;
      Provider(store=configureStore(&lt;span class="local-variable"&gt;this&lt;/span&gt;.props))
        table
          tbody
            tr
              td table
              td layout
              td anyone?
    &lt;span class="error"&gt;`&lt;/span&gt;;
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But Pug is definitely not as widely adopted within React as Haml is within Rails, and it shows. I ran into a tricky issue using Pug to render &lt;code&gt;FieldArray&lt;/code&gt;s with &lt;a href="https://github.com/erikras/redux-form"&gt;Redux Form&lt;/a&gt; and &lt;a href="https://github.com/react-bootstrap/react-bootstrap"&gt;React Bootstrap&lt;/a&gt;. To combine those two packages I’m basically following &lt;a href="https://medium.com/@jtbennett/using-redux-form-to-handle-user-input-1392826f2c6d"&gt;John Bennett’s advice&lt;/a&gt;, except with Pug.&lt;/p&gt;

&lt;p&gt;Here is how typical scalar fields work:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const renderInput = ({input, label, type, meta}) =&amp;gt; pug&lt;span class="error"&gt;`&lt;/span&gt;
  FormGroup(controlId=input.name validationState=&lt;span class="predefined"&gt;$&lt;/span&gt;{validState(meta)})
    Col(componentClass=&lt;span class="predefined"&gt;$&lt;/span&gt;{ControlLabel} sm=&lt;span class="integer"&gt;2&lt;/span&gt;)
      = label || humanizeString(input.name)
    Col(sm=&lt;span class="integer"&gt;5&lt;/span&gt;)
      FormControl(...input type=type)
&lt;span class="error"&gt;`&lt;/span&gt;

&lt;span class="reserved"&gt;class&lt;/span&gt; EditClientPage &lt;span class="reserved"&gt;extends&lt;/span&gt; React.Component {
  render() {
    &lt;span class="keyword"&gt;return&lt;/span&gt; pug&lt;span class="error"&gt;`&lt;/span&gt;
      Form(horizontal onSubmit=&lt;span class="predefined"&gt;$&lt;/span&gt;{&lt;span class="local-variable"&gt;this&lt;/span&gt;.props.handleSubmit})
        fieldset
          Field(name=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;name&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt; component=renderInput type=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;text&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;)
          Field(name=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;paymentDue&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt; component=renderInput type=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;number&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;)
    &lt;span class="error"&gt;`&lt;/span&gt;
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That’s from my time-tracking app where I wrote about using &lt;a href="/posts/2019/01/validating-fieldarrays-in-redux-form/"&gt;&lt;code&gt;FieldArray&lt;/code&gt; with &lt;code&gt;redux-form-validators&lt;/code&gt;&lt;/a&gt;. The &lt;code&gt;Field&lt;/code&gt; component is from Redux Form, and everything else is from React-Bootstrap (&lt;code&gt;Form&lt;/code&gt;, &lt;code&gt;FormGroup&lt;/code&gt;, &lt;code&gt;Col&lt;/code&gt;, &lt;code&gt;ControlLabel&lt;/code&gt;, and &lt;code&gt;FormControl&lt;/code&gt;). You can see that &lt;code&gt;Field&lt;/code&gt; expects a custom component to draw its details, giving you total flexibility how you structure your form’s DOM. Most of the Boostrap components go inside the custom component used by &lt;code&gt;Field&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So far that’s pretty nice, but if you have a &lt;code&gt;FieldArray&lt;/code&gt; you need more nesting. A &lt;code&gt;FieldArray&lt;/code&gt; is also part of Redux Form, and is used to draw a list of child records with their sub-fields. In my case I want the page to have one or more “work categories”, each with a name and hourly rate, e.g. “Design” and “Development”.&lt;/p&gt;

&lt;p&gt;Like &lt;code&gt;Field&lt;/code&gt;, a &lt;code&gt;FieldArray&lt;/code&gt; delegates rendering to a custom component. Then that component will render the individual &lt;code&gt;Field&lt;/code&gt;s (each with their own custom component in turn). If you adapted the Redux Form docs’ example, you might try something like this:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const renderSimpleInput = ({input, placeholder, type, meta}) =&amp;gt; pug&lt;span class="error"&gt;`&lt;/span&gt;
  span(&lt;span class="reserved"&gt;class&lt;/span&gt;=&lt;span class="predefined"&gt;$&lt;/span&gt;{validClass(meta)})
    FormControl(...input placeholder=placeholder type=type)
&lt;span class="error"&gt;`&lt;/span&gt;

const renderWorkCategories = ({fields, meta}) =&amp;gt; &lt;span class="error"&gt;`&lt;/span&gt;pug
  .noop
    = fields.map((wc, index) =&amp;gt; &lt;span class="error"&gt;`&lt;/span&gt;pug
      FormGroup(key=&lt;span class="predefined"&gt;$&lt;/span&gt;{index})
        Col(sm=&lt;span class="integer"&gt;2&lt;/span&gt;)
          Field(name=&lt;span class="predefined"&gt;$&lt;/span&gt;{&lt;span class="error"&gt;`&lt;/span&gt;&lt;span class="predefined"&gt;$&lt;/span&gt;{wc}.name&lt;span class="error"&gt;`&lt;/span&gt;} component=renderSimpleInput type=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;text&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt; placeholder=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;name&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;)
        Col(sm=&lt;span class="integer"&gt;5&lt;/span&gt;)
          Field(name=&lt;span class="predefined"&gt;$&lt;/span&gt;{&lt;span class="error"&gt;`&lt;/span&gt;&lt;span class="predefined"&gt;$&lt;/span&gt;{wc}.rate&lt;span class="error"&gt;`&lt;/span&gt;} component=renderSimpleInput type=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;number&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt; placeholder=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;rate&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;)
        Col(sm=&lt;span class="integer"&gt;2&lt;/span&gt;)
          a.btn.btn-&lt;span class="keyword"&gt;default&lt;/span&gt;(onClick=&lt;span class="predefined"&gt;$&lt;/span&gt;{()=&amp;gt;fields.remove(index)}) remove
    &lt;span class="error"&gt;`&lt;/span&gt;)
    FormGroup
      Col(smOffset=&lt;span class="integer"&gt;2&lt;/span&gt; sm=&lt;span class="integer"&gt;5&lt;/span&gt;)
        a.btn.btn-&lt;span class="keyword"&gt;default&lt;/span&gt;(onClick=&lt;span class="predefined"&gt;$&lt;/span&gt;{()=&amp;gt;fields.push({})}) add rate
&lt;span class="error"&gt;`&lt;/span&gt;

&lt;span class="reserved"&gt;class&lt;/span&gt; EditClientPage &lt;span class="reserved"&gt;extends&lt;/span&gt; React.Component {
  render() {
    &lt;span class="keyword"&gt;return&lt;/span&gt; pug&lt;span class="error"&gt;`&lt;/span&gt;
      ...
      FieldArray(name=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;workCategories&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt; component=&lt;span class="predefined"&gt;$&lt;/span&gt;{renderWorkCategories})
      ...
    &lt;span class="error"&gt;`&lt;/span&gt;
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The problem is that you can’t nest pug strings like that. I’m not sure if the problem is with the Babel transformer or the pug parser itself, but you get an error. Of course that’s not idiomatic Pug anyway, but surprisingly, you can’t use Pug’s &lt;code&gt;each&lt;/code&gt; command either:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const renderWorkCategories = ({fields, meta}) =&amp;gt; &lt;span class="error"&gt;`&lt;/span&gt;pug
  .noop
    each wc, index &lt;span class="keyword"&gt;in&lt;/span&gt; fields
      FormGroup(key=&lt;span class="predefined"&gt;$&lt;/span&gt;{index})
        Col(sm=&lt;span class="integer"&gt;2&lt;/span&gt;)
          Field(name=&lt;span class="predefined"&gt;$&lt;/span&gt;{&lt;span class="error"&gt;`&lt;/span&gt;&lt;span class="predefined"&gt;$&lt;/span&gt;{wc}.name&lt;span class="error"&gt;`&lt;/span&gt;} component=renderSimpleInput type=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;text&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt; placeholder=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;name&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;)
        Col(sm=&lt;span class="integer"&gt;5&lt;/span&gt;)
          Field(name=&lt;span class="predefined"&gt;$&lt;/span&gt;{&lt;span class="error"&gt;`&lt;/span&gt;&lt;span class="predefined"&gt;$&lt;/span&gt;{wc}.rate&lt;span class="error"&gt;`&lt;/span&gt;} component=renderSimpleInput type=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;number&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt; placeholder=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;rate&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;)
        Col(sm=&lt;span class="integer"&gt;2&lt;/span&gt;)
          a.btn.btn-&lt;span class="keyword"&gt;default&lt;/span&gt;(onClick=&lt;span class="predefined"&gt;$&lt;/span&gt;{()=&amp;gt;fields.remove(index)}) remove
    ...
&lt;span class="error"&gt;`&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This gives you the error &lt;code&gt;Expected "fields" to be an array because it was passed to each&lt;/code&gt;. Apparently Redux Form is not using a normal array here, but its own special object.&lt;/p&gt;

&lt;p&gt;The trick is to call &lt;code&gt;getAll&lt;/code&gt;, like this:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;each wc, index &lt;span class="keyword"&gt;in&lt;/span&gt; fields.getAll()
  FormGroup(key=&lt;span class="predefined"&gt;$&lt;/span&gt;{index})
    Col(sm=&lt;span class="integer"&gt;2&lt;/span&gt;)
      Field(name=&lt;span class="predefined"&gt;$&lt;/span&gt;{&lt;span class="error"&gt;`&lt;/span&gt;workCategories[&lt;span class="predefined"&gt;$&lt;/span&gt;{index}].name&lt;span class="error"&gt;`&lt;/span&gt;} component=renderSimpleInput type=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;text&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt; placeholder=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;name&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;)
    Col(sm=&lt;span class="integer"&gt;5&lt;/span&gt;)
      Field(name=&lt;span class="predefined"&gt;$&lt;/span&gt;{&lt;span class="error"&gt;`&lt;/span&gt;workCategories[&lt;span class="predefined"&gt;$&lt;/span&gt;{index}].rate&lt;span class="error"&gt;`&lt;/span&gt;} component=renderSimpleInput type=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;number&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt; placeholder=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;rate&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;)
    Col(sm=&lt;span class="integer"&gt;2&lt;/span&gt;)
      a.btn.btn-&lt;span class="keyword"&gt;default&lt;/span&gt;(onClick=&lt;span class="predefined"&gt;$&lt;/span&gt;{()=&amp;gt;fields.remove(index)}) remove
&lt;span class="error"&gt;`&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that we also had to stop using &lt;code&gt;${wc}&lt;/code&gt; and are building the field name “by hand”. Personally I think we can stop here and be done, but if that feels like breaking encapsulation to you, or if you want something more generic that doesn’t need to “know” its &lt;code&gt;FieldArray&lt;/code&gt; name, there is another way to do it. Even if it’s a bit too much for a real project, it’s interesting enough that it’s maybe worth seeing.&lt;/p&gt;

&lt;p&gt;To start, we need to call &lt;code&gt;fields.map&lt;/code&gt; with another custom component. This almost works:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const renderWorkCategory = (wc, index) =&amp;gt; &lt;span class="error"&gt;`&lt;/span&gt;pug
  FormGroup(key=&lt;span class="predefined"&gt;$&lt;/span&gt;{index})
    Col(sm=&lt;span class="integer"&gt;2&lt;/span&gt;)
      Field(name=&lt;span class="predefined"&gt;$&lt;/span&gt;{&lt;span class="error"&gt;`&lt;/span&gt;&lt;span class="predefined"&gt;$&lt;/span&gt;{wc}.name&lt;span class="error"&gt;`&lt;/span&gt;} component=renderSimpleInput type=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;text&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt; placeholder=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;name&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;)
    Col(sm=&lt;span class="integer"&gt;5&lt;/span&gt;)
      Field(name=&lt;span class="predefined"&gt;$&lt;/span&gt;{&lt;span class="error"&gt;`&lt;/span&gt;&lt;span class="predefined"&gt;$&lt;/span&gt;{wc}.rate&lt;span class="error"&gt;`&lt;/span&gt;} component=renderSimpleInput type=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;number&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt; placeholder=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;rate&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;)
    Col(sm=&lt;span class="integer"&gt;2&lt;/span&gt;)
      a.btn.btn-&lt;span class="keyword"&gt;default&lt;/span&gt;(onClick=&lt;span class="predefined"&gt;$&lt;/span&gt;{()=&amp;gt;fields.remove(index)}) remove
&lt;span class="error"&gt;`&lt;/span&gt;

const renderWorkCategories = ({fields, meta}) =&amp;gt; &lt;span class="error"&gt;`&lt;/span&gt;pug
  .noop
    = fields.map(renderWorkCategory)
    ...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The only problem is the remove button: &lt;code&gt;fields&lt;/code&gt; is no longer in scope!&lt;/p&gt;

&lt;p&gt;The solution is to use currying. The component we hand to &lt;code&gt;fields.map&lt;/code&gt; will be a partially-applied function, generated by passing in &lt;code&gt;fields&lt;/code&gt; early. ES6 syntax makes it really easy. The full code looks like this:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const renderWorkCategory = (fields) =&amp;gt; (wc, index) =&amp;gt; &lt;span class="error"&gt;`&lt;/span&gt;pug
  FormGroup(key=&lt;span class="predefined"&gt;$&lt;/span&gt;{index})
    Col(sm=&lt;span class="integer"&gt;2&lt;/span&gt;)
      Field(name=&lt;span class="predefined"&gt;$&lt;/span&gt;{&lt;span class="error"&gt;`&lt;/span&gt;&lt;span class="predefined"&gt;$&lt;/span&gt;{wc}.name&lt;span class="error"&gt;`&lt;/span&gt;} component=renderSimpleInput type=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;text&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt; placeholder=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;name&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;)
    Col(sm=&lt;span class="integer"&gt;5&lt;/span&gt;)
      Field(name=&lt;span class="predefined"&gt;$&lt;/span&gt;{&lt;span class="error"&gt;`&lt;/span&gt;&lt;span class="predefined"&gt;$&lt;/span&gt;{wc}.rate&lt;span class="error"&gt;`&lt;/span&gt;} component=renderSimpleInput type=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;number&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt; placeholder=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;rate&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;)
    Col(sm=&lt;span class="integer"&gt;2&lt;/span&gt;)
      a.btn.btn-&lt;span class="keyword"&gt;default&lt;/span&gt;(onClick=&lt;span class="predefined"&gt;$&lt;/span&gt;{()=&amp;gt;fields.remove(index)}) remove
&lt;span class="error"&gt;`&lt;/span&gt;

const renderWorkCategories = ({fields, meta}) =&amp;gt; &lt;span class="error"&gt;`&lt;/span&gt;pug
  .noop
    = fields.map(renderWorkCategory(fields))
    ...
&lt;span class="error"&gt;`&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You may recall we also used currying to &lt;a href="/posts/2019/01/validating-fieldarrays-in-redux-form/"&gt;combine &lt;code&gt;redux-form-validators&lt;/code&gt; with &lt;code&gt;FieldArray&lt;/code&gt;&lt;/a&gt;. It can really come in handy!&lt;/p&gt;

&lt;p&gt;As I’ve said before, programming one thing is usually easy; it gets hard &lt;a href="https://illuminatedcomputing.com/posts/2017/05/doing-many-things/"&gt;when we try to do many things at once&lt;/a&gt;. Here I show how to use Pug with a &lt;code&gt;FieldArray&lt;/code&gt; from Redux Form, on a page styled with React Bootstrap. I hope you found it useful if like me you are trying to have your cake and eat it too. :-)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; It turns out I was making things too complicated: &lt;code&gt;fields.map&lt;/code&gt; takes an optional third parameter, &lt;code&gt;fields&lt;/code&gt;. That means there is no need to curry &lt;code&gt;renderWorkCategory&lt;/code&gt; and pass in &lt;code&gt;fields&lt;/code&gt; early. Instead of this:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const renderWorkCategory = (fields) =&amp;gt; (wc, index) =&amp;gt; ...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;you can just say this:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const renderWorkCategory = (wc, index, fields) =&amp;gt; ...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I guess it pays to read the documentation! :-)&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:illuminatedcomputing.com,2019-01-08:/posts/2019/01/validating-fieldarrays-in-redux-form/</id>
    <title type="html">Validating FieldArrays in Redux Form</title>
    <published>2019-01-08T00:00:00Z</published>
    <updated>2019-01-08T00:00:00Z</updated>
    <link rel="alternate" href="https://illuminatedcomputing.com/posts/2019/01/validating-fieldarrays-in-redux-form/" type="text/html"/>
    <content type="html">
&lt;p&gt;I have a &lt;a href="https://github.com/erikras/redux-form"&gt;Redux Form&lt;/a&gt; project where I’m using &lt;a href="https://github.com/gtournie/redux-form-validators"&gt;&lt;code&gt;redux-form-validators&lt;/code&gt;&lt;/a&gt; to get easy Rails-style validations. Its docs explain how to define validators for normal scalar fields, but I thought I’d add how to do the same for a &lt;code&gt;FieldArray&lt;/code&gt;, which is a list of zero of more sub-fields.&lt;/p&gt;

&lt;p&gt;In my case I’m working on a time-tracking and invoicing application, where admins can edit a client. The form has regular fields for the client’s name, the invoicing frequency, etc., and then it also has “work categories”. Each client has one or more work categories, and a work category is just a name and an hourly rate. For instance you might charge one rate for design and another for development, or you might track retainer hours at $0/hour and extra hours at your normal rate.&lt;/p&gt;

&lt;p&gt;Redux Form makes it really easy to include child records right inside the main form using &lt;code&gt;FieldArray&lt;/code&gt;. Their docs give a nice &lt;a href="https://redux-form.com/7.4.2/examples/fieldarrays/"&gt;example of how to validate those nested fields&lt;/a&gt;, but it’s pretty DIY and verbose.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;redux-form-validators&lt;/code&gt; on the other hand, it’s easy. First you define a validation object with the rules for each field, like so:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const validations = {
  &lt;span class="key"&gt;name&lt;/span&gt;: [required()],
  &lt;span class="key"&gt;paymentDue&lt;/span&gt;: [required(), numericality({&lt;span class="reserved"&gt;int&lt;/span&gt;: &lt;span class="predefined-constant"&gt;true&lt;/span&gt;, &lt;span class="key"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;: &lt;span class="integer"&gt;0&lt;/span&gt;})],
  &lt;span class="comment"&gt;// ...&lt;/span&gt;
};&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then you write a little validation function to pass to Redux Form:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const &lt;span class="function"&gt;validate&lt;/span&gt; = &lt;span class="keyword"&gt;function&lt;/span&gt;(values) =&amp;gt; {
  const errors = {}
  &lt;span class="keyword"&gt;for&lt;/span&gt; (let field &lt;span class="keyword"&gt;in&lt;/span&gt; validations) {
    let value = values[field]
    errors[field] = validations[field].map(validateField =&amp;gt; {
      &lt;span class="keyword"&gt;return&lt;/span&gt; validateField(value, values)
    }).find(x =&amp;gt; x) &lt;span class="comment"&gt;// Take the first non-null error message.&lt;/span&gt;
  }
  &lt;span class="keyword"&gt;return&lt;/span&gt; errors
};

&lt;span class="reserved"&gt;export&lt;/span&gt; &lt;span class="keyword"&gt;default&lt;/span&gt; connect(mapStateToProps, mapDispatchToProps)(
  reduxForm({
    &lt;span class="key"&gt;form&lt;/span&gt;: &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;editClient&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;,
    validate
  })(EditClientPage)
);&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That is just straight from the docs. For each field it iterates over its validators and reports the first error it finds. It’s simple, but it doesn’t know how to handle nesting like with &lt;code&gt;FieldArray&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But notice you can really do whatever you like. It’s a bit striking for someone used to Rails how exposed and customizable everything is here. So how can we rewrite &lt;code&gt;validate&lt;/code&gt; to be smarter?&lt;/p&gt;

&lt;p&gt;Ideally we’d like to support validations &lt;em&gt;both&lt;/em&gt; on individual sub-fields, like the &lt;code&gt;name&lt;/code&gt; of a single work category, and &lt;em&gt;also&lt;/em&gt; on the &lt;code&gt;workCategories&lt;/code&gt; as a whole, for example checking that you have at least one. This is exactly what the Redux Form example does above: it checks that your club has at least one member, and that each member has a first and last name.&lt;/p&gt;

&lt;p&gt;Because this is a &lt;code&gt;FieldArray&lt;/code&gt;, Redux Form expects a different structure for its entry in the errors object returned by &lt;code&gt;validate&lt;/code&gt;. Normally you’d have a string value, like this:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;{
  &lt;span class="key"&gt;paymentDue&lt;/span&gt;: &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;must be numeric&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But for a &lt;code&gt;FieldArray&lt;/code&gt; you want to pass an array with one error object for each corresponding &lt;code&gt;FieldArray&lt;/code&gt; element, like this:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;{
  &lt;span class="key"&gt;workCategories&lt;/span&gt;: [
    {},   &lt;span class="comment"&gt;// no errors&lt;/span&gt;
    {&lt;span class="key"&gt;name&lt;/span&gt;: &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;is required&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;},
    {&lt;span class="key"&gt;name&lt;/span&gt;: &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;is too short&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="key"&gt;rate&lt;/span&gt;: &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;must be numeric&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;},
  ]
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Those sub-errors will get passed in the &lt;code&gt;meta&lt;/code&gt; object given to the component used to render each &lt;code&gt;Field&lt;/code&gt;. Again, you can see that happening in the Redux Form example.&lt;/p&gt;

&lt;p&gt;In addition, the array may have its own &lt;code&gt;_error&lt;/code&gt; attribute for top-level errors. That gets passed as &lt;code&gt;meta.error&lt;/code&gt; to the &lt;code&gt;FieldArray&lt;/code&gt; component itself. So &lt;code&gt;_error&lt;/code&gt; is not just a convention; it’s a “magic” attribute built into Redux Form. We want to set it too.&lt;/p&gt;

&lt;p&gt;I want a way to define all these validations in one big object: top-level fields, the &lt;code&gt;FieldArray&lt;/code&gt; itself, and the fields of individual &lt;code&gt;FieldArray&lt;/code&gt; records. Here is the structure I set up:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const validations = {
  &lt;span class="key"&gt;name&lt;/span&gt;:       [required()],
  &lt;span class="key"&gt;paymentDue&lt;/span&gt;: [required(), numericality({&lt;span class="reserved"&gt;int&lt;/span&gt;: &lt;span class="predefined-constant"&gt;true&lt;/span&gt;, &lt;span class="key"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;: &lt;span class="integer"&gt;0&lt;/span&gt;})],
  ...
  workCategories: {
    &lt;span class="key"&gt;_error&lt;/span&gt;: [
      required({&lt;span class="key"&gt;msg&lt;/span&gt;: &lt;span class="string"&gt;&lt;span class="delimiter"&gt;"&lt;/span&gt;&lt;span class="content"&gt;Please enter at least one work category.&lt;/span&gt;&lt;span class="delimiter"&gt;"&lt;/span&gt;&lt;/span&gt;}),
      length({&lt;span class="key"&gt;min&lt;/span&gt;: &lt;span class="integer"&gt;1&lt;/span&gt;, &lt;span class="key"&gt;msg&lt;/span&gt;: &lt;span class="string"&gt;&lt;span class="delimiter"&gt;"&lt;/span&gt;&lt;span class="content"&gt;Please enter at least one work category.&lt;/span&gt;&lt;span class="delimiter"&gt;"&lt;/span&gt;&lt;/span&gt;})
    ],
    &lt;span class="key"&gt;name&lt;/span&gt;:   [required()],
    &lt;span class="key"&gt;rate&lt;/span&gt;:   [required(), numericality({&lt;span class="key"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;: &lt;span class="integer"&gt;0&lt;/span&gt;})],
  },
};&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then instead of the recommended &lt;code&gt;validate&lt;/code&gt; function I used this:&lt;/p&gt;

&lt;div class="CodeRay"&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;code class="language-javascript"&gt;const buildErrors = (validations) =&amp;gt; (values) =&amp;gt; {
  const errors = {};
  &lt;span class="keyword"&gt;for&lt;/span&gt; (let field &lt;span class="keyword"&gt;in&lt;/span&gt; validations) {
    &lt;span class="keyword"&gt;if&lt;/span&gt; (field === &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;_error&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;) &lt;span class="keyword"&gt;continue&lt;/span&gt;;
    let value = values[field];
    const fieldValidations = validations[field];
    &lt;span class="keyword"&gt;if&lt;/span&gt; (fieldValidations.constructor === Array) {
      errors[field] = fieldValidations
          .map(validateField =&amp;gt; validateField(value, values))
          .find(x =&amp;gt; x);
    } &lt;span class="keyword"&gt;else&lt;/span&gt; {
      errors[field] = value ? value.map(o =&amp;gt; buildErrors(fieldValidations)(o)) : [];
      &lt;span class="keyword"&gt;if&lt;/span&gt; (fieldValidations._error) {
        errors[field]._error = fieldValidations._error
            .map(validateField =&amp;gt; validateField(value, values))
            .find(x =&amp;gt; x);
    }
  }
  &lt;span class="keyword"&gt;return&lt;/span&gt; errors;
}

&lt;span class="reserved"&gt;export&lt;/span&gt; &lt;span class="keyword"&gt;default&lt;/span&gt; connect(mapStateToProps, mapDispatchToProps)(
  reduxForm({
    &lt;span class="key"&gt;form&lt;/span&gt;: &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;editClient&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;,
    &lt;span class="key"&gt;validate&lt;/span&gt;: buildErrors(validations),
  })(EditClientPage)
);&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There are a few things to note here: I’m using a recursive function, where each call handles one “level” of the &lt;code&gt;validations&lt;/code&gt; object. It iterates over the field names, and if the field has an array, it handles it as before. Otherwise it expects a nested object structured just like the outermost object, which each sub-field has its own array of validators. There may also be a list of validators under &lt;code&gt;_errors&lt;/code&gt;, and those are handled specially. I’m using currying so that I can build a top-level validation function for &lt;code&gt;reduxForm&lt;/code&gt; as well as nested functions for each &lt;code&gt;FieldArray&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This function also supports reporting errors &lt;em&gt;both&lt;/em&gt; on sub-fields and the whole &lt;code&gt;FieldArray&lt;/code&gt; at the same time. That wouldn’t happen if the only &lt;code&gt;FieldArray&lt;/code&gt; check was to have at least one element, like here, but you can imagine scenarios where you want to validate the &lt;code&gt;FieldArray&lt;/code&gt; as a whole even when it isn’t empty.&lt;/p&gt;

&lt;p&gt;I’m happy that this approach lets me combine the ease of &lt;code&gt;redux-form-validators&lt;/code&gt; with &lt;code&gt;FieldArray&lt;/code&gt; to get the best of both worlds. I also like that &lt;code&gt;buildErrors&lt;/code&gt; is general enough that I can move it to a utility collection, and not write it separately for each form in my app.&lt;/p&gt;

&lt;p&gt;Also: you might enjoy &lt;a href="/posts/2019/01/drawing-redux-form-fieldarrays-with-pug/"&gt;my follow-up article showing how to render the form &lt;code&gt;Field&lt;/code&gt;s and &lt;code&gt;FieldArray&lt;/code&gt;s with Pug and Bootstrap&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
</feed>

