I'm trying to set an IORef in threepenny-gui but I can't get it to work. In my app the IORef itself will be more complicated and not itself be displayed - but this example demonstrates the problem I think.
Here is my try:
testIORef2 :: IORef String -> Window -> UI ()
testIORef2 ref window = void $ do
return window # set title "Test IORef"
inCell <- UI.input
outCell <- UI.input
getBody window #+ [
column [
grid [[string " In cell::", element inCell]
,[string "Out cell::" , element outCell ]]
, string "Cells should update while typing."
]]
-- When value changes write to IORef
on UI.valueChange inCell $ \_ -> do
inValue <- get value inCell
liftIO $ writeIORef ref inValue
-- Read the IORef
refVal <- liftIO $ readIORef ref
-- Behaviour which holds the string value in the input cell
inValue <- stepper "0" $ UI.valueChange inCell
-- Behaviour which holds the value in the ref
let outValue = (const refVal) <$> inValue
-- Set the value of the output cell to the outValue
element outCell # sink value outValue
The code sort of works but the outValue is not quite up to date.
How do I fix it so that the updates are on time. Also, any improvements to the code would be welcome.
Thanks.
The code you wrote is probably not what you intended to do. The line
let outValue = (const refVal) <$> inValue
specifies that outValue
is a Behavior
whose value is constant and equal to refValue
. In turn, the latter value is obtained from
refVal <- liftIO $ readIORef ref
which means that its the value stored by IORef
at this point in time in the UI
monad.
When using IORef
, you want to read the value of the reference when something changes, and use this value to modify the UI content, for instance like this:
on UI.valueChange inCell $ \_ -> do
inValue <- get value inCell
liftIO $ writeIORef ref inValue
outValue <- liftIO $ readIORef ref
element outCell # set value outValue
For reasons of consistency (order of operations), it is not advisable to use an IORef
as a source for a Behavior
— it's either the latter or the former.