Giter Site home page Giter Site logo

reflex-frp / reflex-dom Goto Github PK

View Code? Open in Web Editor NEW
349.0 44.0 138.0 2.63 MB

Web applications without callbacks or side-effects. Reflex-DOM brings the power of functional reactive programming (FRP) to the web. Build HTML and other Document Object Model (DOM) data with a pure functional interface.

Home Page: https://reflex-frp.org

License: BSD 3-Clause "New" or "Revised" License

Haskell 96.81% Nix 0.85% C 1.00% Java 1.35%
reflex-frp haskell functional-reactive-programming reactive frp

reflex-dom's Introduction

reflex-dom's People

Contributors

3noch avatar alexfmpe avatar ali-abrar avatar arguggi avatar cgibbard avatar dalaing avatar dbbnrl avatar dfordivam avatar elvishjerricco avatar ericson2314 avatar eskimor avatar hamishmack avatar hsloan avatar imalsogreg avatar jbetz avatar kmicklas avatar lpsmith avatar luigy avatar mango314 avatar manyoo avatar marisakirisame avatar matthewbauer avatar meditans avatar mightybyte avatar nomeata avatar qrilka avatar ryantrinkle avatar sztupi avatar tomsmalley avatar treeowl avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

reflex-dom's Issues

Unify _input/_change names

The TextInput and TextArea types have _input events, but with Checkbox and Dropdown they're called _change. This terminology difference confused me, so I think it should probably be unified. I personally like _change better but don't have a huge attachment to that name. It seems like _input is ok for everything except _textInput_input where the two inputs made me fail to notice it all on the first pass.

dropdown value never change

