More bananas

Posted on January 12, 2015

On the whole, this is very neat. First we attach an event handler, which turns whatever actual DOM event occurred into the overall event type. For example, if a click toggles the checkbox on item 3 to be checked, that generates the event Toggle 3 True.

Within the banana network, we need a function that extracts events of a particular type. This part seems more repetitive than it should be:

justToggleEs (Toggle n b) = Just (n, b)
justToggleEs _ = Nothing

It’s also a bit odd to change the representation of the event again, but if we were to use the Toggle data constructor again, the next function would have to cope with receiving an argument of any XEvent type, even though we know it must be a Toggle. Actually, perhaps it would be better to do that. Compare the current version:

todoToggle :: (Int, Bool) -> IO ()
todoToggle (n, b) = select (todoIdSelector n) >>= toggle b

with this proposed version:

todoToggle :: XEvent -> IO ()
todoToggle (Toggle n b) = select (todoIdSelector n) >>= toggle b
todoToggle _ = error "todoToggle called with non-Toggle argument"

Anyway, modest tweaks aside, we’ve now dealt with updating the page. I believe that the ajax call to update the external model will be in todoToggle too.

All that remains is to update our internal model. This is a behaviour, so we need a second selection function that extracts all events that can affect the internal model, and returns pure functions that do so:

justTodoFns :: XEvent -> Maybe ([Todo] -> [Todo])
justTodoFns (Toggle n b) = Just set
  where 
    set ts = case find ((n ==) . todoId) ts of
      Nothing -> ts
      Just x -> x { todoDone = b } : L.delete x ts
...

All nice and clean. The snag I’ve hit, though, is with entering a new item. If I try to follow this same pattern, I’m stuck: we can’t pick an id for the new item without having access to the entire list. And I don’t know how to combine the behaviour which is that internal list, with the two events: the NewEnter Text event that fires (with the value of the input element) when the enter key is hit, and the changes event synthesized from the changing of the behaviour.

Bother.

Now, in fact the id for a new item should come from the external model; the ajax call, when we have such things. For the current exercise, I think I need an external model which is not conflated with the internal model (as it was in the previous version). Can I use an IORef for this?

Yes, that looks extremely promising!