2017-06-03 11 views
1

keyboard-input exampleのHandleKey以外のアクションからのキーボードイベントの登録を解除するにはどうすればよいですか? (質問は、ハロゲンバージョン2.0.1とpurescript 0.11.4に関連しています)ハロゲンキーボード入力の例とイベントの参加を解除する?

この例では、入力/戻りが機能します。クローズボタンを押してマウスでつぶすことができる要素のグループがあり、クローズアクションがそれを処理します。また、Enter/Returnを使用して要素を折りたたむことができ、必要に応じて機能します。

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 

問題は、私はマウスを使って(崩壊)の要素を閉じたときに、イベントリスナーが削除されていない(行っていない)、それはまだそこになるということです。要素をもう一度開くと、上記のコードで2番目(3番目、4番目など)のリスナーが作成され、すべてのキー押しが何度も処理されます。

私はキーボードイベントを作成することを検討していましたが、ここで正しい方法は聞こえません。

だから、質問は以下のとおりです。

  • キーボードリスナーがすでに存在しているかどうかを確認する方法は?
  • そして、Close-Actionで停止する方法は?
  • また、完了したSubscribeStatusを作成し、それをClose-Actionでキーボードリスナに送信することはできますか?

さらに質問:

  • example状態でunsubscribeを持っています。それの使い方?
  • は(私は、init -actionにして閉じる-actionでそれに何かを入れてみましたが、それは純粋な推測だった。)

後期編集: これはについての質問に関連しているようですdynamically attached event listenersおよびthis,thisおよびthisも参照のこと。

答えの1つは、状態を使用してダイナミックハンドラについて知ることが可能であり、それが私の問題のためのトリックでした。とにかく、ここに記載されている質問は残っていると思います(ハロゲンのハンドラを取り除く方法、特に例の脱退フィールドについてはどうしたらいいですか?)

+0

ますイベントソース。私は良い解決策を見つけるときに答えを書くでしょう。 – Albtzrly

答えて

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部分だと思います。ここでは、参照した例のような外部関数インタフェース(FFI)を使用しないHTMLDocumentのonMouseUpのイベントソースの例を示します。

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 

だから、コールバックは、(この場合、一般的なEventに)aイベントを取得します。リスナーへの参照を作成する必要があるので、addEventListenerと同じ参照をremoveEventListenerとして渡すことができます(関数参照は、リスナー関数が削除されるかどうかを判断するIDのように機能します)。

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) 
+0

もう1つの質問: 'リスニングを停止する'コメントでは、返信はH.Doneに返信することによってremoveEventListenerを呼び出します。 eval関数内の他のアクション(クエリ)からremoveEventListenerを直接呼び出すことはできますか?または、MooListenerからキーリスナーにH.Doneを送信することは可能ですか(あるいは、何らかの形で、mouseEventsをリスンしているハンドラからkeyEventListenerを削除する)ことは可能ですか?私がeventSourceの型を正しく理解していれば、removeEventListenerを返すようには見えません。まあ、最初の 'onMouseUp document'を作成し、そのリスナーを状態レコードに入れることはできますか? – Gspia

+0

私はそれが可能かもしれないと思っていますが、私はそれを行う最善の方法や反パターンであるかどうかはわかりません。私の考えは何とかEventSourceを保存して他のクエリでアクセスできるようにすることです。 EventSource newtypeをunEventSourceでアンラップすると、EventSource内のProducerとdone関数にアクセスできます。 eventSourceの実装を見てください - EventSourceがアンラップされ、removeEventListenerを呼び出すためにどのように使用されているのかが分かります。 – Albtzrly

関連する問題