reflex
Reflex is a class library for writing reactive Perl programs. It provides base classes for reactive objects, and specific subclasses for various tasks.
The intent of this small program is to show three buttons, with the third button's label initially being "0" and afterwards being the index of the last-clicked button. For now the number of buttons and the labels of the other buttons are constant.
When I compile this self-contained file with ghcjs and load Main.jsexe/index.html in the browser, I can see the two traceDyns firing in a loop, both always having the value 0. As far as I understand, nothing should happen until a button is clicked, because the _el_clicked feeds the rest of the system.
Also, note that I'm using mapDyn (fst . head . Map.toList)
in order to extract the index of the selected button - I'm not sure this is correct, but either way I don't know what causes the infinite looping.
{-# LANGUAGE RecursiveDo #-}
module Main where
import Reflex
import Reflex.Dom
import qualified Data.Map as Map
dynButton
:: MonadWidget t m
=> Dynamic t String
-> m (Event t ())
dynButton s = do
(e, _) <- el' "button" $ dynText s
return $ _el_clicked e
-- widget that takes dynamic list of strings
-- and displays a button for each, returning
-- an event of chosen button's index
listChoiceWidget
:: MonadWidget t m
=> Dynamic t [String]
-> m (Event t Int)
listChoiceWidget choices = el "div" $ do
asMap <- mapDyn (Map.fromList . zip [(0::Int)..]) choices
evs <- listWithKey asMap (\_ s -> dynButton s)
k <- mapDyn (fst . head . Map.toList) evs
return $ updated (traceDyn "k" k)
options :: MonadWidget t m => Dynamic t Int -> m (Dynamic t [String])
options foo = do
mapDyn (\x -> ["a", "b", show x]) foo
main :: IO ()
main = mainWidget $ el "div" $ do
rec n <- listChoiceWidget o
o <- options foo
foo <- holdDyn 0 n
display (traceDyn "foo" foo)
Source: (StackOverflow)
I want to perform a basic Ajax request, that's all.
I use reflex
for the frontend and Scotty
for the backend. The Firefox Web Console tells me the request was a success and I see the expected result there. But the website switches from Just "default"
to Nothing
instead of Just "success!"
.
Here is a complete minimal example:
import Reflex (holdDyn)
import Reflex.Dom (button, el, mainWidget, display)
import Reflex.Dom.Xhr (performRequestAsync, xhrRequest, decodeXhrResponse)
import Reflex.Class (tag, constant)
import Data.Default (def)
main :: IO ()
main = do
mainWidget $ el "div" $ do
buttonEvent <- button "click me"
let defaultReq = xhrRequest "GET" "mystring" def --served by Scotty
asyncEvent <- performRequestAsync (tag (constant defaultReq) buttonEvent)
buttonDyn <- holdDyn (Just "default") $ fmap decodeXhrResponse asyncEvent
display buttonDyn
and the Scotty
part:
{-# LANGUAGE OverloadedStrings #-}
import Web.Scotty
import Network.Wai.Middleware.Static
main = scotty 3000 $ do
middleware $ staticPolicy (noDots >-> addBase "/mnt/b/haskell/try-reflex/hello.jsexe")
get "/" $ do
file "/mnt/b/haskell/try-reflex/hello.jsexe/index.html"
get "/mystring" $ html "success!"
Since the debug tools tell me the request was a success, I suspect the error somewhere near decodeXhrResponse
but I am a bit lost how I should proceed debugging since it just gets compiled to (unreadable) Javascript.
I used the try-reflex Nix script from GitHub to set up everything and compiled with ghcjs hello.hs
in the Nix environment.
Edit: Adding the output of curl
:
$ curl -G http://localhost:3000/mystring
success!%
Source: (StackOverflow)
I am just starting with the reflex-dom library and I cannot quite figure out the proper and convenient way to work with dialogs.
Showing a dialog generally means adding a few elements to the end of <body>
and removing it when the user clicks on some button, backdrop or presses e.g. escape. However doing this from some nested widget means somehow bubbling up the event ('show the dialog') to the top, which could be quite clumsy. Is there any other way to do it nicely? I just had a look at markup.rocks and that seems to use some JS/jQuery hacks.
I can decide not to use modal dialogs (it may not be a bad option after all), but for some things I may really need it.
Source: (StackOverflow)