elmish-browser


Custom navigation

This port of the Elm library is about treating the address bar as an input to your program. It converts changes in the address bar into messages and provides functions for manipulation of the browser history.

1: 
2: 
3: 
4: 
5: 
namespace Elmish.Navigation

open Browser
open Browser.Types
open Elmish

Parser

A function to turn the string in the address bar into data that is easier for your app to handle.

1: 
2: 
3: 
4: 
5: 
type Parser<'a> = Location -> 'a

type Navigable<'msg> =
    | Change of Location
    | UserMsg of 'msg

Direct history manipulation

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
[<RequireQualifiedAccess>]
module Navigation =
    let [<Literal>] internal NavigatedEvent = "NavigatedEvent"

    /// Modify current location
    let modifyUrl (newUrl:string):Cmd<_> =
        [fun _ -> history.replaceState((), "", newUrl)]

    /// Push new location into history and navigate there
    let newUrl (newUrl:string):Cmd<_> =
        [fun _ -> history.pushState((), "", newUrl)
                  let ev = CustomEvent.Create(NavigatedEvent)
                  window.dispatchEvent ev
                  |> ignore ]

    /// Jump to some point in history (positve=forward, nagative=backward)
    let jump (n:int):Cmd<_> =
        [fun _ -> history.go n]

Program extensions

