Avoiding component coupling while dealing with related events

I am implmenting a formula editor, which opens on a click, and parses the resulting formula on focusout. However, I would like to ignore focusout if it is generated by a click on various other “clickable” things: for instance, there is an autocomplete box, a help box with internal links, a message box…

What is the best design to figure out if a view or component that handles click has been clicked on without coupling all of the implementation of all the components?

One thought was to force them all to define “clickable” html class (which is already some coupling but perhaps not so severe, then have the app handle “mousedown” (which should fire before focusout – I don’t see that click and focusout have a guaranteed order). In the mousedown handler I’d set a property that said whether the last click was clickable.

This has several drawbacks (for instance, I’d want to clear the property with a delay perhaps? … how do I know that the focusout and the mousedown are related…). Is there another way? Can I find a list of event handlers somewhere, to avoid the coupling?

Any thoughts welcome; thanks!

On reflection, this is my plan:

  1. catch click at the application level using “normal” handler (not event manager), and increment a global “unhandledClick” property.

  2. In the editor, don’t handle focusOut; rather, handle keyPress, and filter for escape and tab (the control is a textbox, so “enter” doesn’t submit). Also, an observer of application “unhandledClick” in the editor component will trigger submit.

Does this sound reasonable?

No to globals. And just because a component can listen to focusOut doesn’t mean it has to do anything special with the hook. I think you’re better off just handling your special behaviour on its own and not worrying whether anything returns null.

Like, your special formula editor component has a certain hook, focusOut which parses the formula that was input by the user. You also have a video component that on focusOut doesn’t do anything. There’s no real coupling there. Two different components with their own context. If you’re using views, they’d be tied to a controller.

If you want to know if a view or component that handles clicks AND has been previously clicked on, create a new property ‘hasBeenClicked’, and either make it computed property or observe it.

You may want to look more into preventing bubbling though. That way, you don’t even have to worry about handling actions on the views you don’t want pas their own context.

@ulisesrmzroche,

Thanks for the reply … I’m not sure how to implement concretely your suggestion, though. How does the editor’s “focusOut” get triggered? That is the rub. keypress esc->cancel and tab->submit are easy, but I want to avoid submit if focus out event occurs because of click on some other clickable UI component, but trigger it if click was on something else. Global level seems only place to handle this as clickable components don’t bubble up their events so this would be the place to detect clicks on “nonclickable” things. The only other way I could think was to inject code into ember itself to incept that “some click was handled” – then I could act on all other focusout events – however that avoids coupling between components only at cost of messy intrusion into ember itself.

At application level I was thinking of sending a custom event “unhandledClickEvent” but I couldn’t figure out how to register my component for it – and in any case both event or the property are global, so it doesn’t seem to be any better, and I couldn’t think of how to register my editor for this event (I guess I could include a css class and send via jquery?)

A side question: how to create actual event handlers on components (as action doesn’t get actual event)? They extend views, but “keyPress” member of a component doesn’t get called on keypress. (An event manager does, but that seems messier and odd that one works and the other doesn’t – is it a bug?)

Yeah, I see what you mean now. Maybe components are not the best way to go since your use case does have so many dependencies.

Side Question: i think you have call sendAction from your component. You declare these on your actions hash.