{-# LANGUAGE OverloadedStrings #-}
import Reflex
import Reflex.Dom
import Data.Monoid
import Control.Monad.IO.Class

data Color = Red|Blue|Yellow deriving (Show, Enum, Eq, Ord)
main :: IO ()
main = mainWidget $ do
  drop <- dropdown Red (constDyn $ Red =: "red" <> Blue =: "blue" <> Yellow =: "yellow") def
  submit <- button "submit"
  let s = tagPromptlyDyn (value drop) submit
  performEvent_ $ (liftIO . print) <$> s

you will always see "Red" when the submit clicked whatever the select is.

listWithKey (/ simpleList) sometimes leave 'orphaned' nodes in DOM

This repo demonstrates the problem:

https://github.com/benmos/reflex-bug/blob/master/bug/src/Bug.hs

The sample app in question displays a (hard-coded) list of three RSS Feed names. Clicking on the feed names causes the feeds to be loaded via XHR and their contents displayed in a dynamic list below.

Two methods are used to display the dynamic list - "widgetHold" (which always seems to work fine) and "simpleList" which sometimes leaves "orphaned" DOM nodes:

simplelistorphans

Thoughts on improvements

I started developing an application with reflex-dom about a week ago, so maybe some of my thoughts might be wrong. My experience is so far quite good, but here are some thoughts...

  • I installed ghcjs 7.10.2 (not the try-reflex) and I had to use https://github.com/k0001/reflex-dom/tree/develop-ghcjs-0.2.0 . Any plans on integrating it into your repo?
  • I am using servant with structures from persistent, which compiles (at least for the datatypes) directly into ghcjs. It works wonderfully (I absolutely recommend it), however my server structures are in Data.Text. Ghcjs seems to work correctly with Data.Text (probably bettern than with String). Are there any thoughts about converting the whole reflex-dom to Text? It seems to me there actually is no reason to use String at all, especially with the OverloadedStrings extension. The thing is that just changing types in the reflex-dom files from String to Data.Text.Text probably does the trick.
  • I have a little problem with large page loading lots of elements where many of them are hidden. I'm not sure how it works internally, but it seems to me that the elements are first put to page and only in the next step the Dynamic variables are applied (e.g. for the class=hidden attribute). Is there a simple way to evade the problem?
  • I still have a non-composable feeling. Like: I suddenly need some div to be shown or hidden on some slightly more complex condition and I just have to wire the code with mapDyns, 'combineDyn's, <=< (I finally found use for this operator) - while I just wanted to say hide if a ==0 && b && !c.

E.g. I had to change the button to buttonClass, but had to change the signature to accomodate the simple fact, that I needed to put a glyphicon into the label text.

buttonClass :: MonadWidget t m => String -> m () -> m (Event t ())

I am developing with the CSS bootstrap framework that relies quite a lot on class attribute. What might cleanup the code may be making a Monoid (e.g. newtype ElClass) for the class parameter.

Anyway, so for it's not a bad experience, it just works :)

develop doesn't build with out-of-scope errors

At least on my machine, the current version of develop doesn't build with the following error:

src/Reflex/Dom/Widget/Basic.hs:164:43-50: error:
    Variable not in scope:
      tagCheap :: Behavior t (m a) -> Event t () -> Event t (m a)

src/Reflex/Dom/Widget/Basic.hs:428:57-65: error:
    Variable not in scope:
      fmapCheap
        :: (Workflow t0 m0 a -> Workflow t0 m0 b)
           -> Event t (Workflow t m a) -> Event t (Workflow t m b)

I'm running this from reflex-platform using ../work-on ghc ./.. The error comes up when I try to do cabal build or cabal haddock.

Cannot cast object to HTMLElement

I was trying to port our app to reflex-0.5 and reflex-dom-0.4 and it went OK with one exception - FFI function we use is failing with

Cannot cast object to HTMLElement
CallStack (from HasCallStack):
  error, called at src/GHCJS/DOM/Types.hs:909:22 in ghcjs-dom-0.2.4.0-E4ZRixqgxUV2viahdK96Up:GHCJS.DOM.Types

The function definition is

 foreign import javascript unsafe
   "(function(){$1.querySelector(\"thead\").style.transform = \"translate(0,\"+$1.scrollTop+\"px)\";})()"
  js_translateTHead :: Element -> IO ()

and was called as

liftIO $ js_translateTHead (_el_element fixer)

for reflex-dom-0.3 version and it was working fine

For reflex-dom-0.4 I've replaced Element with HTMLElement and _el_element with _element_raw but it fails with that error above.
And I couldn't find a way to do that without FFI (see ghcjs/ghcjs-dom#51).
What do I miss here or what magic is needed to pass that element into JS?

Why simple lenses?

Hi there!

Especially for Websocket - why are you generating simple lenses, which don't allow changing the type? For example this is not possible with simple lenses:

config & webSocketConfig_send . mapped . mapped %~ BL.toStrict . Aeson.encode

it took me a while that this was the reason, why my lens code did not work. The workaround is simple enough - I simply generated my own lenses.

xhr with Dynamic

The xhr functions all work on Events. For example,

performRequestAsync :: MonadWidget t m => Event t XhrRequest -> m (Event t XhrResponse)

It would be nice to have a version of this that worked on Dynamic. The type signature would be:

performRequestAsyncDyn :: MonadWidget t m => Dynamic t XhrRequest -> m (Dynamic t XhrResponse)

CEF Support.

Hi, this is not really an issue. I'm asking more out of curiosity than necessity, as GHCJS is working fine.

I was looking through this project which seems to have successfully created bindings for the Chromium Embedded Framework:

Haskell CEF3 bindings

What would take to tie Reflex-Dom to this?

Upgrade to ghcjs-dom-0.2.3.0

Creating this issue just to track progress on upgrading to ghcjs-dom-0.2.3.0. I tried myself, but it seems that change will be too big for me to handle.

foldDyn freezes reflex-dom with ghcjs

When I use foldDyn in my reflex-dom code, compiled to a web page using ghcjs, the event system on the web page no longer seems to work: keypress events no longer have any effect where they did before.

For example: adding foldDyn (:) [] ev where ev is a _textInput_keypress has this effect. Please let me know if you would like a full example.

I mostly use the branch hamishmack-master, in order to use ghcjs 0.2. I also tried https://github.com/k0001/reflex-dom/tree/develop-ghcjs-0.2.0 which includes some more recent patches, but this did not help.

text does not escape argument

It seems that the text combinator does not escape it's argument, which is really bad because of cross-site-scripting attacks.

A html inserting combinator should be named accordingly so it won't be fed with user input.

How to defer FFI call until after attributes are set

I'm trying to write ChartJS bindings but I'm running into an issue. When I got to apply ChartJS to the the canvas that I've created using elDynAttr I'm finding that the canvas size is zero resulting in the chart to be drawn incorrectly. What is the proper way to handle this? Code example.

     (canvas, _) <- elDynAttr' "canvas" (constDyn (Map.fromList                                                                                                                       
                                         [ ("height", "1000px")                                                                                                                      
                                         , ("width", "1000px")                                                                                                                       
                                         , ("style", "width: 1000px; height: 1000px")                                                                                                
                                         ]                                                                                                                                           
                                       )) (return ())                                                                                                                                
    schedulePostBuild $ do                                                                                                                                                           
      _ <- liftIO $ lineChart (_el_element canvas) lineData                                                                                                                          
      return () 

Here is a gist of the ffi code https://gist.github.com/DiegoNolan/cea621f6abcb25e79fb2.

I added the schedulePostBuild just to see if it would work.

provide a possibility to terminate `mainWidget`

It should be possible to somehow cleanly let a call to mainWidget terminate. For testing it is crucial that it's possible to run a mainWidget, perform some tests and then cleanly tear everything down again to be able to run the next test-case.

