-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add first class support for Backbone.Radio in Mn.Object #2431
Add first class support for Backbone.Radio in Mn.Object #2431
Conversation
@@ -37,5 +37,62 @@ _.extend(Marionette.Object.prototype, Backbone.Events, { | |||
bindEntityEvents: Marionette.proxyBindEntityEvents, | |||
|
|||
// Proxy `unbindEntityEvents` to enable unbinding view's events from another entity. | |||
unbindEntityEvents: Marionette.proxyUnbindEntityEvents | |||
unbindEntityEvents: Marionette.proxyUnbindEntityEvents, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't want to add too much more work for you, but I think this deserves it's own file. Maybe src/radioHelpers.js
src/radioHelpers.js
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can get on board with that. It certainly is doubling the size of Mn.Object right now. So you're suggesting just leaving the _.proxyRadioHandlers call in the constructor, and then adding a separate extend call in a different file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nah, I'm suggesting adding two functions: Marionette.bindRadioHandlers(context) and Marionette.unbindRadioHandlers(context). I think we could use these two functions in the Object class, but atleast we don't clutter Object source w/ tons of radio knowledge. And, other external classes get this logic for free in 3.0
So I think maybe we need to take a step back on this for a sec and look at either Radio additions or Marionette/Radio helpers that need to be introduced prior to this work. One concern in this PR is that we're using But so we should really be switching to Plus any inline Second, I think it would be better to suggest a primary channel for an object, giving the user the freedom to channelName: 'someChannel',
radioEvents: {
'some:event', 'someHandler',
'otherChannel other:event', 'someOtherHandler'
} etc. |
Ah I jumped the gun a bit.. Radio is working on TL;DR for my last post. Get this Radio API in first, and utilize it for Object. |
haha - @paulfalgout. This stuff is confusing, no? I definitely like the idea of RadioHelpers and radio helper tests, which will expose the api we offer. Lets try and get the smallest thing in which in my mind is |
I don't know how you accomplish |
_unproxyRadioEvents: function() { | ||
_.each(this._radioChannels, function(channel) { | ||
_.each(this._radioTypes,function(commands) { | ||
Backbone.Radio[commands.stopMethod](channel,this); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Passing in this
as the second argument will prevent unbinding I believe. The second argument needs to be the callback and then the context. Obviously, listenTo/stopListening
and the forthcoming command/reply counterparts would be preferred here. Otherwise, we'll need to track the callbacks we add, which is really just reimplementing listenTo
-type behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep. I think I actually need to add more arguments here, Backbone events isn't smart enough to figure out that this is supposed to be the context if you only pass one argument. So this is broken.
But thats the general idea of what I'm trying to achieve. A small fix will prevent over-unsubscribing on everything but manually subscribed methods on the same object. Like @jfairbank said, if we want to be airtight we will need to keep track of the callbacks or get the updated radio functions. It's hardly a disaster as is though, especially since the _unproxyRadioEvents stuff should only be run in the constructor and on destroy anyway. It wouldn't interfere with existing radio usage unless somebody called it manually.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
marionettejs/backbone.radio#162 There's also a confusing issue with radio around clean-up not being as selective as it should.
@jmeas you anywhere where you could weigh in?
on and off accept a context argument that only deletes events and commands in the context of that object. See: http://codepen.io/ben336/pen/zxyPQj I'm currently not doing this right in the code. The whole unregistering stuff got written too quickly and is screwed up. I'll clean it up and resubmit soon. But basically you can have pretty fine-grained control of what you're unsubscribing from. I was trying (a little too carelessly sadly) to deregister only events in context of the current object. That would possibly remove any manual listeners on that object, but wouldn't interfere with anything else. |
So, thanks for the feedback everyone. I'm going to take some of that back and try to improve the PR. Specifically:
I'll aim for that over the weekend and hopefully this can continue to get pushed forward. |
👏 thanks a ton for taking this on! I'm pretty excited to start using it actually. It will clean up a lot of boilerplate for my various services. |
ac723c0
to
dd4bec8
Compare
Ok I worked in the feedback from @jasonLaster @jfairbank and @paulfalgout. The radio code is now in its own file. The unsubscribe stuff has been cleaned up so that it works correctly and happens in the destroy function. And there are tests to verify that and also make sure it doesn't "over unsubscribe". The only cases I can see where this might interfere with existing code:
The first one could be mitigated by doing more manual tracking of which callbacks are being attached. I don't think thats worth it. The second could be mitigated by creating a central object => channel tracking object rather than sticking that directly on the object. I'm indifferent here, I can see advantages either way. Other than that, the only big issue I'm aware of with this code is that it currently makes Radio a hard dependency for Mnv3. If that is not something the core team wants to do, I'll probably have to put some thought into the best way to make this an optional behavior depending on Radio availability, similar to Backbone.View.$. (oh, and obviously this needs documentation work. Waiting on some agreement that this is a good approach before adding that) |
this.clickStub3 = this.sinon.stub(); | ||
this.Object = Marionette.Object.extend({ | ||
radioEvents: { | ||
'foo bar' : this.clickStub1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is weird because you run into the object2
problem w/ prototypes.
The easier thing is to add the stub to the object directly.
O = extend({
radioEvents: {'foo bar': 'barHandler'}
barHandler: function() {}
});
o = new O();
o.barHandler = this.barHandler;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, I can switch that up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jasonLaster So after looking at this again, I don't see the problem here. I pass 2 functions directly and one by reference, to make sure that we handle both of those cases. Yes object2 shares the stub on the prototype, but I think the testing is still pretty unambiguous. I just wrote it out the other way, and it makes the code a lot more verbose and (in my mind) less clear. So I'm going to leave it unless you strongly object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm cool with this
Really excited about this @benmccormick!
💯 🌴 |
@benmccormick this is looking great! This is gonna be such a nice feature for v3! |
- Radio added as a dependency - Mn.Object now supports radioEvents, radioCommands, and radioRequests hashes in the form `{'channel message':'handler'}` - Tests added for this feature - Initial Documentation Note that this is only adding support to Mn.Object and the Classes that inherit from it, not trying to add the same support to Backbone.View
dd4bec8
to
a5afa20
Compare
@jasonLaster Addressed the comments other than the testing one, which I replied to. Added a first pass at docs. Do we want to try to include this in Views as well? Or just Object? Behaviors and Application get it by default now, though I'm not sure commands or requests make any sense at all on Behaviors, since they have to be unique. But if they're going to get included there, probably makes sense to include them on Views as well. |
Also, I threw together a quick library for anyone who wants to use this feature with Mn 2.1.x. |
@benmccormick docs looking good. Maybe provide a link to the radio docs to help users who are new |
👍 (one to go) @benmccormick Lets create a separate PR for adding Radio to Views. It should be easy / un-controversial, but still nice to break up the discussions. This looks great. Huge Huge. 3.0 contribution. |
👍 let's add the link to radio docs when we add to views |
Add first class support for Backbone.Radio in Mn.Object
📻 🔘 💭 Yesss! |
👍 Thanks for the feedback everyone. I'll toss up a separate PR for the Views/ more documentation sometime later this week. Is there anywhere else in this repo where I should document that Radio will now be a dependency (instead of wreqr?) Or is that more of a www thing? |
That's a good question. Man it'd be great to pull in radio docs. |
This is a very initial PR to try and handle #2324. It needs more tests, any documentation at all, and the code could probably be cleaned up considerably. But I wanted to keep that issue moving and give everybody a concrete proposal to discuss.
This PR adds support to Mn.Object and its subclasses for the following API:
The biggest change that it would involve is making Backbone.Radio a dependency of Marionette. In this PR, I've made it a hard dependency and something that the UMD modules try to pull in automatically. I could also see this being written in a way though that only activated the feature if Radio was present on the Backbone object.