Treat user's program as a child component, by wrapping it and handling navigation events.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
36: 
37: 
38: 
39: 
40: 
41: 
42: 
43: 
44: 
45: 
46: 
47: 
48: 
49: 
50: 
51: 
52: 
53: 
54: 
55: 
56: 
57: 
58: 
59: 
60: 
61: 
62: 
63: 
64: 
65: 
66: 
67: 
68: 
69: 
70: 
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<RequireQualifiedAccess>]
module Program =

    module Internal =
        let mutable private onChangeRef : obj -> obj =
            fun _ ->
                failwith "`onChangeRef` has not been initialized.\nPlease make sure you used Elmish.Navigation.Program.Internal.subscribe"

        let subscribe (dispatch:Dispatch<_ Navigable>) =
            let mutable lastLocation = None
            let onChange _ =
                match lastLocation with
                | Some href when href = window.location.href -> ()
                | _ ->
                    lastLocation <- Some window.location.href
                    Change window.location |> dispatch
                |> box

            onChangeRef <- onChange

            window.addEventListener("popstate", unbox onChangeRef)
            window.addEventListener("hashchange", unbox onChangeRef)
            window.addEventListener(Navigation.NavigatedEvent, unbox onChangeRef)

        let unsubscribe () =
            window.removeEventListener("popstate", unbox onChangeRef)
            window.removeEventListener("hashchange", unbox onChangeRef)
            window.removeEventListener(Navigation.NavigatedEvent, unbox onChangeRef)

        let toNavigableWith (parser : Parser<'a>)
                            (urlUpdate : 'a->'model->('model * Cmd<'msg>))
                            (program : Program<'a,'model,'msg,'view>)
                            (onLocationChange : Dispatch<Navigable<'msg>> -> unit) =

            let map (model, cmd) =
                model, cmd |> Cmd.map UserMsg

            let update userUpdate msg model =
                match msg with
                | Change location ->
                    urlUpdate (parser location) model
                | UserMsg userMsg ->
                    userUpdate userMsg model
                |> map

            let subs userSubscribe model =
                Cmd.batch
                  [ [ onLocationChange ]
                    userSubscribe model |> Cmd.map UserMsg ]

            let init userInit () =
                userInit (parser window.location) |> map

            let setState userSetState model dispatch =
                userSetState model (UserMsg >> dispatch)

            let view userView model dispatch =
                userView model (UserMsg >> dispatch)
            
            program
            |> Program.map init update view setState subs

    /// Add the navigation to a program made with `mkProgram` or `mkSimple`.
    /// urlUpdate: similar to `update` function, but receives parsed url instead of message as an input.
    let toNavigable (parser : Parser<'a>)
                    (urlUpdate : 'a->'model->('model * Cmd<'msg>))
                    (program : Program<'a,'model,'msg,'view>) =

        Internal.toNavigableWith parser urlUpdate program Internal.subscribe
namespace Elmish
type Parser<'a> = obj -> 'a
type Navigable<'msg> =
  | Change of obj
  | UserMsg of 'msg
union case Navigable.Change: obj -> Navigable<'msg>
union case Navigable.UserMsg: 'msg -> Navigable<'msg>
Multiple items
type RequireQualifiedAccessAttribute =
  inherit Attribute
  new : unit -> RequireQualifiedAccessAttribute

--------------------
new : unit -> RequireQualifiedAccessAttribute
Multiple items
type LiteralAttribute =
  inherit Attribute
  new : unit -> LiteralAttribute

--------------------
new : unit -> LiteralAttribute
val internal NavigatedEvent : string
val modifyUrl : newUrl:string -> ('a -> 'b) list


 Modify current location
val newUrl : string
Multiple items
val string : value:'T -> string

--------------------
type string = System.String
val newUrl : newUrl:string -> ('a -> unit) list


 Push new location into history and navigate there
val ev : obj
val ignore : value:'T -> unit
val jump : n:int -> ('a -> 'b) list


 Jump to some point in history (positve=forward, nagative=backward)
val n : int
Multiple items
val int : value:'T -> int (requires member op_Explicit)

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

--------------------
type int<'Measure> = int
Multiple items
type CompilationRepresentationAttribute =
  inherit Attribute
  new : flags:CompilationRepresentationFlags -> CompilationRepresentationAttribute
  member Flags : CompilationRepresentationFlags

--------------------
new : flags:CompilationRepresentationFlags -> CompilationRepresentationAttribute
type CompilationRepresentationFlags =
  | None = 0
  | Static = 1
  | Instance = 2
  | ModuleSuffix = 4
  | UseNullAsTrueValue = 8
  | Event = 16
CompilationRepresentationFlags.ModuleSuffix: CompilationRepresentationFlags = 4
module Program

from Elmish.Navigation
val mutable private onChangeRef : (obj -> obj)
type obj = System.Object
val failwith : message:string -> 'T
val subscribe : dispatch:(Navigable<'a> -> unit) -> 'b
val dispatch : (Navigable<'a> -> unit)
val mutable lastLocation : obj option
union case Option.None: Option<'T>
val onChange : ('c -> obj)
union case Option.Some: Value: 'T -> Option<'T>
val href : obj
val box : value:'T -> obj
val unbox : value:obj -> 'T
module Navigation

from Elmish.Navigation
val unsubscribe : unit -> 'a
val toNavigableWith : parser:Parser<'a> -> urlUpdate:('a -> 'model -> 'model * 'a0) -> program:'b -> onLocationChange:('c -> unit) -> 'd
val parser : Parser<'a>
val urlUpdate : ('a -> 'model -> 'model * 'a0)
val program : 'b
val onLocationChange : ('c -> unit)
type unit = Unit
val map : ('e * 'f -> 'e * 'g)
val model : 'e
val cmd : 'f
val update : (('e -> 'model -> 'model * 'a) -> Navigable<'e> -> 'model -> 'model * 'f)
val userUpdate : ('e -> 'model -> 'model * 'a)
val msg : Navigable<'e>
val model : 'model
val location : obj
val userMsg : 'e
val subs : ('e -> 'f -> 'g)
val userSubscribe : 'e
val model : 'f
val init : (('a -> 'e * 'f) -> unit -> 'e * 'g)
val userInit : ('a -> 'e * 'f)
val setState : (('e -> ('f -> 'g) -> 'h) -> 'e -> (Navigable<'f> -> 'g) -> 'h)
val userSetState : ('e -> ('f -> 'g) -> 'h)
val dispatch : (Navigable<'f> -> 'g)
val view : (('e -> ('f -> 'g) -> 'h) -> 'e -> (Navigable<'f> -> 'g) -> 'h)
val userView : ('e -> ('f -> 'g) -> 'h)
val toNavigable : parser:Parser<'a> -> urlUpdate:('a -> 'model -> 'model * 'a0) -> program:'b -> 'c


 Add the navigation to a program made with `mkProgram` or `mkSimple`.
 urlUpdate: similar to `update` function, but receives parsed url instead of message as an input.
module Internal

from Elmish.Navigation.ProgramModule