I tried throwing exceptions, but for some reason I'm not able to catch any exception that is thrown inside mainWidget from the outside. It just causes the whole process to die.

Separate webkitgtk from dependecies.

It is currently impossible to build reflex-dom on Windows because of this dependency. I understand that webkitGtk is necessary for the GHC version of Reflex, but couldn't it be separated from the pure JS version?

Webkitgtk requires the webkitgtk-3.0 package which is unavailable for Windows and building it is nigh impossible. Due to this problem, even though GHCJS builds successfully in Windows, development for Reflex remains unreachable without the use of VMs, even when you are targeting a pure JS build.

dyn at other position in the DOM, popup handling

this was covered a bit on the side in bug #35, but I think this probably deserves its own bug. I'm not sure how to handle popups in reflex-dom, actually my feeling is that it's not well-catered for use case -- I don't understand how the existing commercial projects can make it properly with the primitives in place... I must be missing something, or possibly I have a little more specific requirements?

I make popups using the bootstrap system. I have a div with a certain ID, render the HTML I want in the div, then I call a JS function that displays that div as a popup. In normal HTML/JS, I would have a DIV at the top or bottom of the page, and reuse it -- because typically can display only one popup at a time.

Now in reflex I don't see how to from point X in the DOM (where I'm rendering the 'edit' button that'll open the popup) modify point Y (where the popup contents live). So my first approach was to generate the popup div just next to my code. But that was bloated. For instance if I display a list of 10 items, I would have in my DOM 10 popup divs, each next to its 'edit' button.
The next step was to move the popup div a little higher up in the DOM, then communicating, passing up and down events, but that message-passing was really messy. In addition sometimes an action for the popup would cause re-generation of the part of the DOM where the popup HTML lived... That required careful timing to make sure the popup was fully closed before the DOM update would occur (otherwise the popup would be wiped from the DOM before it had fully closed, causing funky effects), which was messy and forced me to disable animations when closing popups so that the user wouldn't have to wait too much.

Then I came up with the solution that I currently use:
https://github.com/emmanueltouzery/cigale-timesheet/blob/97de81a01b5bac2a44d238df2861a82a8b0e1d90/src/WebGui/Common.hs#L220-L247

At the time I copy-pasted dyn from reflex-dom and modified it so that it may render not at the current location within the DOM, but at any element ID. I'm super happy with this solution, although it's stringly typed. I guess I could put the element in a reader monad transformer and pass it, and so on.

Anyway now I have a problem because I'm trying to update my app to the latest reflex & reflex-dom develop versions, and the code changed in such a way that I don't manage to port my dynAtEltId.

I wonder about two things:

  1. how come I seem to be the only one with such requirements? I wonder how others handle popups?
  2. if my requirements are indeed slightly different, is there a more sound way to handle this in reflex?

Use the GitHub default branch for development

This is just a suggestion with an explanation for why I think it's useful.

