I just tried the new Marionette 1.0.0-beta with my existing project. After fiddling around with it for many hours, I must say the altered event handling confuses me.
Events seem to fire doubled. May be an artifact of the new triggerMethod() call?
Event bubbling in CollectionViews doesn't seem to work for standard events like 'item:rendered'. Those fire inside the ItemViews, but not the parent CollectionView. Is this intended?
What are the different event handling methods are meant to be used for? EventAggregator, EventBinder, Wreqr, native Backbone Events, …?
Would be great, if you could clear things up. It would also be great, if you could mark the existing documentation as being appropriate for what versions of Marionette.
Regarding the event bubbling in CollectionViews, there is a pull request to fix this as it is a bug
Related
What are the advantages and disadvantages of the following 2 lines of code? I don't understand why there are 2 different ways to do the same thing.
this.listenTo(app.Todos, 'change:completed', this.filterOne);
app.Todos.on('change:completed', this.filterOne);
Also when using .on, how do I determine is the default context?
listenTo is the newer and better option because these listeners will be automatically removed for you during stopListening which is called when a view gets removed (via remove()). Prior to listenTo there was a really insidious problem with phantom views hanging around forever (leaking memory and causing misbehavior) because view methods were referenced as event listeners on models even though the view instances themselves were long gone and no longer in the DOM.
If you want to read the back story for listenTo, search the backbone github repository for listenTo and read through some of the longer issue discussions.
As to the default context, several things can end up bound to this:
if you do the binding via this.listenTo, it will always be the view instance (pointed out by Wim Leers in the comments)
without this.listenTo, the story gets complicated
For misc events, it will be the global object (best to avoid this)
for DOM events, it will be the source element just like in regular DOM event binding
If you provide an explicit context (the 3rd argument to foo.on), backbone will use that (thus this is a more robust approach)
If you use the ECMA standard function () {//your event handler}.bind(this), you can also manually control the context (also recommended)
As #mu pointed out, _.bind or $.proxy are available alternatives to ECMA function.bind
For backbone views, doing this.bindAll('onClick', ...) will ensure the view instance is the this context when any view methods are used as event handlers
any events wired up by using the view's standard events property will get bound for you automatically to the view instance by backbone (this is belt & suspenders with bindAll)
So to summarize into some guidelines:
use the events property whenever possible as it is concise and correct
use this.listenTo for all bindings to models and collections
any additional bindings remember to bind the context reliably using your preferred method. I usually use ECMA Function.bind because hey, standards, but there are several good options here.
With listenTo, the object whose events you want to listen to is passed as the first argument. In the case of on, it is actually a method on that object.
The advantages of listenTo over on are:
The listener keeps track of all the event handlers, making it easier to remove them all at once when needed.
The callback’s context is always set to the listener itself.
I'm building a project using the Backbone global as an event bus. The idea is that a view will trigger a custom event and pass in some data, then whatever collection is listening for that event will use the data to create a model and add that model to itself, and give some kind of message.
I notice that if I start from a new instance of my application and trigger one of these events, then in Chrome Dev Tools, Backbone._events looks something like this: {'add_person': [Object] } and the appropriate event handler runs and processes that one object in the value array. So far, so good.
Now, let's say I trigger that event handler again. What I've noticed is that Backbone._events looks like {'add_person': [Object, Object]} and the event handler runs twice, presumably on both members of the value array, including the first which was already processed.
My question is how do I prevent this behavior, short of binding the event with once and re-binding it after each time it's called? Thanks.
I'm not entirely sure what your setup is, i.e. how you're triggering and listening to these events you're firing but it sounds like you might be doing something like:
GlobalEventBus.on('add_person', this.addPerson, this);
Assuming you're binding to the event using on this could well be your problem if you're not manually unbinding the listener when your view is destroyed.
You're better off using Backbone's listenTo when listening to events that are triggered from an object outside the object you're listening in.
So, for example, in your collection you'd instead have:
this.listenTo(GlobalEventBus, 'add_person', this.addPerson)
Again though, i'm not entirely sure what your setup is.
See this codepen for a working example.
Only one events is triggered each time but keep in mind that only one model is being added because each model is a duplicate and has the same id. Assuming each model was unique it would be added to the collection.
Some further info on listenTo
Basically we have a huge project, and we have an event handler that sometimes is triggered and some others it isn't. I think this is because somewhere in the jungle of code, we're handling that event, so it doesn't bubble up to where we need it. Is there anyway to find out where is it being handled?
Thanks!
Did you try to use Snoop..... there is an event Tab that tells us where the event is bubbled to and where its handled...
I have implemented a UserControl. Then I would like to handle an event that is originally handled by Window (keyboard press). What is the best way to route the event caught by another component (higher in the components' tree)?
Thanks in advance for the replies and hints!
Cheers
It depends on the event you're trying to access. If it's a Preview event and the Window is setting e.Handled to true you'll need to use the method Alex suggests to circumvent the Window's handling of the tunneling. If it is a bubbling event (i.e. KeyDown) you don't need to do anything special since bubbling events hit the handlers on child elements first and go up the visual tree so the Window handler won't occur until after your UC's.
One thing you need to be careful with using Key events is that the event is only going to get picked up by your UC in the first place if the Focus is on or inside of it. This isn't something you need to worry about with things like Mouse events since they start at a specific location in the tree.
I believe you cannot gurantee that.
Window class is wrapping Win32 message-based event model and this will be the only WPF entity which will have access to those information.
I suggest that you create an attached property (which will be used by the Window) and implement the routing of the events yourself so that controls could subscribe to.
You can attach the routed handler specifying that you want to handle handled messages as well:
this.AddHandler(routedEvent, handler, true);
where this is an UIElement or derived class.
However there may still be events (key presses in this case) which don't make it past the window, not sure.
A colleague and I were chatting about routed events, and we came up with some things that didn't make a lot of sense. Primarily, what is the purpose of a Direct event, and why are both LeftMouseButtonDown and PreviewLeftMouseButtonDown direct events as opposed to bubbling and tunneling respectively?
According to the documentation, the LeftMouseButtonDown (and preview) events appear to behave as bubbling and tunneling events, except that the event is raised and reraised as these events traverse the tree. Since direct events can only be handled by the source of the event, it follows that any UIElement could handle a direct event since each one is raising the event and is also therefore the source. (Unless reraising the event is different than raising?). Why are these then not tunneling and bubbling like so many other similar events?
Neither my colleague nor I could come up with a use case in which we would ever create a custom event using a direct strategy (although we came up with some for tunneling and bubbling), yet LeftMouseButtonDown, one of the most common events (if not THE most common) is using this strategy.
Anyone have any ideas about the rational behind this?
Thanks!
My guess would be performance and there are considerations for having multiple events for the same thing.
There is already an event for MouseDown, to route both that and LeftMouseDown wouldn't make much sense. Finally, which would fire first and would cancelling\handling the first prevent the other? It sounds like it would be too easy to handle the same event twice.