Reputation: 9218
This is idential to this question, except elm has changed since then so that answer is no longer valid (in particular there is no longer a Decode.customDecoder
object).
How do you do this same thing in elm-core > 5.0.0?
Upvotes: 4
Views: 1521
Reputation: 696
Here's a solution that avoids having to choose a sketchy default value:
import Json.Decode as Decode exposing (Decoder)
decodeIntString : Decoder (Maybe Int)
decodeIntString =
Decode.map String.toInt Decode.string
decodeMaybeFail : Maybe a -> Decoder a
decodeMaybeFail val =
case val of
Just a ->
Decode.succeed a
Nothing ->
Decode.fail "'Nothing' value can't be decoded"
You then use it with
Decode.andThen decodeMaybeFail decodeIntString
(this is of type Decoder Int
, so you use it like you would use Decode.int
)
Not obvious at first, but it illustrates how to break this problem down into simple small steps.
In my opinion a function decodeMaybeFail : Maybe a -> Decoder a
should be in the standard Json.Decode
module.
Upvotes: 0
Reputation: 2112
For Elm 0.19 using the documentation for targetValue, the code becomes:
import Html.Events
import Json.Decode
onIntInput : (Int -> msg) -> Attribute msg
onIntInput tagger =
Html.Events.stopPropagationOn "input" <|
Json.Decode.map alwaysStop (Json.Decode.map tagger targetIntValue)
targetIntValue : Decoder Int
targetIntValue =
Json.Decode.at ["target", "value"] Json.Decode.string |> Json.Decode.andThen (\value ->
case String.toInt value of
Just number -> Json.Decode.succeed number
Nothing -> Json.Decode.fail "not a number")
alwaysStop : a -> (a, Bool)
alwaysStop x =
(x, True)
and you can then use onIntInput where you used onInput.
Upvotes: 0
Reputation: 15266
Use parseInt
decoder (source):
decodeString parseInt """ "123" """
Look at the tutorial about custom decoders, like for date. Reuse fromResult
approach.
Read about function composition (<<), which is used in parseInt
function.
Upvotes: 2
Reputation: 4641
You can create your own custom decoder by using succeed
and fail
from Json.Decode
. I changed the argument order below to make it chainable.
Edit: separated decoder concerns from result concerns.
import Json.Decode as Json
import Result
-- // This is a Result helper function that could be used elsewhere.
-- // Currently, there is no Result.either in Elm core.
eitherR : (x -> b) -> (a -> b) -> Result x a -> b
eitherR fErr fOk result =
case result of
Err x ->
fErr x
Ok a ->
fOk a
customDecoder : (a -> Result String b) -> Json.Decoder a -> Json.Decoder b
customDecoder fResult decoder =
decoder |> Json.andThen (fResult >> eitherR Json.fail Json.succeed)
Plugging this in to the linked question...
let number =
Json.oneOf [ Json.int, Json.string |> customDecoder String.toInt ]
Here's another example use. This is a version of onChange
which converts the value to an integer. Mainly useful for select
when you know the option value is an Int.
import Html
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import String
onChangeInt : (Int -> msg) -> Attribute msg
onChangeInt fMsg =
on "change" (targetValue |> customDecoder String.toInt |> Json.map fMsg)
Note that targetValue
is defined in the Html.Events module:
targetValue : Decoder String
Upvotes: 3
Reputation: 21007
Given that in the comment to the other answer, you state the need to embrace possible failure, you could use a Maybe.
stringIntDecoder : Decoder (Maybe Int)
stringIntDecoder =
Json.Decode.map (String.toInt >> Result.toMaybe) Json.Decode.string
Or
stringIntDecoder : Decoder (Result String Int)
stringIntDecoder =
Json.Decode.map (String.toInt) Json.Decode.string
Upvotes: 1
Reputation: 1047
One way to do it (as of Elm 0.18 and core 5.0) would be like this:
stringIntDecoder : Decoder Int
stringIntDecoder =
Json.Decode.map (\str -> String.toInt (str) |> Result.withDefault 0) Json.Decode.string
The String.toInt
function from the standard library takes a string and attempts to convert it to an integer, returning a Result. Result.withDefault
does what its name implies -- you give it some default value and a result, and if the Result is Ok x
you get x
but if it's Err _
you get the default value you supplied, here 0. You could instead write a function to handle a Result yourself if you like and pass that function in instead.
Upvotes: 6