First of all, thanks for all the great work so far. vuejs is by a great measure the most enjoyable frontend framework I've tried so far.
As for some of the changes that are scheduled for v2, I'd like to know if a replacement with a plugin is possible.
One thing i liked about events is the events
scope where all listeners are gathered. With your suggestion for vue2 with a global event-bus, I don't see how I can replace following code:
my comp = {
events: {
'overlay:close': function() {
/* handle event */
}
}
}
I don't miss the actual hierarchy of $broadcast and $dispatch within the component tree, but I'd really love to keep a global event bus that works together with the events
object. If this is possible through a plugin, that would fit my needs. Maybe it could be possible to make $emit
emit globally with an additional attribute?
Did you see this? https://github.com/vuejs/vue/wiki/2.0-features#how-to-deal-with-deprecation-of-dispatch-and-broadcast
Yep, I've seen this. My concern is, how to implement the global event bus with events registered in the event object. I'm looking for a way to automate:
{
ready: {
bus.$on('id:selected', this['idSelected']);
},
methods: {
'idSelected': function() {
// ...
}
}
}
into:
{
events: {
'id-selected': function() {
// ...
}
}
}
I know that this seems merely a convenience, but vue is all about convenience, simplicity and ease of use.
@Nirazul something like the following in one of the lifecycle hooks may work
for (var evt_id in this.options.events)
bus.$on(evt_id, this.options.events[evt_id])
I haven麓t looked close enough to the new API but you may be able to use it as a mixin
// ...
var auto_events = {
created: function () {
for (var evt_id in this.options.events)
bus.$on(evt_id, this.options.events[evt_id])},
destroyed: function () {
for (var evt_id in this.options.events)
bus.$off(evt_id)}
}
// ...
new Vue({
// ...
mixin: [auto_events],
events: {
'id-selected': function () {
// ...
}
}
// ...
})
@indus
This sounds like a plan. I'll try it out when the first alpha of vue 2 is released 馃憤
This all sounds :+1: for application components where I control the bus that _my_ components use. My concern here is 3rd party components. How do I listen to events emitted by an arbitrary component?
2.0 recommends using Vuex to inject the bus into components where you need to use events, but this seems like overkill for small projects. I liked that Vue didn't require using Vuex or Router or even Http unless it was needed. Also as @rpkilby states, there is no longer a universal system for 3rd party components, which will hurt the community as a whole. Thinking of how important they are in jQuery, I think Vue needs an equivalent.
@rpkilby 3rd party components still have the ability to directly $emit
on themselves, they just no longer have the ability to dispatch events that propagates. This essentially ensures that a 3rd party component can only cause side effects in its direct parent, which I believe is a good thing. An isolated component being able to dispatch a event that causes side effects in its unknown parent tree sounds like a recipe for trouble to me.
An isolated component being able to dispatch a event that causes side effects in its unknown parent tree sounds like a recipe for trouble to me.
@yyx990803, totally agree. My concern is how the direct parent of the 3rd party component will be able to listen for those event. I would not want select2 to fire events on a global bus. I would (most likely*) want only the parent to get those events. How do events $emit
ted on yourself communicate with the parent component? I thought $emit
was isolated to the component.
*There may be cases where I'd want the event to propagate beyond the direct parent. Either way, that's an application detail that the parent component would determine.
@rpkilby I guess using v-ref
on the component and then listening with this.$refs.component.$on('foo',(data) => {})
. If the $emit
ted event had the relevant data sent along with it, or the affected data was .sync
'd to the parent, you could handle it accordingly. With .bind()
or with an =>
function you would be executing the result in the parent scope.
@rpkilby with v-on
:
<child @some-event="handleIt"></child>
@yyx990803 Is this correct?
var Child = {
methods: {
method: function() {
var arg = ""
this.$emit('some-event', arg)
}
}
}
with v-on
Holy crap I had no idea that you could do this the entire time. Where is the :facepalm: emoji.
@rpkilby subscribe to vuejs/vuejs.org repo commits :wink:
From my viewpoint of standalone component developer I would need something like
v-on
working on slot
) and slot
)to fully replace the communication of two nested, depending components. #2648 was dismissed mainly because of $dispatch
and $broadcast
- please reconsider.
Use-cases:
vue-card
vue-collapsible
vue-comps-scrollspy
@kaorun343 that is correct.
@paulpflug the communication between slot components and its host can be implemented by calling $parent.$emit('xxx')
from the slot components and listening for that event on the parent. This is tight coupling, but since you are designing tightly coupled components that are meant to be used together, I think it's the most straightforward solution.
Also, in 2.0, complex slot distribution is best handled by using a programmatic render
function, which should simplify things a lot.
I'm closing this because I think most questions have been answered, and it seems there are no strong arguments against the deprecation of $dispatch
and $broadcast
.
I think removing $dispatch was a terrible idea. This wasn't the first ui framework/library to implement the notion of bubbling actions/events up a visual tree. It's a well established idea. Why take away this functionality on the premise that " being able to dispatch a event that causes side effects in its unknown parent tree sounds like a recipe for trouble to me"? You need to leave this responsibility to the users. I'm sure most have the common sense to use this feature appropriately. It is not a new concept!
I really can't see the benefit of this change when this library is built upon long time established web technologies/concepts such as the DOM and DOM events that do in fact bubble up the visual tree and have been doing so for years with no one complaining. Isn't the idea of components something that has been recently embraced thanks to the W3C proposal for web components? In my opinion, It only makes sense that Vue components behave similarly to regular DOM elements in regards to how event handling is done.
The proposed alternative to use a global event bus seems illogical to me when something more practical, effective, and easier to understand (due to it being a well established concept for years) already existed.
Other proposals in this thread remind me of how EmberJS wants to do it. Passing closure actions as properties to the components down each level of the hierarchy. So tedious and unnecessary! Vuejs was the reason i wrote https://www.npmjs.com/package/ember-component-action-bubbling!
Aside from this, I really like your library. But seriously, I think this was a terrible change.
Feels like I'm back in Backbone. :)
I think this change is a bit painful, but for simple apps that don't use Vuex managing on and off of events is not that difficult. If you are doing it a lot... then its possible your app benefits from Vuex anyways.
We did a huge project at work that relied on Marionette, I can attest from that that having a lot of views listening to and emitting events is not great. Making the event listening pattern less "magic" and more explicit is fine IMHO.
I have implemented a pretty simple global event bus for vue. I was developing a vue ui kit for fun and wanted to be able to open any modals from anywhere.
https://github.com/vouill/vue-geb
when using var bus = new Vue();
for replacement of $broadcast
and $dispatch
there's a problem:
the child components will still process $on
event after it already been destroyed !
@toby1991
https://vuejs.org/v2/guide/migration.html#dispatch-and-broadcast-replaced
js // It's good to clean up event listeners before // a component is destroyed. beforeDestroy: function () { eventHub.$off('add-todo', this.addTodo) eventHub.$off('delete-todo', this.deleteTodo) },
@fnlctrl Thks. But I've tried the $off
method with add-todo
, it will discard all the events in the channel add-todo
.
Finally, I've found my way to solve this:
Simply make a determination of the this._isDestroyed
in all situations of $on
method, that would solve my problem.
I think what caused this is the method $destroy
,
In vuejs 1.x, the $destroy
method has a parameter which will remove the DOM completely.
In vuejs 2.x, the $destroy
method remove the parameter. And in the official document, it suggest we shouldn't destroy the component by this method, and suggest us to use v-if
or v-for
. OR we could use this method and remove the DOM ourselves.
BUT! the $destory
method cannot destroy the mixins
, so, in order to avoid the component which has been destroyed processing the $emit
from the bus, we should do this.
Simply make a determination of the
this._isDestroyed
in all situations of$on
method, that would solve my problem.
@yyx990803
@toby1991
Sorry but you're completely off the point. $destory has nothing to do with this. The event hub is a global instance which has nothing to do with the lifecycle of components that use it.
Thks. But I've tried the $off method with add-todo, it will discard all the events in the channel add-todo .
No, that's not the case. You simply forgot to pass the second parameter. Please refer to the docs: https://vuejs.org/v2/api/#vm-off
I'm locking this issue since it's obsolete. For future references, please refer to the docs. For support questions and discussions, please use gitter or forum.
Most helpful comment
@Nirazul something like the following in one of the lifecycle hooks may work
I haven麓t looked close enough to the new API but you may be able to use it as a mixin