How to subscribe to "custom" FFI event from halogen

I will explain which information i already found and which event i want to respond to.

This github issue asks about FFI and then forwards to

Here the working of EventSource if covered. But nothing specific about FFI is mentioned. The event in the example code is onSomeEvent which i assume is a stand in for any of the events listed here

I however, would like to a “custom” event hide.bs.modal from

I have access to the element in purescript through a Ref so that substitutes the jQuery $('#myModal') part.

Questions:

Is the method in the gists (subscribing through purescript) still the way to go in this situation?

Should i not instead do something in javascript FFI code (that i already wrote for the modal) ?

How can i create an event in purescript with a custom string hide.bs.modal (or should i do this in JS, see previous question) ?

Thanks for help !

1 Like

@garyb could you have a look at this question please? :slight_smile:

Just to check I’m understanding the question correctly: you have an element that will raise an event with the type "hide.bs.modal", and want to know how to listen to it?

Yes that’s right @garyb

preferably i would like to put as much logic into the FFI purs or js file so that it doesn’t leak much code in the main application.

I think you should be able to add a HE.handler (EventType "hide.bs.modal") \event -> ... property to the element. That’s how most of the other onBlah handlers are defined, with the appropriate EventType for that handler already plugged in.

If that doesn’t work, there are some other options, but this is certainly the simplest! :wink:

1 Like

@garyb i made this function and put it in the FFI module

onHide :: forall r i. (Event -> Maybe i) -> HP.IProp r i
onHide f = HE.handler (EventType "hide.bs.modal") f 

The event doesn’t trigger the purescript logic (i don’t know why).

The bootstrap native javascript code should watch the close button onClick, and click on background (behind modal), and escape key and why any of these are triggered, then just let the element emit “hide.bs.modal” event as far as i understood the js code.

In the main module i have

BSM.onHide \_ -> Just CloseModal

and

CloseModal -> trace "open modal" \_ -> pure unit

as the two relevant parts of the code.

For reference … here is where the event is generated

And helper function:

This was a bit stupid of me. I forgot to change the debug message :cry:

On the plus side i’m very happy that it works. And which such a simple solution.

I was thinking it was going to be very complicated because of the bootstrap native javascript code triggering the event in all sorts of ways.

Thanks again very much @garyb

1 Like

Oh! Haha, well, glad you got it sorted.

I’d put this more self contained example together to illustrate it should work before I saw this, but I’ll drop it here anyway in case it’s useful to anyone else:

import Prelude

import Data.Foldable (traverse_)
import Data.Maybe (Maybe(..))
import Effect (Effect)
import Effect.Class (class MonadEffect)
import Effect.Class.Console as Console
import Halogen as H
import Halogen.HTML as HH
import Halogen.HTML.Events as HE
import Halogen.HTML.Properties as HP
import Web.Event.Event (Event, EventType(..))
import Web.Event.EventTarget as EventTarget
import Web.HTML.HTMLElement as HTMLElement

data Action
  = Trigger
  | Handle

type State = Unit

component :: forall f i o m. MonadEffect m => H.Component HH.HTML f i o m
component =
  H.mkComponent
    { initialState: const unit
    , render
    , eval: H.mkEval $ H.defaultEval { handleAction = handleAction }
    }

render :: forall m. State -> H.ComponentHTML Action () m
render _ =
  HH.div
    [ HP.ref containerRef
    , HE.handler (EventType "testEvent") \_ → Just Handle
    ]
    [ HH.button
        [ HE.onClick \_ -> Just Trigger ]
        [ HH.text "Trigger" ]
    ]

containerRef ∷ H.RefLabel
containerRef = H.RefLabel "container"

-- I guess we don't have an event constructor in the web libraries just now
foreign import mkEvent ∷ EventType → Effect Event
-- exports.mkEvent = function (type) {
--   return function () {
--     return new Event(type);
--   };
-- };

handleAction :: forall o m. MonadEffect m => Action -> H.HalogenM State Action () o m Unit
handleAction = case _ of
  Trigger ->
    H.getHTMLElementRef containerRef >>= traverse_ \el → H.liftEffect $ do
      event ← mkEvent (EventType "testEvent")
      EventTarget.dispatchEvent event (HTMLElement.toEventTarget el)
  Handle ->
    Console.log "testEvent was triggered"
3 Likes