I believe most projects on GitHub make the default branch (as specified in the repository's settings) – usually master but can be anything – the development branch and use other branches or tags for releases. This is useful for several reasons:

  • Visitors can see (and, would guess, expect to see, since it's the common case) the latest work quickly without looking for another branch.
  • GitHub uses the default for pull requests. So, you won't have to ask somebody to use a different branch for a PR again in the future.

In that light, I would recommend setting the default branch on GitHub to whatever branch you use for ongoing development, which I guess is develop.

Alternatively, you could change to doing development on master, which is what seems to be most common on GitHub.

You can always have another branch follow releases. Or, you could just use tags for releases, which it looks like you did for version 0.2.

undefined crashes ghci when using reflex-dom

Consider the following scenario:

  1. you have cabal repl running
  2. you are happily writing your code in ghc/reflex-dom
  3. something bad happens

Sample code: https://gist.github.com/anonymous/770b201ff0cd78636ec9

Now, when I run main0, the following happens in my cabal repl:
https://gist.github.com/anonymous/cb5088c5f6ba5f90d73a

I got an undefined. That's okay. My repl is still alive.

Now, when I run main1, the following happens in my cabal repl:
https://gist.github.com/anonymous/92563966c5e2a4f1437f

My repl dies. The "undefined" kills my repl.

This is problematic since:

  1. I like "cabal repl + reloads" since it's faster than cabal run

  2. I like sprinkling "undefined" all over the place as "to code in the future"

  3. this coding style can't work with reflex-dom since undefined = assassinates cabal repl :-(

Release Status

Hi there! I am currently trying to port my application from purescript (purescript-pux) to Haskell with reflex-dom. Unfortunately I am facing problems getting my dependencies to build with ghcjs. reflex-platform worked fine for the tutorial, but it seems that it breaks as soon as I add a single other dependency. Anyway - I experimented with the platform and with nixpkgs:

haskell.packages.ghcjs

which is basically completely broken, fortunately I also tried

haskell.packages.ghcjsHEAD

which I got to work pretty well actually, I even got reflex to build via jailbreak=true and some other minor tweaks. But reflex-dom-0.3 has a dependency on jsaddle which seems to have some build issues, it looks like reflex-dom-#development no longer has this dependency and as a result I get a nix-shell for building it, but there it starts failing (I used jailbreak again to get anywhere). In particular:

  • A dependency is missing in the cabal file: ghcjs-dom-jsffi
  • WebView cannot be found in src-ghcjs/Reflex/Dom/Internal/Foreign
  • runWebView is missing ..

I started fixing these problems, but then I thought - "Hey man, this is the development branch - you have no idea how release close this stuff is and what is left to do apart from fixing compiler errors" - so I stopped and opened this issue, with the basic issue: A new release seems to be the easiest way to get reflex-dom to work with ghcjsHEAD, so how close is reflex-dom to a new release? Should I wait/help or try to get 0.3 to work?

Thank you!

Best regards,

Robert

Can reflex-frp-dom be compiled with Haste?

If not, then why? Just curious because it seems that Haste compiles down to a smaller JS size, which is important from a production perspective.

Has anyone tried it? Any benchmarks between Haste and GHCJS?

voidEvents need to fire before next input frames

I made a minimal (ish) test case yesterday to illustrate the problem (without javascript) in case it's useful. Thought I'd attach it here in case anyone found it useful.

  {-# LANGUAGE RecursiveDo #-}

  import Reflex.Dom
  import Reflex.Host.Class

  import Control.Monad
  import Control.Monad.IO.Class
  import Data.Monoid

  run :: MonadWidget t m => m ()
  run = el "div" $ do
    clicked <- button "Go"  

    (e, ref) <- newEventWithTriggerRef
    performEvent_ $ ffor clicked $ \_ -> do
      forM_ [1..10] $ \i -> do
        runFrameWithTriggerRef ref i

    rec 
      e' <- performEvent $ ffor (attach prevB e) $ \(prev, i) -> liftIO $ do
        putStrLn $ ("Processing: " <> show (prev, i))
        return i

      performEvent_ $ ffor e' $ liftIO . print
      prevB <- hold (0 :: Int) e'

    return ()  


  main = mainWidget $ run

`performRequestAsync` slows other elements down.

I have this code: https://gist.github.com/e2750b4615e3be7f4853. It creates a textarea input and then displays the value of the textarea (debug value). It also sends an xhr request to a server on every keystroke and displays the server's answer (debug answer). If the server is slow then of course I expect the latter output (the one of debug answer) to lag. But what happens is that also the first output (from debug value) gets slowed down by a slow server, although all input values should be available immediately client side.

It also seems as if performRequestAsync doesn't send requests in parallel if you type faster than the server can answer.

I'm new to reflex so I'm not sure if this is intended behaviour or a bug.

Comparison with React (or any virtual-DOM based library)

Over at https://github.com/vacationlabs/haskell-webapps we're almost through with our POC of Reflex-DOM. We're about to start our POC of the same app with either Pux or Thermite

While we will be in a position to juxtapose Reflex with React-like libraries at the end of this exercise, we'd like to know your opinion on this matter. What does Reflex-DOM solve that React-like libraries don't? What does Reflex-DOM solve more elegantly/efficiently than React-like libraries?

GHCJS (8.0) compiling reflex-dom takes excessive memory

I'm building reflex-dom 9af728b on CircleCI, and the instance keeps hitting the 4 GB memory limit. Specifically, I've seen GHCJS consistently reach around 3.223244 GB of resident memory. I've also seen it reach > 3 GB on a local Linux VM with 4 GB RAM, though, for some reason, it didn't reach the max.

In most of my builds, reflex-dom was one dependency out of many, but in the latest, I tried building it alone. It reached this point before dying:

[23 of 24] Compiling Reflex.Dom.Old   ( src/Reflex/Dom/Old.hs, .stack-work/dist/x86_64-linux/Cabal-1.24.0.0_ghcjs/build/Reflex/Dom/Old.js_o )
Linking Template Haskell (Foreign.JavaScript.TH,Reflex.Dom.Builder.Class,Reflex.Dom.Builder.Class.Events,Reflex.Dom.Builder.Immediate,Reflex.Dom.Builder.InputDisabled,Reflex.Dom.Builder.Static,Reflex.Dom.Class,Reflex.Dom.Internal,Reflex.Dom.Internal.Foreign,Reflex.Dom.Location,Reflex.Dom.Time,Reflex.Dom.WebSocket,Reflex.Dom.WebSocket.Foreign,Reflex.Dom.Widget,Reflex.Dom.Widget.Basic,Reflex.Dom.Widget.Input,Reflex.Dom.Widget.Lazy,Reflex.Dom.Widget.Resize,Reflex.Dom.Xhr,Reflex.Dom.Xhr.Exception,Reflex.Dom.Xhr.Foreign,Reflex.Dom.Xhr.ResponseType,ThRunner8)

This problem is, of course, a mix of an issue with GHCJS and reflex-dom. But I thought posting here might bring out other people who have experienced something similar with reflex-dom.

I haven't looked at how reflex-dom organizes its TH, but I have found with an older version of GHCJS that putting all my TH in one module both reduced maximum memory consumption and sped up the build. I could test this to see if it changes anything.

Other than that, are there any suggestions for debugging or resolving this?

Disconnect event handlers?

Hi,

After migrating to the develop branch I can't find a way to use the "disconnect" functionality previously provided by newEventWithTrigger.

The thing is that I need to trigger the event from a callback which is passed to a foreign library from IO. I could do this before like this and reflex would take my cleanup function to run it when the event is GCd. This is very important for my use-case as I need to release the haskell callback in order not to leak memory when an olMap widget is destroyed.

However, with the new API the best I could come up with is this . If I use newEventWithTrigger the only way I can find to trigger the event is with fireEvents but I cannot run that from IO. The only way I could find to get an "IO-triggerable" trigger is with newTriggerEvent but I see no way to release it when I'm done with it.

What would be the correct way to do this with the new API?

Thanks!

Could not find module `Reflex.Dom'

I'm still trying to make a pure Windows setup. When I try to build a simple program with:

ghcjs --make test.hs -v

I get this error:

*** Chasing dependencies:
Chasing modules from: *test.hs

test.hs:3:8:
    Could not find module `Reflex.Dom'
    Locations searched:
      Reflex\Dom.hs
      Reflex\Dom.lhs
      Reflex\Dom.hsig
      Reflex\Dom.lhsig
*** Deleting temp files:
Deleting:
*** Deleting temp dirs:
Deleting:

I'm importing Reflex and Reflex-Dom inside a sandbox, which is something I didn't tried.

keypress event doesn't seem to fire properly on firefox

Given the following minimal code:

module Main where

import Reflex
import Reflex.Dom

main :: IO ()
main = mainWidget $ el "div" $ do
  t <- textInput
  text "Last key pressed: "
  let keypressEvent = fmap show $ _textInput_keypress t
  keypressDyn <- holdDyn "None" keypressEvent
  dynText keypressDyn

Compiled with ghcjs Main.hs, I get the expected behavior* on Chrome, but not on Firefox (versions 35.0 and 37.0.1). Instead, I see 0's, though if I tab out of the input box, I do see a 7.

  • Where the expected behavior is to see a key code every time a key is pressed.

Firefox:
2015-04-14-010933_1916x478_scrot

Chrome:
2015-04-14-010944_1916x478_scrot

Poor performance with SVG and listWithKey

From @gergoerdi on March 12, 2016 13:50

Doug asked me to post this even with the state the code is currently in (which is far from optimal), so here goes...

My code is in https://github.com/gergoerdi/tfb-reflex-repro and to reproduce it, just do a stack build in that directory, then navigate to the resulting index.html. (You'll need to edit the path in Main.hs because that's how hacked-together the source is at the moment).

If you then click on the Play button, everything works as expected, until the pace picks up and there are lots of rectangles flying around. That's when the framerate goes to crap really fast.

For comparison, I have the original Elm implementation running on http://unsafePerform.io/projects/tfb/ (but that one uses an HTML Canvas instead of SVG -- I'm not sure if that difference matters).

Copied from original issue: reflex-frp/reflex#46

documentation missing a line for elDynAttrNS

The elDynAttrNS' element came up on discussion in StackOverflow [1] and thus I learned the reflex-dom quickrefrence is not complete.

I would gladly add the one line and do a pull-request. Especially if one can indicate what it should say? Obviously I can take a guess. It should look very similar to:

-- As above, but now the attribute map is Dynamic
[W]   elDynAttr  :: Text ->   Dynamic (Map Text Text) ->     m a -> m a
[W]   elDynAttr' :: Text ->   Dynamic (Map Text Text) ->     m a -> m (El, a)

delayed getPostBuild event happens much too late.

This code creates an SVG trail of dots that follow the mouse as it moves over an svg element. At the same time that a dot is created, a getPostBuild event fires, gets delayed by 0.3 seconds and then signals the code that the dot should be removed. The effect is to create a trail of dots that disappear after 0.3 seconds.

In earlier versions of reflex this worked as expected. In the latest version, no dots disappear while the mouse is moving ( and new dots are being created ). Once the mouse stops moving the dots start to disappear but it looks like the rate at which they disappear is one every 0.3 seconds - not at the same rate as they were created.

I can still reproduce the earlier (correct, I believe) behavior by checking out an earlier version of reflex-platform, running try-reflex in that environment, and rebuilding. In particular, revision c0bd3f3e991346a1b789d674dd18cfe567f4dd38 of reflex-platform ( last change on Oct 10,2016 ) works fine but version 6f7aedfd57678b6e5c46dff3657dc60d40efe427 (current as of Nov 28, 2016) does not.

Follow this link to see a demo that shows the code behaving as expected ( built with the earlier reflex-platform ). Follow this link to see a demo of the code behaving incorrectly ( built with the later reflex-platform ). Except for the color of the dots, the code used to build those two examples is the same.

Upgrade to ghcjs-dom >= 0.3

Hi!
reflex-dom does not compile with ghcjs-dom >= 3.0. There have been some changes where pure functions went into the IO monad. f.e. when compiling with ghcjs-dom-0.3.1.0 I get:

    [ 5 of 24] Compiling Reflex.Dom.Xhr.Foreign ( src-ghcjs/Reflex/Dom/Xhr/Foreign.hs, .stack-work/dist/x86_64-linux/Cabal-1.24.0.0_ghcjs/build/Reflex/Dom/Xhr/Foreign.js_o )

    src-ghcjs/Reflex/Dom/Xhr/Foreign.hs:172:69-78: error:
        • Couldn't match type ‘IO Blob’ with ‘Blob’
          Expected type: GObject -> Blob
            Actual type: GObject -> IO Blob
        • In the second argument of ‘(.)’, namely ‘castToBlob’
          In the first argument of ‘(<$>)’, namely
            ‘XhrResponseBody_Blob . castToBlob’
          In the second argument of ‘($)’, namely
            ‘XhrResponseBody_Blob . castToBlob <$> mr’

I did a quick fix for that but then I got a huge bunch of other errors in

   /home/alios/src/reflex-dom/src/Reflex/Dom/Builder/Immediate.hs:190:19: error:
        • Couldn't match type ‘IO DOM.HTMLElement’ with ‘DOM.HTMLElement’
          Expected type: RawElement GhcjsDomSpace
            Actual type: IO DOM.HTMLElement
        • In the first argument of ‘wrap’, namely ‘e’
          In the expression: wrap e
          In a stmt of a 'do' block:
            wrapped <- wrap e $ extractRawElementConfig cfg

    src/Reflex/Dom/Builder/Immediate.hs:191:3-31: error:
        • Couldn't match type ‘IO DOM.HTMLElement’ with ‘DOM.HTMLElement’
          Expected type: ImmediateDomBuilderT
                           t m ((Element er GhcjsDomSpace t, a), DOM.HTMLElement)
            Actual type: ImmediateDomBuilderT
                           t m ((Element er GhcjsDomSpace t, a), IO DOM.HTMLElement)
        • In a stmt of a 'do' block: return ((wrapped, result), e)
          In the expression:
            do { doc <- askDocument;
                 events <- askEvents;
                 Just e <- ImmediateDomBuilderT
                           $ fmap DOM.castToHTMLElement
                             <$>
                               case cfg ^. namespace of {
                                 Nothing -> createElement doc (Just elementTag)
                                 Just ens -> createElementNS doc (Just ens) (Just elementTag) };
                 ImmediateDomBuilderT
                 $ iforM_ (cfg ^. initialAttributes)
                   $ \ (AttributeName mAttrNamespace n) v
                       -> case mAttrNamespace of {
                            Nothing -> ...
                            Just ans -> ... };
                 .... }
          In an equation for ‘makeElement’:
              makeElement elementTag cfg child
                = do { doc <- askDocument;
                       events <- askEvents;
                       Just e <- ImmediateDomBuilderT
                                 $ fmap DOM.castToHTMLElement
                                   <$>
                                     case cfg ^. namespace of {
                                       Nothing -> createElement doc (Just elementTag)
                                       Just ens -> createElementNS doc (Just ens) (Just elementTag) };
                       .... }

    src/Reflex/Dom/Builder/Immediate.hs:239:21-71: error:
        • Could not deduce (IsElement (IO DOM.Element))
            arising from a use of ‘defaultDomEventHandler’
          from the context: er ~ EventResult
            bound by the instance declaration
            at src/Reflex/Dom/Builder/Immediate.hs:234:10-56
        • In the first argument of ‘runReaderT’, namely
            ‘(defaultDomEventHandler (DOM.castToElement t) en)’
          In a stmt of a 'do' block:
            runReaderT (defaultDomEventHandler (DOM.castToElement t) en) evt
          In the expression:
            do { Just t <- withIsEvent en $ Event.getTarget evt;
                 runReaderT (defaultDomEventHandler (DOM.castToElement t) en) evt }

    src/Reflex/Dom/Builder/Immediate.hs:264:20-34: error:
        • Couldn't match expected type ‘DOM.HTMLInputElement’
                      with actual type ‘IO DOM.HTMLInputElement’
        • In the first argument of ‘Input.setValue’, namely
            ‘domInputElement’
          In the expression: Input.setValue domInputElement
          In a stmt of a 'do' block:
            Input.setValue domInputElement
            $ Just (cfg ^. inputElementConfig_initialValue)

    src/Reflex/Dom/Builder/Immediate.hs:265:31-45: error:
        • Couldn't match expected type ‘DOM.HTMLInputElement’
                      with actual type ‘IO DOM.HTMLInputElement’
        • In the first argument of ‘Input.getValue’, namely
            ‘domInputElement’
          In a stmt of a 'do' block:
            Just v0 <- Input.getValue domInputElement
          In the expression:
            do { ((e, _), domElement) <- makeElement
                                           "input" (cfg ^. inputElementConfig_elementConfig)
                                         $ return ();
                 let domInputElement = castToHTMLInputElement domElement;
                 Input.setValue domInputElement
                 $ Just (cfg ^. inputElementConfig_initialValue);
                 Just v0 <- Input.getValue domInputElement;
                 .... }

    src/Reflex/Dom/Builder/Immediate.hs:266:54-68: error:
        • Couldn't match expected type ‘DOM.HTMLInputElement’
                      with actual type ‘IO DOM.HTMLInputElement’
        • In the first argument of ‘Input.getValue’, namely
            ‘domInputElement’
          In the second argument of ‘(<$>)’, namely
            ‘Input.getValue domInputElement’
          In the expression: fromMaybe "" <$> Input.getValue domInputElement

    src/Reflex/Dom/Builder/Immediate.hs:269:22-36: error:
        • Couldn't match expected type ‘DOM.HTMLInputElement’
                      with actual type ‘IO DOM.HTMLInputElement’
        • In the first argument of ‘Input.setValue’, namely
            ‘domInputElement’
          In the expression: Input.setValue domInputElement
          In a stmt of a 'do' block: Input.setValue domInputElement $ Just v'

    src/Reflex/Dom/Builder/Immediate.hs:275:22-36: error:
        • Couldn't match expected type ‘DOM.HTMLInputElement’
                      with actual type ‘IO DOM.HTMLInputElement’
        • In the first argument of ‘Input.setChecked’, namely
            ‘domInputElement’
          In the expression: Input.setChecked domInputElement
          In a stmt of a 'do' block:
            Input.setChecked domInputElement
            $ _inputElementConfig_initialChecked cfg

    src/Reflex/Dom/Builder/Immediate.hs:277:24-38: error:
        • Couldn't match expected type ‘DOM.HTMLInputElement’
                      with actual type ‘IO DOM.HTMLInputElement’
        • In the first argument of ‘Input.getChecked’, namely
            ‘domInputElement’
          In a stmt of a 'do' block: Input.getChecked domInputElement
          In the second argument of ‘($)’, namely
            ‘do { Input.getChecked domInputElement }’

    src/Reflex/Dom/Builder/Immediate.hs:279:38-52: error:
        • Couldn't match expected type ‘DOM.HTMLInputElement’
                      with actual type ‘IO DOM.HTMLInputElement’
        • In the first argument of ‘Input.getChecked’, namely
            ‘domInputElement’
          In a stmt of a 'do' block:
            oldChecked <- Input.getChecked domInputElement
          In the expression:
            do { oldChecked <- Input.getChecked domInputElement;
                 if newChecked /= oldChecked then
                     do { Input.setChecked domInputElement newChecked;
                          .... }
                 else
                     return Nothing }

[...]

so I decided to create a ticket here.

redisplay of unchanged model causes flicker.

This code displays 1000 SVG circles using listWithKey. Every 2 seconds the circles get re-displayed without any changes.

In the latest version of reflex-platform, when the circles get redisplayed there is a flicker on the screen. Sometimes it is hard to see but other times it looks more like a complete redraw. If you open the inspect panel in chrome and view the tree representing the svg area, you will see the flicker/refresh there as well. In earlier versions of reflex this worked as expected ( no flicker at all ).

I can still reproduce the earlier (correct, I believe) behavior by checking out an earlier version of reflex-platform, running try-reflex in that environment, and rebuilding. In particular, revision c0bd3f3e991346a1b789d674dd18cfe567f4dd38 of reflex-platform ( last change on Oct 10,2016 ) works fine but version 6f7aedfd57678b6e5c46dff3657dc60d40efe427 (current as of Dec 01, 2016) does not.

Follow this link to see a demo that shows the code behaving as expected ( built with the earlier reflex-platform ). Follow this link to see a demo of the code behaving incorrectly ( built with the later reflex-platform ). The code used to build those two examples is the same.

Not possible to create a tree like widget, modelled using a dynamic, with minimal re-rendering?

I build a tree using listViewWithKey where leafs are form field (input/select) widgets and nodes are listViewWithKey.

The only way i can create a "child" creation function, where the type of the widget depends on the Dynamic modelling node/leafs, is this - using dyn:

formElemCmdToWidget :: MonadWidget t m => [PathElem] -> Dynamic t FormElemCmd -> m (Event t UpdateT)
formElemCmdToWidget path dynOrd =
  let
  mapFld (OrdVar var) = 
   let
    l ve = fmap (fmap ( (flip (:) [] ) . (Upd path ) . UV . VarUpd )) ve
    in case var of
        SV sv -> l $ textField sv
        IV sv -> l $ intField sv
        CV sv -> l $ choiceField  sv
        DV sv -> l $ dateField sv
  mapFld (OrdRep vkey loopElemKey2FormCmds) = do
    res <- listViewWithKey loopElemKey2FormCmds someOtherFunction
    return res
  in do
    res <- dyn $ ffor (uniqDyn dynOrd) $ \o -> mapFld o
    res2 <- holdDyn (never) res
    return res2

Imagine a root widget created using listViewWithKey. That root dont have to be handled by a "dyn". So say 1st level will have 1 leaf and 1 subtree. As the subtree in 1st level will be created using dyn, the 2nd level will re-render whenever the dynamic of the subtree in 1st level changes. So it will work fine for 1st level. For second level, dyn forces re-render of the complete subtree - even if the actual change could be at N levels deep.

PS. With "minimal re-render" i mean that; if a leaf in a nested subtree changes, only that leaf should be rerendered and not the whole subtree its contained in. DS.

Routes

Reflex-DOM needs a story for URL routing, or some good docs to explain how to pull it off.

Catching errors

I'd like to perform an action when any part of my reflex-dom application throws an action.

I noticed that Control.Exception.handle at the top level doesn't seem to work, because apparently if an exception flies in widgetHold's second argument, it never bubbles up any more; instead only console.log(str); from function h$errorMsg(pat) { is invoked and my error message is printed to the developer console.

Is this what's supposed to happen?

Thanks!

dropdown should probably format keys differently

The dropdown function uses Show to format option values. This results in things like this:

<option value="Just (Foo "blah")">

In my testing this appears to work in chrome, but it seems rather fragile. dropdown should probably encode values so they can never contain illegal characters.

postBuild fires before the document fragment is added to the DOM

I've migrated a reflex binding for OpenLayers to the development branch of reflex-dom and I've noticed that I can no longer depend on the "postBuild" event to perform some initialization on the OpenLayers side which needs to be done when the element has been attached to the DOM and sized properly.

I've worked around it by polling the document until my element is added, like this, but with the stable version of reflex-dom I could simply do this.

Is this change intentional? If so, is there a better way I can use to be notified when an element I create is added to the DOM? If not I can try to submit a fix...

Cheers

textArea's keypress event doesn't seem to work

I've got a textarea and I did a traceEvent on the keydown event, but it never fires. Also, while you're fixing this, it would probably be good to go ahead and add keyup and keydown events too.

Strange `listWithKey` behavior

I'm getting strange behavior with listWithKey displaying a dynamic value.

On button press, the menuItems toggle from Join/Leave/Star to Join/Leave/Unstar. But the drawn list adds a bullet point with each toggle, and never displays text for "Star", ending up with lists that look like this:

* Join
* Leave
* 
* 
* Unstar

To reproduce:

{-# LANGUAGE OverloadedStrings #-}                         

import Reflex.Dom                                                               
import Data.Bool (bool)                                                         
import qualified Data.Text as T                                                 
import qualified Data.Map as Map                                                

main = mainWidget $ do                                                          
  bClick <- button "Click Me"                                                   
  boolDyn <- foldDyn (const not) True bClick                                    
  menuItems <- mapDyn filteredMenu boolDyn                       
  el "ul" $                               
    listWithKey menuItems $ const $ el "li" . dynText . fmap T.pack  
  return ()      

filteredMenu :: Bool -> Map.Map Menu String                                     
filteredMenu b = Map.fromList                                                   
               . map (\c -> (c, show c))                                      
               . bool (filter (/= Unstar)) (filter (/= Star)) b $ [minBound..maxBound]

data Menu = Join | Leave | Star | Unstar deriving (Enum, Bounded, Eq, Ord, Show)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.