How to get query parameters in Elm?

Elm 0.19


For elm 0.19 the below concept is the same. Both of these packages still exist but have been moved and relabeled as the official elm/url and elm/browser libraries.

Elm 0.18


This example uses evancz/url-parser and elm-lang/navigation. There are a few kinks that aren't straightforward in the documentation, but I've explained them briefly below. The example should speak for itself.

module Main exposing (..)

import Html as H exposing (..)
import Navigation exposing (Location)
import UrlParser as UP exposing ((</>), (<?>), top, parsePath, oneOf, s, stringParam, Parser)
import Maybe.Extra as MaybeExtra exposing (unwrap)


type Route
    = UrlRoute (Maybe String) (Maybe String)
    | NotFoundRoute


type Msg
    = UrlParser Navigation.Location


type alias Model =
    { location : Route
    , w : String
    , h : String
    }


type alias SearchParams =
    { w : Maybe String, h : Maybe String }


main =
    Navigation.program UrlParser
        { init = init
        , view = view
        , update = update
        , subscriptions = (\_ -> Sub.none)
        }


init : Location -> ( Model, Cmd Msg )
init location =
    let
        currentPath =
            parseLocation location
    in
        ( initialModel currentPath
        , Cmd.none
        )


parseLocation : Location -> Route
parseLocation location =
    case (parsePath matchers location) of
        Just route ->
            route

        Nothing ->
            NotFoundRoute


matchers : Parser (Route -> a) a
matchers =
    UP.map UrlRoute (UP.s "index" <?> UP.stringParam "w" <?> UP.stringParam "h")


initialModel : Route -> Model
initialModel route =
    { location = route
    , w = MaybeExtra.unwrap "" (\x -> Maybe.withDefault "" x.w) (parseParams route)
    , h = MaybeExtra.unwrap "" (\x -> Maybe.withDefault "" x.h) (parseParams route)
    }


parseParams : Route -> Maybe SearchParams
parseParams route =
    case route of
        UrlRoute w h ->
            Just { w = w, h = h }

        NotFoundRoute ->
            Nothing


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        UrlParser location ->
            ( model
            , Cmd.none
            )


view : Model -> Html msg
view model =
    div []
        [ h1 [] [ text "URL Info" ]
        , div [] [ text ("W is: " ++ model.w) ]
        , div [] [ text ("H is: " ++ model.h) ]
        ]

The "trick" is to create another type alias to place your query params inside of. In the above example I've created the type SearchParams. After creating this type we just use an initialModel that takes in the currentPath.

From there, our model can extract the query params with Maybe.withDefault (it needs to be a Maybe type because the params may not be there). Once we have our data in the model we just print it out in the view.

Hope this helps!


There is no built-in core library way to access the URL. You can use ports and the community library jessitron/elm-param-parsing.

If you also want to set the URL, you can again use ports, or you can use the History API, for which there are bindings in TheSeamau5/elm-history.


Unfortunately jessitron/elm-param-parsing doesn't work with Elm 0.18.

Use elm-lang/navigation package:

http://package.elm-lang.org/packages/elm-lang/navigation/latest/Navigation

https://github.com/elm-lang/navigation/tree/2.1.0

especially this function:

program
    : (Location -> msg)
    -> { init : Location -> (model, Cmd msg), update : msg -> model -> (model, Cmd msg), view : model -> Html msg, subscriptions : model -> Sub msg }
    -> Program Never model msg

In the second parameter you can see "init : Location -> (model, Cmd msg)". This should handle reading of initial URL. To complement that, first parameter is a function which gets called every time URL changes.

(I am aware it's an old question, but this link popped out when I was looking for the solution to the same problem and accepted answer didn't help)

Tags:

Elm