Sorry, but I'm a newbie with Fable and F#. I started a boilerplate from SAFE project, and I created a SPA with two pages. However, all the logic is inside a single file. My question is. How can I implement a router putting each view in one file?
I would something like that:
...
Client
|_Client.fs
|_Pages
|_ Home.fs
|_ About.fs
Server
|_Server.fs
...
Below is my Client.fs file
src/Client/Client.fs
(**
- title: Navigation demo
- tagline: The router sample ported from Elm
*)
module App
open Fable.Core
open Fable.Import
open Elmish
open Fable.Import.Browser
open Fable.PowerPack
open Elmish.Browser.Navigation
open Elmish.Browser.UrlParser
JsInterop.importAll "whatwg-fetch"
// Types
type Page = Home | Blog of int | Search of string
type Model =
{ page : Page
query : string
cache : Map<string,string list> }
let toHash =
function
| Blog id -> "#blog/" + (string id)
| _ -> "#home"
/// The URL is turned into a Page option.
let pageParser : Parser<Page->_,_> =
oneOf
[ map Home (s "home")
map Blog (s "blog" </> i32) ]
type Msg =
| Query of string
| Enter
| FetchFailure of string*exn
| FetchSuccess of string*(string list)
type Place = { ``place name``: string; state: string; }
(* If the URL is valid, we just update our model or issue a command.
If it is not a valid URL, we modify the URL to whatever makes sense.
*)
let urlUpdate (result:Option<Page>) model =
match result with
| Some page ->
{ model with page = page; query = "" }, []
| None ->
Browser.console.error("Error parsing url")
( model, Navigation.modifyUrl (toHash model.page) )
let init result =
urlUpdate result { page = Home; query = ""; cache = Map.empty }
(* A relatively normal update function. The only notable thing here is that we
are commanding a new URL to be added to the browser history. This changes the
address bar and lets us use the browser’s back button to go back to
previous pages.
*)
let update msg model =
match msg with
| Query query ->
{ model with query = query }, []
| FetchFailure (query,_) ->
{ model with cache = Map.add query [] model.cache }, []
| FetchSuccess (query,locations) ->
{ model with cache = Map.add query locations model.cache }, []
// VIEW
open Fable.Helpers.React
open Fable.Helpers.React.Props
let viewLink page description =
a [ Style [ Padding "0 20px" ]
Href (toHash page) ]
[ str description]
let internal centerStyle direction =
Style [ Display "flex"
FlexDirection direction
AlignItems "center"
unbox("justifyContent", "center")
Padding "20px 0" ]
let words size message =
span [ Style [ unbox("fontSize", size |> sprintf "%dpx") ] ] [ str message ]
let internal onEnter msg dispatch =
function
| (ev:React.KeyboardEvent) when ev.keyCode = 13. ->
ev.preventDefault()
dispatch msg
| _ -> ()
|> OnKeyDown
let viewPage model dispatch =
match model.page with
| Home ->
[ words 60 "Welcome!"
str "Play with the links and search bar above. (Press ENTER to trigger the zip code search.)" ]
| Blog id ->
[ words 20 "This is blog post number"
words 100 (string id) ]
open Fable.Core.JsInterop
let view model dispatch =
div []
[ div [ centerStyle "row" ]
[ viewLink Home "Home"
viewLink (Blog 42) "Cat Facts"
viewLink (Blog 13) "Alligator Jokes"
viewLink (Blog 26) "Workout Plan" ]
hr []
div [ centerStyle "column" ] (viewPage model dispatch)
]
open Elmish.React
open Elmish.Debug
// App
Program.mkProgram init update view
|> Program.toNavigable (parseHash pageParser) urlUpdate
|> Program.withReact "elmish-app"
|> Program.withDebugger
|> Program.run