-
Notifications
You must be signed in to change notification settings - Fork 396
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
Allow components to fire events on their ancestors? #1099
Conversation
…tion that is used for references
I haven't verified yet, but this also retains the original event and context, whereas I don't think manually chaining does. |
@evs-chris biggest issue I have with this is that it removes the normal dependency inversion that you get with pub-sub. Event publishers are explicitly coupled with the subscriber. |
I don't really have a problem with the explicit coupling in this case because I don't view the sub-components as independent pieces. I suppose it could be used in other cases that would be confusing though. In #782, you suggested that namespaced events would address some component finding issues. That would also address this issue and be a more generally useful construct, I think. I don't think I would namespace by component though, as that could cause name conflicts. So how about if an event name is namespaced (one or more . in the name), then have fire walk up the component hierarchy to the first handler that is found for the event. That way, the publisher is decoupled from the subscriber, there aren't any intermediate proxys required, the original context isn't lost, and the use-case in #782 should be addressable by having the component fire events with a supplied namespace or a default. var cmp = Ractive.extend({
template: 'complex html with a <button on-click="someAction">that fires</button> some internal logic that fires a relevent event upward and a <button on-click="{{eventNamespace}}.bippy">that is set to to fire from the template</button>',
init: function() {
this.on('someAction', function() {
if (relevant) this.fire((this.get('eventNamespace') || 'defaultNamespace') + '.bar');
}
}
});
Ractive.components.cmp = cmp;
var ractive = new Ractive({
template: 'some html with <containerComponent><cmp eventNamespace="foo" /></containerComponent>'
});
ractive.on('foo.bar', function() { console.log('foo has barred'); });
ractive.on('foo.bippy', function() { console.log('foo has bippied'); }); The only caveat to this approach that I have found thus far is that changing eventNamespace after the component is rendered does not change the event name that is fired. What do you think? |
How so? I like the idea of being able to specify a namespace, but I was thinking the default would just be the name, because externally that's how the parent view already "knows" the component: Ractive.components.widget = Widget
new Ractive({
...
init: function(){
this.on('widget.selected', function(){..})
}
}) Adding {{#items:i}}<widget eventNamespace='{{"widget"+i}}'/>{{/}} and thus only listen to events on say the first item. I like being able to set it on the template, though should it be possible to set as an option during And just to be clear, my thought was that the namespace would not be additive and would be consistent as the event bubbled, as opposed to changing with each layer as it bubbled. (i.e. no As to context, I agree the original context should be preserved. I was wondering if there should be a this.on('widget.selected', function(e){
e.context // event context from originating element
e.contextStack.widget // context of widget as seen from its parent
e.contextStack.widget1 // context of widget1 as seen from its parent
e.contextStack.widget2 // context of widget2 as seen from its parent
}) Sometimes you want the component context and you don't care about the specifics of the event implementation context. Maybe this is overkill, or better solved by improving component events.
Not entirely sure what you meant here. Are you looking for a cancel bubble type funtionality? |
I was looking at this as entirely opt-in where namespaces are never automatically specified. Either the component-maker has arranged for namespaced events and has a way to modify them i.e. with a data element or That last part is where I've had some trouble. Having nested child components that blink in and out of existence with state changes can make using Also, if namespaces were automatically assigned, how would parents proxy them in the template? I don't think
I wouldn't really consider additive or automatically nesting namespaces to be worth their complexity and overhead. At least, not for my use-cases. The same goes for bubbling beyond the first layer that can handle the event. I would make further bubbling opt-in only as well if at all, perhaps with an additional sigil like As far as tracking context stacks, the code I have already written is only concerned with the source component and the component with the handler (parent and child, the same as the code attached to this request). I haven't delved deeply enough into ractive to figure out how to build a context stack, but I am only interested in the components on either end of the event at this point.
No, that was a poor example meant to indicate a number of simple components that work together inside a conglomerate parent, which fires events upward when an appropriate state has been reached. |
As long as it will still work and doesnt break to create a "Tab UI"-component. Discussed a little #879 (comment) |
That's actually my primary use-case at this point. I have a form builder that can spit out nested tab boxes and binding events deeper into the component hierarchy is tedious. |
On further examination, my version of namespaced events is untenable since they can't be addressed in templates and there isn't a simple way to supply a namespace outside of direct use within a template. I think bubbling #1116 would be a better solution. |
This is more of a proposal for discussion than a pull request.
When deeply nesting components, it is possible to manually bubble events up the component stack by having a boilerplate event handler that fires an event. There is already a notation for referencing up-hierarchy for references, so does it make sense to do the same for events?
This is mostly useful for components that act as containers, and as such, have a content partial as part of their template.
Given the following component
this would allow you to turn
into the slightly more friendly
Granted, this short example doesn't show off the benefit very well, but when you get three or four levels deep with multiple events, it really starts to clear some fog. I suppose it may improve performance slightly as well since it skips intermediate events, but that wasn't really an avenue I was trying to explore.