# Form validation technique using \`Result\` (and findings)

**URL:** <https://discourse.elm-lang.org/t/form-validation-technique-using-result-and-findings/9976>\
**Category:** Request Feedback\
**Created:** [September 19, 2024, 9:27pm UTC](https://discourse.elm-lang.org/t/form-validation-technique-using-result-and-findings/9976 "2024-09-19T21:27:41Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![badlydrawnrob](https://avatars.discourse-cdn.com/v4/letter/b/ee59a6/32.png) [@badlydrawnrob](https://discourse.elm-lang.org/u/badlydrawnrob)\
**Post date:** [September 19, 2024, 9:27pm UTC](https://discourse.elm-lang.org/t/form-validation-technique-using-result-and-findings/9976/1 "2024-09-19T21:27:41Z")

</div>

> **TL;DR:** If you’re impatient **[view the working example here](https://ellie-app.com/shPQYbgSzbZa1)** and [skip to my questions](https://discourse.elm-lang.org/t/form-validation-technique-using-result-and-findings/9976) 🙂

**How to properly use `Result`?** On reflection, this might’ve been better as an article, so if it’s too long I’ll post things like this someplace else in future — let me know! I’d like some feedback on my form validation method.

## Here’s the exec summary of what I learned:

> **As an example of what I’m trying to achieve (eventually), [Bandcamp](https://antonyandthejohnsons.bandcamp.com/album/the-crying-light) would be a good example:** add/delete/move song, cover art, audio, multiple albums, so on.
> 
> Hopefully this helps beginners a bit. Learn from my pain.

1. **Think carefully about your data upfront:**
  - [2.00](https://github.com/badlydrawnrob/elm-playground/blob/2e6b8e7134196d2f0e47cb13cd49ce845bf1c72b/how-to-elm/src/HowToResult/FieldError.elm) (`Float`) is MUCH harder to error check [than `2` and `0`](https://github.com/badlydrawnrob/elm-playground/blob/2e6b8e7134196d2f0e47cb13cd49ce845bf1c72b/how-to-elm/src/HowToResult/FieldErrorRevisited.elm) `Int/Int`
  - When using for `minutes` and `seconds`

2. **Unpack `Maybe` in ONE place** wherever possible
  - I’m using [`Result`](https://github.com/badlydrawnrob/elm-playground/blob/2e6b8e7134196d2f0e47cb13cd49ce845bf1c72b/how-to-elm/src/CustomTypes/Songs.elm#L227) in this case

3. **Splitting out these functions** results in better code:
  - Build [`Song` function](https://github.com/badlydrawnrob/elm-playground/blob/2e6b8e7134196d2f0e47cb13cd49ce845bf1c72b/how-to-elm/src/CustomTypes/Songs.elm#L254) (in the `case` statement)
  - Create [`Album` function](https://github.com/badlydrawnrob/elm-playground/blob/2e6b8e7134196d2f0e47cb13cd49ce845bf1c72b/how-to-elm/src/CustomTypes/Songs.elm#L327) (passing it a `Song`)

4. **[Unbound type variable](https://frontendmasters.com/courses/intro-elm/unbound-type-variables/)** named [`Validate a` and `UserInput a`](https://github.com/badlydrawnrob/elm-playground/blob/2e6b8e7134196d2f0e47cb13cd49ce845bf1c72b/how-to-elm/src/CustomTypes/Songs.elm#L169-L178) (alias of `Result`) …
  - MUST provide `String` or `Int` wherever it’s used
  - `UserInput a` doesn’t represent the input type ..
  - It represents the `Ok data` type

5. **Trying to [chain `Result`](https://github.com/badlydrawnrob/elm-playground/blob/a0ab8a0f639ec6b2bb7587a59d8d74c444cc7cd4/how-to-elm/src/CustomTypes/Songs.elm#L267) with different data types is probably a bad idea**
6. **Nested records are probably [discouraged](https://discourse.elm-lang.org/t/updating-nested-records-again/1488)** in Elm (for whatever reasons)
7. **[Destructuring](https://gist.github.com/yang-wei/4f563fbf81ff843e8b1e) data types is really handy** in functions and makes them simpler!

## The problem

> A simple form with errors that creates a custom type.  
> Using a `Result` to validate forms and translate it into a `Song` type.

I understand there’s [many ways to validate](https://discourse.elm-lang.org/t/what-is-the-elm-way-to-validate-form-fields/9689/8) a form, so that’s not really my question … it’s more the stuff that **[I cover in this thread](https://discourse.elm-lang.org/t/where-can-i-find-a-mentor/9975)** that’s tripping me up. I think a lot of beginners to intermediates will suffer the same fate!

I think it’s sometimes good to STOP and reassess your decisions, let the background brain take over (sleep on it), or understand how you might write code in a better way first.

## My initial (failed) attempt

I tried to chain `Result`s in my [first attempt](https://github.com/badlydrawnrob/elm-playground/blob/a0ab8a0f639ec6b2bb7587a59d8d74c444cc7cd4/how-to-elm/src/CustomTypes/Songs.elm).

```plaintext
Input -> ClickedSave -> Result
                        |_ Chain Results
                           |_ Err? -> Return "Error" in view
                           |_ Ok? -> Return "Ok String"
                                            |_ check if error -> update Model

```

In `Update Model` we’d either create an `Album Song []` or if we already have an album, update the `Album Song (List Song)`. You could’ve also generated a `Song` with that `Ok` if no errors.

I got a bit stuck with that method as the [`Result` chaining](https://github.com/badlydrawnrob/elm-playground/blob/a0ab8a0f639ec6b2bb7587a59d8d74c444cc7cd4/how-to-elm/src/CustomTypes/Songs.elm#L267) felt a bit messy, and I’m not even sure if it’s supposed to be used in this fashion (the Elm Guide example uses a single data type for `Result` and `Result.andThen`).

## Hard questions that tutorials don’t always help with:

1. What model do I use?
2. How do I use _that_ function properly?
3. How does the data flow? How do functions interact?
4. Where do I go if I get stuck?

Tutorials are great, but learning enough to be able to build things alone and figure stuff out if you don’t know is hard to teach I guess.

## Second attempt — 🤩 [success!](https://ellie-app.com/shPQYbgSzbZa1)

Anyways, for my second attempt I decided to just give every input it’s own `Result`, change the model to `UserInput` records, and use those results to format the data (if needed) or return an error for that field:

```plaintext
Input -> { m | valid = Result String a } -> Render view for errors

```

Turns out this is a bit easier. I’m currently updating the `Result` for each field on user input. I’m not sure if this is the ideal way to do things. After [reading @rtfeldman reply here](https://discourse.elm-lang.org/t/message-types-carrying-new-state/2177/5) it seems clear that **your update functions are the only things that should be dealing with state.** `Msg` are just simple containers for data, right?

```plaintext
ClickedSave -> case runErrorsAndBuildSong in update
                 |_ Nothing -> return model (show errors in view)
                 |_ Just song -> update model -> show the album in view

```

When the user clicks save, we need to cycle through the `.valid` field in each user input, and my first thought was to reach for `List.map` … but it seems types in Elm are way more fussy than I thought:

```auto
{ valid = Ok 20 }
{ valid = Ok "Get Back" }

```

Throws an error. I was quite surprised. So you can’t even have different `Ok data` types when trying to use a `List.map`. Hmm.

## This leaves me with SO many questions

> **Feel free to just answer any (or no) question you care to!**  
> If you’re interested, see [this post](https://discourse.elm-lang.org/t/where-can-i-find-a-mentor/9975) for the general problems I’m having (and assume many reading this will have)

1. Are my functions in the right place?
2. Is validating on `ClickedSave` preferable to `EnteredInput`?
3. I thought it might be useful to have two `Msg` for button action:
  - `ClickedSave` (check errors, then handover to ..)
  - `SaveSong` (handle the update album function)
  - is this a silly idea?

4. How can I improve the code base so it’s [scalable](https://www.youtube.com/watch?v=DoA4Txr4GUs)?\[1\] (A bigger form)
  - Narrowing the types
  - Splitting out the `Msg` (isolate the form)
  - Better ways to check all errors for lots of fields?
    - Alternative for `List.map .validate [...]`?

5. Am I dealing with multiple form inputs correctly?
6. Should I avoid nested records completely? (A flatter style)
7. Anything else I could improve?

So yeah, I continually find that programming is hard, and often your program asks more questions than it answers!

* * *

1. I’ve watched, but don’t fully understand “Scaling Elm Apps”, and the Elm Spa example is too big for me to follow.

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/1X/50a05e53677a2c3b47776d7abd0f113eb50193a1.png) [@system](https://discourse.elm-lang.org/u/system)\
**Post date:** [September 29, 2024, 9:28pm UTC](https://discourse.elm-lang.org/t/form-validation-technique-using-result-and-findings/9976/2 "2024-09-29T21:28:25Z")

</div>

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.
