elmish-browser


Working with query parameters

In addition to working with routes, the library also defines parser combinators for working with ? queries:

  • <?> combinator for query parameters,
  • stringParam combinator to extract a string,
  • intParam combinator to attempt to parse an int.

Some examples:

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
open Elmish.UrlParser

type PersonQuery = 
    { name: string
      age: int }

type Route = 
    | Blog of int 
    | Search of string option 
    | Query of PersonQuery option
    with static member FromParams name age = 
        match name,age with
        | Some name, Some age -> Query (Some { name = name; age = age})
        | _ -> Query None


let route : Parser<Route->Route,_>=
    oneOf
        [ map Search (s "blog" <?> stringParam "search")
          map Blog (s "blog" </> i32)
          map (Route.FromParams) (top <?> stringParam "name" <?> intParam "age") ]

Note that unlike route combinators, which fail to match the entire route if some combinator can not be parsed, query param parsers return Option. It's up to you if you decide to accept a query parameter as None.

The parser above will resolve:

blog/              ==>  Some (Search None)
blog?search=cats   ==>  Some (Search (Some "cats"))
blog/42            ==>  Some (Blog 42)
?name=tom&age=42   ==>  Some (Query {name="tom"; age=42})
?name=tom          ==>  Some (Query None)

Full vs hashbang URL queries

Normally, query parameters apply to the full URL and are available via location.search property of the browser, that is where pathParser will look. This doesn't work very well with hashbang URLs and hashParser looks for ? in location.hash instead.

Keep this difference in mind when formatting your routes.

type PersonQuery =
  {name: string;
   age: int;}
PersonQuery.name: string
Multiple items
val string : value:'T -> string

--------------------
type string = System.String
PersonQuery.age: int
Multiple items
val int : value:'T -> int (requires member op_Explicit)

--------------------
type int = int32

--------------------
type int<'Measure> = int
union case Route.Blog: int -> Route
union case Route.Search: string option -> Route
type 'T option = Option<'T>
union case Route.Query: PersonQuery option -> Route
val name : string option
val age : int option
union case Option.Some: Value: 'T -> Option<'T>
val name : string
val age : int
union case Option.None: Option<'T>
val route : obj
type Route =
  | Blog of int
  | Search of string option
  | Query of PersonQuery option
    static member FromParams : name:string option -> age:int option -> Route
static member Route.FromParams : name:string option -> age:int option -> Route