John Baker
John Baker

Reputation: 109

Elm Piping Multiple values to a function

I have a decoder that currently works as desired, but I made an update and now need to pass two values into the initFilter function, as opposed to just passing in the view.

The JSON has a new "filter" string field and I'd like to generate a specific type based on that value.

Here is the decoder for the new field:

filterTypeDecoder : Json.Decode.Decoder FilterType
filterTypeDecoder =
    Json.Decode.string
        |> Json.Decode.andThen
            (\s ->
                case s of
                    "filter1" ->
                        Json.Decode.succeed (DefaultFilter)

                    "edited" ->
                        Json.Decode.succeed (EditedFilter)

                    _ ->
                        Json.Decode.fail ("unknown filter: " ++ s)
            )

Here is where I'm decoding the testModel

 TestDecoder.decoder today
        |> Json.Decode.andThen
            (\( tester, errors ) ->
                Json.Decode.succeed testModel
                    |> Pipeline.hardcoded tester
                    |> Pipeline.required "view"
                        (viewDecoder
                            |> Json.Decode.map 
                               (initFilter tester DefaultFilter)
                        )
                    |> Pipeline.hardcoded errors

So this, as it's written currently works. The problem is, I'm providing DefaultFilter directly instead of decoding the "filter" field to figure out what it actually should be. The issue is, I'm not certain how to go about passing multiple values in via pipeline.

My first thought was to decode it separately use let to set the value of filter at the start, but then I would be decoding the same JSON twice which doesn't seem correct.

Is there a way to decode and pipe in filter to the same place that I'm piping the view? If I'm not being 100% clear, let me know...still struggle to understand elm decoding.

Upvotes: 1

Views: 378

Answers (1)

Chad Gilbert
Chad Gilbert

Reputation: 36375

You can use Json.Decode.andThen to use different decoders based on a value within the JSON itself.

First off, let's move the existing decoding of "view" into its own function to avoid extraneous indentation:

viewFilterDecoder tester =
    viewDecoder
        |> Json.Decode.map 
           (initFilter tester DefaultFilter)

Now the decoding of "view" looks like this:

    |> Pipeline.required "view" (viewFilterDecoder tester)

Now you can update the definition of viewFilterDecoder to first decode the "filter" value and then (andThen) use that filter value in the subsequent call to initFilter:

viewFilterDecoder tester =
    Json.Decode.field "filter" filterTypeDecoder
        |> Json.Decode.andThen
                (\filter -> viewDecoder
                    |> Json.Decode.map 
                       (initFilter tester filter)
                )

Upvotes: 2

Related Questions