Пример ввода галогенной клавиатуры и отписка от событий?
Как отказаться от подписки на события клавиатуры от других действий, кроме HandleKey в примере ввода с клавиатуры? (Этот вопрос относится к галогеновой версии 2.0.1 и purescript 0.11.4.)
В примере работает ввод / возврат. У меня есть группа элементов, которые можно свернуть с помощью мыши, нажав кнопку закрытия, и Close-action позаботится об этом. Кроме того, ввод / возврат может использоваться для свертывания элементов, и он работает как следует.
Open next -> do
st <- H.get
if not st.open
then do
H.modify (_ { open = true })
eval (H.action Init)
else pure unit
pure next
Close next -> do
H.modify (_ { open = false })
st <- H.get
case st.unsubscribe of
Nothing -> pure unit
-- Just smth -> H.liftAff smth
Just _ -> H.modify (_ { unsubscribe = Nothing}) -- H.liftAff us
pure next
Init next -> do
H.modify (_ { open = true})
document <- H.liftEff $ DOM.window >>= DOM.document <#> DOM.htmlDocumentToDocument
H.subscribe $ ES.eventSource'
(K.onKeyUp document)
(Just <<< H.request <<< HandleKey)
-- H.modify (_ { unsubscribe = ??? })
pure next
Проблема в том, что когда я закрываю (сворачиваю) элементы мышью, слушатель событий не удаляется (не Готово) и он все еще там. Когда я заново открываю элементы, приведенный выше код установит второго (третьего, четвертого и т. Д.) Прослушивателя, а затем каждое нажатие клавиши будет обрабатываться много раз.
Я думал о создании события клавиатуры, но здесь это звучит неправильно.
Итак, вопросы:
- Как проверить, есть ли уже прослушиватель клавиатуры?
- И как тогда остановить это на закрытии?
- Или возможно создать Done SubscribeStatus и отправить его слушателю клавиатуры при действии Close?
Дальнейшие вопросы:
- В примере есть
unsubscribe
в состоянии. Как это использовать? - (Я пытался вставить что-то в него в действии инициации и в действии закрытия, но это было чистое предположение.)
Позднее редактирование: похоже, это связано с вопросами о динамически подключенных слушателях событий, а также смотри это, это и это.
В одном из ответов говорилось, что о динамических обработчиках можно узнать только через использование состояний, и это помогло решить мою проблему. Во всяком случае, я думаю, что вопросы, изложенные здесь, остаются (как удалить обработчик с галогеном и особенно о поле отказа от подписки в примере - это как-то полезно?)
1 ответ
Мне потребовалось некоторое время, чтобы понять сигнатуру eventSource, но вот разбивка, которая может помочь прояснить, что происходит.
Это настоящая подпись...
eventSource' :: forall f m a eff. MonadAff (avar :: AVAR | eff) m =>
((a -> Eff (avar :: AVAR | eff) Unit) -> Eff (avar :: AVAR | eff) (Eff (avar :: AVAR | eff) Unit)) ->
(a -> Maybe (f SubscribeStatus)) ->
EventSource f m
Если мы используем своего рода псевдокод для именования компонентов подписи...
type Callback a = (a -> Eff (avar :: AVAR | eff) Unit)
type MaybeQuery a = (a -> Maybe (f SubscribeStatus))
type RemoveEventListener = (Eff (avar :: AVAR | eff) Unit)
Мы получаем...
eventSource' :: forall f m a eff.
(Callback a -> Eff (avar :: AVAR | eff) RemoveEventListener) ->
MaybeQuery a ->
EventSource f m
Я думаю, что часть, которую вы пропустили, это часть RemoveEventListener. Вот пример EventSource для onMouseUp для HTMLDocument, который не использует интерфейс внешней функции (FFI), как в примере, на который вы ссылались.
import DOM.Event.Types as DET
import DOM.Event.EventTarget as DEET
import DOM.HTML.Event.EventTypes as EventTypes
onMouseUp :: forall e
. DHT.HTMLDocument
-> (DET.Event -> Eff (CompEffects e) Unit)
-> Eff (CompEffects e) (Eff (CompEffects e) Unit)
onMouseUp doc callback = do
let eventTarget = (DHT.htmlDocumentToEventTarget doc)
-- Create an EventListener that will log a message
-- and pass the event to the callback
let listener =
DEET.eventListener (\event -> do
log "mouseUp"
callback event
)
-- Add the EventListener to the
-- document so it will fire on mouseup
DEET.addEventListener
EventTypes.mouseup
listener true eventTarget
-- Return the function that will later
-- remove the event listener
pure $ DEET.removeEventListener
EventTypes.mouseup
listener true eventTarget
Таким образом, обратный вызов получит a
событие (в этом случае общий Event
). Обратите внимание, что мы должны создать ссылку на слушателя, поэтому мы можем передать ту же ссылку на addEventListener, что и removeEventListener (ссылка на функцию действует как идентификатор, определяющий, какая функция слушателя удаляется).
Функция MaybeQuery также будет передана a
событие, так что Halogen может выполнить запрос, и вы можете решить, следует ли вам продолжать слушать события или нет. Этот запрос должен быть структурирован следующим образом...
data YourQuery =
| HandleEvent Event (SubscribeStatus -> a)
eval (HandleEvent event reply) =
-- Decided if you want to keep listening
-- or now.
-- Keep listening...
-- pure $ reply (H.Listening)
-- Stop listening. Halogen will call the removeEventListener
-- function you returned from onMouseUp earlier
-- pure $ reply (H.Done)
И просто покажи, как подписаться на EventSource...
import DOM.HTML.Window as Win
import Halogen.Query.EventSource as HES
document <- H.liftEff $ (window >>= Win.document)
H.subscribe $ HES.eventSource'
(onMouseUp document)
(Just <<< H.request <<< HandleEvent)