Just starting out with Fable / Elmish / F#, but getting stuck getting a basic concept done...
The goal of the code is to execute a simple HTTP GET request and, thereafter, to post the results of the GET request to the user on a web page.
The idea was to use Fable Promise
or async
to execute the GET request and return the result, thereafter the result can be displayed on a web page using Elmish and Fable.
I expected that the web page (localhost) will output a text string containing the response of of the GET request, instead I only got "[object Promise]" on the web page. The desired response of the GET request is however logged on the Browser console. If I issue a printfn command with the txt
in the body of the promise (before the return
) I can also see the result of the GET request in the browser console.
Thus: I have no idea how to access the results of the promise. Please help, what am I missing? The sample apps from [Fable][1] , there is a image "container" created and an image placed based on the results of the HTTP get, but I need to work with text (json string).
Here is my code:
module App
open Elmish
open Fable.React
open Elmish.React
open Fable.React.Props
open Fable.Import
open Fable.PowerPack
open Fetch
// CallAPI
let getMe = promise {
let! res = fetch "https://reqres.in/api/users/2" []
let! txt = res.text()
// Access your resource here
Browser.console.log txt
return txt
}
//State
type MyInputString =
{Response : string}
// Message
type Message =
|ShowResponse
|Error
let getFromAPI =
getMe |> sprintf "%A"
//Update
let update msg model =
match msg with
|ShowResponse -> {Response = getFromAPI }
|Error -> {Response = "Errrrrr"}
//Helper function
let text(content:string) : ReactElement = unbox content
//Helper function
let init() = {Response = ""}
//View
let view model dispatch =
div
[]
[
div [] [ input[ Type "text"] ]
button [ OnClick (fun _ -> dispatch ShowResponse ) ] [ text "Show Me"]
div [] []
div [] [text (model.Response)]
]
Program.mkSimple init update view
|> Program.withReactSynchronous "werk"
|> Program.withConsoleTrace
|> Program.run ```
[1]: https://fable.io
If you do it following the elmish pattern, you could do the following. This might give some errors but should be enough to get you going:
Use mkProgram because it gives you flexibility to specify Cmd callbacks
Program.mkProgram init update view
|> Program.withReact "elmish-app"
|> Program.withConsoleTrace
|> Program.run
Make sure you have a distinction between your model and message
type Model = {
UserMessage: string
ErrorMessage: string
}
Add a message type to receive the promise result and to handle an error:
type Message =
| Loading
| ShowResponse of Result<string,string>
| Error of exn
Your init should return model and Cmd now as the signature has changed (see update below):
let init() = { UserMessage= "" ; ErrorMessage= "" } , Cmd.ofMsg Loading
Change your update function, the signature has now changed as we are using mkProgram. Note that when you call Cmd.ofPromise you are passing the ShowResponse and Error messages as callbacks -ShowResponse on success and Error if anything bad happens in your promise code.
//update signature has changed from
msg -> model -> model
//to:
msg -> model -> (model*Cmd<msg>)
let update msg model =
match msg with
| Loading ->
{ model with UserMessage= "Loading" },
Cmd.ofPromise (getMe ) () ShowResponse Error
| ShowResponse resp ->
match resp with
| Ok str ->
{ model with UserMessage = str }, Cmd.none
| Error str ->
{ model with ErrorMessage = str }, Cmd.none
| Error exn -> { model with ErrorMessage = string exn }, Cmd.none
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With