0

So I have a component, and let's say when I click on it this should trigger a state change, e.g.:

:on-click #(om/set-state! this {:activated? true})

now, what If I want to "deactivate" it when clicked anywhere on the document? I guess I could just use addEventListener by hooking it up onto the document object, something like this:

(componentDidMount [this]
       (events/listen (gdom/getDocument)
         (.-CLICK events/EventType)
         #(om/set-state! this {:activated? false}) true))

now this does what I want, but first of all if I have 200 instances of the same component it will have 200 event listeners, right? Which is not desirable but ok, I guess

The real question though is how do I distinguish one instance of the component from another when setting its state? I definitely don't want all of them to be "deactivated", but only the one in which context that click event handler is being triggered

iLemming
  • 34,477
  • 60
  • 195
  • 309
  • It's okay to have N event listeners per N DOM nodes, while each has its own event listener, and the former is fine, too. I bet you could check a certain property of state (perhaps `:activated`), and if it has a certain value, just do nothing, otherwise do something, while even listener would still be executed per every click. (that's perfectly fine, too) It doesn't really help answer the main question but hopefully it's still useful. – rishat Sep 12 '16 at 19:06

1 Answers1

1

I think the title of the question points to the real problem: global events affecting local state. It sounds to me like the notion of being "activated" doesn't belong to each of these components (as local state), but to something higher in the tree. Otherwise, they'd function independently. But it sounds to me like you want one of these to be activated at a time, correct?

I'd identify the currently active one either in a parent's local state or in global app state. Then I'd have the parent hand each child a callback it can call when it's clicked to activate it. Lastly, the parent can have a single click event listener on its element, presumably an element which covers the entire page, which deactivates the active child (by setting the active child to nil wherever it's being stored).

Peeja
  • 13,683
  • 11
  • 58
  • 77
  • I do understand semantics of not mixing global events with local state, but in this case I'm curious about technicality of the problem (namely distiguishing context of component wherein the handler is triggered). `listen` takes a context as a parameter http://www.closurecheatsheet.com/events#listen, maybe there's a way to employ `this-as` macro and find exact component which triggered the global event? – iLemming Sep 12 '16 at 19:26
  • If you *really* want to do this, you could `events/listen` from your `:on-click` handler, and detach the listening after it fires. But I still think there's probably a structural issue to fix here, and you're probably going to run into it and work around it repeatedly. – Peeja Sep 12 '16 at 19:30
  • yeah I don't like detaching/attaching event listeners. Also having an opaque element that covers entire page just to catch click event doesn't feel right, then you'd have to click twice (for other side-effects) – iLemming Sep 12 '16 at 19:37
  • Is attaching and detaching *worse* than having 200 listeners? – Peeja Sep 12 '16 at 20:00