Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get query parameters in Elm?

Tags:

elm

In my Elm program, I'd like to initialize my model based on the query string.

For example, if the query string is ?w=3&h=5 I'd like to have:

initialModel =
  { width = 3
  , height = 5
  }

Is that possible to achieve this in Elm, or the only way to do this is to get the query parameters in Javascript and pass them via a port?

like image 389
Misha Moroshko Avatar asked Nov 06 '15 07:11

Misha Moroshko


2 Answers

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!

like image 118
Joseph Cho Avatar answered Oct 13 '22 06:10

Joseph Cho


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.

like image 24
Apanatshka Avatar answered Oct 13 '22 08:10

Apanatshka