Custom events do not bubble up #2296

Open
SekibOmazic opened this Issue Jun 2, 2015 · 64 comments

Comments

@SekibOmazic
Contributor

SekibOmazic commented Jun 2, 2015

Couldn't get custom event (ping) bubble up to the root component. DOM event (click) works just fine:
http://plnkr.co/edit/g6RNv5qMreVFKYcwvtOs?p=preview

Using alpha.25

@gdi2290

This comment has been minimized.

Show comment
Hide comment
@gdi2290

gdi2290 Jun 2, 2015

Member

^ should be working for the custom event <grand-child (^ping)="onPing($event)" ></grand-child> :/

github-tipe-logo

Member

gdi2290 commented Jun 2, 2015

^ should be working for the custom event <grand-child (^ping)="onPing($event)" ></grand-child> :/

github-tipe-logo

@SekibOmazic

This comment has been minimized.

Show comment
Hide comment
@SekibOmazic

SekibOmazic Jun 2, 2015

Contributor

@gdi2290 By design? If so, should I close the issue? And is there a workaround?

Contributor

SekibOmazic commented Jun 2, 2015

@gdi2290 By design? If so, should I close the issue? And is there a workaround?

@gdi2290

This comment has been minimized.

Show comment
Hide comment
@gdi2290

gdi2290 Jun 2, 2015

Member

@SekibOmazic oh no sorry, this seems like a bug since it should be working

github-tipe-logo

Member

gdi2290 commented Jun 2, 2015

@SekibOmazic oh no sorry, this seems like a bug since it should be working

github-tipe-logo

@vicb

This comment has been minimized.

Show comment
Hide comment
@vicb

vicb Jun 2, 2015

Member

Dup of #1254 ?

Member

vicb commented Jun 2, 2015

Dup of #1254 ?

@gdi2290

This comment has been minimized.

Show comment
Hide comment
@gdi2290

gdi2290 Jun 2, 2015

Member

ah okay, if it's by design then it means you should create your own ping event to be sent up rather than delegate to a component's event. That makes sense since it's better decoupling but also confusing since it's not enforced with native events like ^click

github-tipe-logo

Member

gdi2290 commented Jun 2, 2015

ah okay, if it's by design then it means you should create your own ping event to be sent up rather than delegate to a component's event. That makes sense since it's better decoupling but also confusing since it's not enforced with native events like ^click

github-tipe-logo

@SekibOmazic

This comment has been minimized.

Show comment
Hide comment
@SekibOmazic

SekibOmazic Jun 2, 2015

Contributor

@gdi2290 That seems very verbose. So every component in the chain would need to re-send event?
Like:
-parent (listen to ping)
-- child (listen to ping and resend the ping - even if not interested in)
---- grand child (emit ping event)

Contributor

SekibOmazic commented Jun 2, 2015

@gdi2290 That seems very verbose. So every component in the chain would need to re-send event?
Like:
-parent (listen to ping)
-- child (listen to ping and resend the ping - even if not interested in)
---- grand child (emit ping event)

@gdi2290

This comment has been minimized.

Show comment
Hide comment
@gdi2290

gdi2290 Jun 2, 2015

Member

@SekibOmazic I updated the example so it works. It's verbose I agree but it does make each component more loosely coupled but it forces it rather than allowing the developer to take advantage of ^

http://plnkr.co/edit/MYYuNm?p=preview

github-tipe-logo

Member

gdi2290 commented Jun 2, 2015

@SekibOmazic I updated the example so it works. It's verbose I agree but it does make each component more loosely coupled but it forces it rather than allowing the developer to take advantage of ^

http://plnkr.co/edit/MYYuNm?p=preview

github-tipe-logo

@SekibOmazic

This comment has been minimized.

Show comment
Hide comment
@SekibOmazic

SekibOmazic Jun 2, 2015

Contributor

@gdi2290 OK thanks. This may by so by design but now we have 2 different behaviours:

  • for native DOM events bubbling up works to the root element
  • for custom events bubbling up works to parent only and an event has to be resent if you need it in ancestor

Not very intuitive IMHO.

Contributor

SekibOmazic commented Jun 2, 2015

@gdi2290 OK thanks. This may by so by design but now we have 2 different behaviours:

  • for native DOM events bubbling up works to the root element
  • for custom events bubbling up works to parent only and an event has to be resent if you need it in ancestor

Not very intuitive IMHO.

@2fdevs

This comment has been minimized.

Show comment
Hide comment
@2fdevs

2fdevs Jun 16, 2015

+1 this needs to be reviewed I think.

@SekibOmazic as a workaround we're using CustomEvent(): https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events

Maybe a parameter (bubbles=true) when emitting the event could do the trick:

class TodoCmp {
  complete = new EventEmitter();

  onCompletedButton() {
    this.complete.next({bubbles: true});
  }
}

2fdevs commented Jun 16, 2015

+1 this needs to be reviewed I think.

@SekibOmazic as a workaround we're using CustomEvent(): https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events

Maybe a parameter (bubbles=true) when emitting the event could do the trick:

class TodoCmp {
  complete = new EventEmitter();

  onCompletedButton() {
    this.complete.next({bubbles: true});
  }
}
@ericmdantas

This comment has been minimized.

Show comment
Hide comment
@ericmdantas

ericmdantas Jul 27, 2015

Contributor

It'd be definetely nice to have the ^ to work with custom events as well.

Contributor

ericmdantas commented Jul 27, 2015

It'd be definetely nice to have the ^ to work with custom events as well.

@mhevery

This comment has been minimized.

Show comment
Hide comment
@mhevery

mhevery Aug 24, 2015

Member

@SekibOmazic Can you add justification/use-case as to why do you need this for custom events? Bubbling only makes sense for input (key/mouse) events.

Member

mhevery commented Aug 24, 2015

@SekibOmazic Can you add justification/use-case as to why do you need this for custom events? Bubbling only makes sense for input (key/mouse) events.

@jpsfs

This comment has been minimized.

Show comment
Hide comment
@jpsfs

jpsfs Aug 24, 2015

Hi @mhevery, I don't know @SekibOmazic's use case but I have the following scenario:

Imagine you have a component that will trigger a service call thus requering some kind of loading animation.

Depending on the component's location (parent) we want to have different behaviours for the loading animation.

If we could propagate custom events we could easily implement this.

Of course there are other ways of doing this, and with time many other (better) examples will surge for sure if this is supported.

I hope you consider this functionality.

Best regards,

jpsfs commented Aug 24, 2015

Hi @mhevery, I don't know @SekibOmazic's use case but I have the following scenario:

Imagine you have a component that will trigger a service call thus requering some kind of loading animation.

Depending on the component's location (parent) we want to have different behaviours for the loading animation.

If we could propagate custom events we could easily implement this.

Of course there are other ways of doing this, and with time many other (better) examples will surge for sure if this is supported.

I hope you consider this functionality.

Best regards,

@SekibOmazic

This comment has been minimized.

Show comment
Hide comment
@SekibOmazic

SekibOmazic Aug 27, 2015

Contributor

@mhevery No special use case to be honest. I just expect the custom event to bubbled as well. It's not intuitive the first time you deal with it, but later on it's not a problem.

So another nice to have I guess.

Contributor

SekibOmazic commented Aug 27, 2015

@mhevery No special use case to be honest. I just expect the custom event to bubbled as well. It's not intuitive the first time you deal with it, but later on it's not a problem.

So another nice to have I guess.

@bduffany

This comment has been minimized.

Show comment
Hide comment
@bduffany

bduffany Sep 6, 2015

@mhevery also consider the following use case (which I have actually run into multiple times while working in Angular2): say I have written a component which fires a bunch of custom events. Now, another developer likes my component, and wants to "extend" my component by wrapping it with a lightweight component and adding a few custom behaviors. But now the issue is that the lightweight component has to manually export all of the events from the inner component by creating an event emitter for each one and wiring up the event emitter to each event of the sub-component.

bduffany commented Sep 6, 2015

@mhevery also consider the following use case (which I have actually run into multiple times while working in Angular2): say I have written a component which fires a bunch of custom events. Now, another developer likes my component, and wants to "extend" my component by wrapping it with a lightweight component and adding a few custom behaviors. But now the issue is that the lightweight component has to manually export all of the events from the inner component by creating an event emitter for each one and wiring up the event emitter to each event of the sub-component.

@bduffany

This comment has been minimized.

Show comment
Hide comment
@bduffany

bduffany Sep 6, 2015

@2fdevs I think with the extra bubbles argument, that would result in namespace clashes, e.g. if two sub-components want to bubble an event and it has the same name, and you try to catch the event in the parent component, you could get two events with a different type.

It's bad enough currently that native events like (click) are already reserved names for events and that it's not obvious what happens if you accidentally use one of those names for a custom event. I think there should be a separate syntax entirely for custom events, but I digress.

bduffany commented Sep 6, 2015

@2fdevs I think with the extra bubbles argument, that would result in namespace clashes, e.g. if two sub-components want to bubble an event and it has the same name, and you try to catch the event in the parent component, you could get two events with a different type.

It's bad enough currently that native events like (click) are already reserved names for events and that it's not obvious what happens if you accidentally use one of those names for a custom event. I think there should be a separate syntax entirely for custom events, but I digress.

@2fdevs

This comment has been minimized.

Show comment
Hide comment
@2fdevs

2fdevs Sep 6, 2015

@SekibOmazic @mhevery I must say that after using a lot Angular 2 I still didn't needed so maybe it's not necessary I think.

@bduffany on a first moment I used native events but after understanding better how Angular 2 works finally I changed a few things and I think that I don't need this feature anymore.

2fdevs commented Sep 6, 2015

@SekibOmazic @mhevery I must say that after using a lot Angular 2 I still didn't needed so maybe it's not necessary I think.

@bduffany on a first moment I used native events but after understanding better how Angular 2 works finally I changed a few things and I think that I don't need this feature anymore.

@ericmdantas

This comment has been minimized.

Show comment
Hide comment
@ericmdantas

ericmdantas Sep 11, 2015

Contributor

Apparently it's still not working with .37.

See this plnkr.

Contributor

ericmdantas commented Sep 11, 2015

Apparently it's still not working with .37.

See this plnkr.

@mhevery

This comment has been minimized.

Show comment
Hide comment
@mhevery

mhevery Sep 12, 2015

Member

Component/Directive events do not bubble up, and as of right now I don't see a strong enough use case for them.

Could someone provide one?

PS: #2296 (comment) can better be solved by injecting services rather then using events.

Member

mhevery commented Sep 12, 2015

Component/Directive events do not bubble up, and as of right now I don't see a strong enough use case for them.

Could someone provide one?

PS: #2296 (comment) can better be solved by injecting services rather then using events.

@ericmdantas

This comment has been minimized.

Show comment
Hide comment
@ericmdantas

ericmdantas Sep 12, 2015

Contributor

@mhevery my opinion is pretty much the same of @SekibOmazic (thinking it'd bubble like any other event), but I do agree with @bduffany (reusable components that could hook to some of these custom events).

But again, maybe it really wasn't designed to work like a $broadcast/$on, and we'll have to use services instead.

Contributor

ericmdantas commented Sep 12, 2015

@mhevery my opinion is pretty much the same of @SekibOmazic (thinking it'd bubble like any other event), but I do agree with @bduffany (reusable components that could hook to some of these custom events).

But again, maybe it really wasn't designed to work like a $broadcast/$on, and we'll have to use services instead.

@typotter

This comment has been minimized.

Show comment
Hide comment
@typotter

typotter Oct 6, 2015

+1
We frequently encounter wrap and compose components, exposing part or all of the inner components' APIs (both properties and events).

typotter commented Oct 6, 2015

+1
We frequently encounter wrap and compose components, exposing part or all of the inner components' APIs (both properties and events).

@timkindberg

This comment has been minimized.

Show comment
Hide comment
@timkindberg

timkindberg Oct 14, 2015

What @typotter said. +1

We currently have an a1atscript project going. We found the no-bubble restriction of custom events to be frustrating. We ended up using $scope events because we assumed Angular 2 would bubble custom events so we thought they better polyfilled Angular 2.

Here is a great use case with code example.

We have a product purchasing app. It's a grid of products. When I add a product, I do not want the product-card to talk to any services directly, it should remain a "dumb" component. I just want it to broadcast what happened.

product-card-grid is also not a good place to deal with the event, I'd like to keep that guy "dumb" too.

app ends up being the highest point that I can bubble my event that makes sense to handle this event. So app passes the payload to a CartService. app is now a throwaway layer in my app, and the other two components are truly re-usable.

We call this idea Components and Composers. Components are "dumb". Composers are components and also tie together services, models and other components.

See how the event bubbles right through product-card-grid?

@Component({ selector: 'product-card' })
@View({ template: `<button (click)="add()">Add {{productData.name}}</button>` })
class ProductCard {
    @Input() productData;
    @Output() addToCart = new EventEmitter();

    add() {
        this.addToCart.next(this.productData)
    }
}

@Component({ selector: 'product-card-grid' })
@View({
    template: `
    <div *ng-for="#product of products">
        <product-card [product-data]="product"></product-card>
    </div>
    `
})
class ProductCard {
    @Input() products;
    // ... other stuff, pagination, etc
}

@Component({ selector: 'app' })
@View({
    template: `<product-card-grid [products]="products" (add-to-cart)="onAddToCart()"></product-card-grid>`
})
class ProductCard {
    constructor() {
        this.products = [{name:'Car'}, {name:'Boat'}];
    }

    onAddToCart(product) {
        this.CartService.add(product);
    }
}

What @typotter said. +1

We currently have an a1atscript project going. We found the no-bubble restriction of custom events to be frustrating. We ended up using $scope events because we assumed Angular 2 would bubble custom events so we thought they better polyfilled Angular 2.

Here is a great use case with code example.

We have a product purchasing app. It's a grid of products. When I add a product, I do not want the product-card to talk to any services directly, it should remain a "dumb" component. I just want it to broadcast what happened.

product-card-grid is also not a good place to deal with the event, I'd like to keep that guy "dumb" too.

app ends up being the highest point that I can bubble my event that makes sense to handle this event. So app passes the payload to a CartService. app is now a throwaway layer in my app, and the other two components are truly re-usable.

We call this idea Components and Composers. Components are "dumb". Composers are components and also tie together services, models and other components.

See how the event bubbles right through product-card-grid?

@Component({ selector: 'product-card' })
@View({ template: `<button (click)="add()">Add {{productData.name}}</button>` })
class ProductCard {
    @Input() productData;
    @Output() addToCart = new EventEmitter();

    add() {
        this.addToCart.next(this.productData)
    }
}

@Component({ selector: 'product-card-grid' })
@View({
    template: `
    <div *ng-for="#product of products">
        <product-card [product-data]="product"></product-card>
    </div>
    `
})
class ProductCard {
    @Input() products;
    // ... other stuff, pagination, etc
}

@Component({ selector: 'app' })
@View({
    template: `<product-card-grid [products]="products" (add-to-cart)="onAddToCart()"></product-card-grid>`
})
class ProductCard {
    constructor() {
        this.products = [{name:'Car'}, {name:'Boat'}];
    }

    onAddToCart(product) {
        this.CartService.add(product);
    }
}
@alexpods

This comment has been minimized.

Show comment
Hide comment
@alexpods

alexpods Oct 14, 2015

@timkindberg Just add addToCart event (output property), as you've done it for ProductCard component. It'll make ProductCardGrid interface to be more explicit and, as a result, much easier to maintain.

@Component({ selector: 'product-card-grid' })
@View({
    template: `
    <div *ng-for="#product of products">
        <product-card [product-data]="product" (add-to-cart)="addToCart.next($event)"></product-card>
    </div>
    `
})
class ProductCardGrid {
    @Input() products;
    @Output() addToCart = new EventEmitter();
    // ... other stuff, pagination, etc
}

Also bubbling can lead to event name collision, when two child elements emit different events with the same name. So mine -1 for it.

@timkindberg Just add addToCart event (output property), as you've done it for ProductCard component. It'll make ProductCardGrid interface to be more explicit and, as a result, much easier to maintain.

@Component({ selector: 'product-card-grid' })
@View({
    template: `
    <div *ng-for="#product of products">
        <product-card [product-data]="product" (add-to-cart)="addToCart.next($event)"></product-card>
    </div>
    `
})
class ProductCardGrid {
    @Input() products;
    @Output() addToCart = new EventEmitter();
    // ... other stuff, pagination, etc
}

Also bubbling can lead to event name collision, when two child elements emit different events with the same name. So mine -1 for it.

@alexpods

This comment has been minimized.

Show comment
Hide comment
@alexpods

alexpods Oct 14, 2015

A small offtopic.

BTW I also very much like "dumb/smart components" idea. It's very handy to create smart components (statefull) using a lot of dumb components (statelesss, can only receive properties (inputs) and emit events (outputs)). Unfortunately angular2 is very bad adopted for this sort of things.

For example in React 0.14 you can create dumb components pretty easy:

const DumbComponent = ({ someProp }) => (
   <ChildComponent1>
      <ChildComponent2>
         {someProp}
      <ChildComponent2>
   </ChildComponent1>
);

while in angular2 you must do:

@Component({
    selector: 'dumb-component',
    directives: [ChildComponent1, ChildComponent2],
    template: `
        <child-component1>
            <child-component2>
                {{ someProp }}
            </child-component2>
        </child-component1>
    `
})
class DumbComponent {
    @Input() someProp: string
}

Looks too verbose for me.

Maybe we can somehow improve it?

@mhevery @gdi2290

A small offtopic.

BTW I also very much like "dumb/smart components" idea. It's very handy to create smart components (statefull) using a lot of dumb components (statelesss, can only receive properties (inputs) and emit events (outputs)). Unfortunately angular2 is very bad adopted for this sort of things.

For example in React 0.14 you can create dumb components pretty easy:

const DumbComponent = ({ someProp }) => (
   <ChildComponent1>
      <ChildComponent2>
         {someProp}
      <ChildComponent2>
   </ChildComponent1>
);

while in angular2 you must do:

@Component({
    selector: 'dumb-component',
    directives: [ChildComponent1, ChildComponent2],
    template: `
        <child-component1>
            <child-component2>
                {{ someProp }}
            </child-component2>
        </child-component1>
    `
})
class DumbComponent {
    @Input() someProp: string
}

Looks too verbose for me.

Maybe we can somehow improve it?

@mhevery @gdi2290

timkindberg added a commit to ngUpgraders/ng-forward that referenced this issue Oct 22, 2015

test(general): improve test coverage; component decorator; events; ch…
…ange outputs to not bubble; angular version behaviors;

BREAKING CHANGE:
Component outputs no longer bubble, follow along here: angular/angular#2296
@mhelvens

This comment has been minimized.

Show comment
Hide comment
@mhelvens

mhelvens Nov 17, 2015

It seems to me that for the sake of consistency and the principle of least surprise, the default position would be to support bubbling for custom event, to make their behavior consistent with that of native DOM events. And I'm not seeing any drawbacks.

For example, the name collision problem mentioned by @bduffany above only occurs if you opt into using custom event bubbling in the first place, by using the ^ syntax. And it can be solved by sending a reference to the originating element along with the event. As for third-party components, they should namespace their events / attributes anyway (e.g., myLib-myEvent).

@mhevery: You say that event bubbling only makes sense for input events. I'm not sure I agree. But leaving that aside: what if I want to create a custom input event?

It seems to me that for the sake of consistency and the principle of least surprise, the default position would be to support bubbling for custom event, to make their behavior consistent with that of native DOM events. And I'm not seeing any drawbacks.

For example, the name collision problem mentioned by @bduffany above only occurs if you opt into using custom event bubbling in the first place, by using the ^ syntax. And it can be solved by sending a reference to the originating element along with the event. As for third-party components, they should namespace their events / attributes anyway (e.g., myLib-myEvent).

@mhevery: You say that event bubbling only makes sense for input events. I'm not sure I agree. But leaving that aside: what if I want to create a custom input event?

@mhevery

This comment has been minimized.

Show comment
Hide comment
@mhevery

mhevery Nov 18, 2015

Member

Allowing custom events to bubble is something which we may consider post beta.

Member

mhevery commented Nov 18, 2015

Allowing custom events to bubble is something which we may consider post beta.

@ecopony

This comment has been minimized.

Show comment
Hide comment
@ecopony

ecopony Nov 22, 2015

@mhelvens +1 to the principle of least surprise comment. Not being able to bubble custom events surprised me building my first Angular 2 prototype. Working with deep component hierarchies, not being able to fire off events and let whoever cares handle them is a fairly big constraint. @alexpods' example passthrough is helpful for smaller hierarchies, but I imagine would get tedious and restrictive in something deeper and more complicated. I don't know whether it should be the default behavior, but at least an option.

ecopony commented Nov 22, 2015

@mhelvens +1 to the principle of least surprise comment. Not being able to bubble custom events surprised me building my first Angular 2 prototype. Working with deep component hierarchies, not being able to fire off events and let whoever cares handle them is a fairly big constraint. @alexpods' example passthrough is helpful for smaller hierarchies, but I imagine would get tedious and restrictive in something deeper and more complicated. I don't know whether it should be the default behavior, but at least an option.

@scottwio

This comment has been minimized.

Show comment
Hide comment
@scottwio

scottwio Dec 9, 2015

+1 for this. Same thing as everyone is saying above. As soon as you have a nested hierarchy you end up having to pass the events through multiple components. Also I have done so much DOM coding that I expect events to bubble, this really threw me the first time I encountered it. I would imagine if you ask any front-end dev who can listen on an event that gets emitted they are going to say anyone, not just the direct parent.

scottwio commented Dec 9, 2015

+1 for this. Same thing as everyone is saying above. As soon as you have a nested hierarchy you end up having to pass the events through multiple components. Also I have done so much DOM coding that I expect events to bubble, this really threw me the first time I encountered it. I would imagine if you ask any front-end dev who can listen on an event that gets emitted they are going to say anyone, not just the direct parent.

@scottwio

This comment has been minimized.

Show comment
Hide comment
@scottwio

scottwio Dec 10, 2015

After looking a bit deeper into custom events I now understand why they do not bubble. In my head I had these down as DOM events so expected them to act in the same way. I thought that angular was simply firing DOM events with something like CustomEvent() so why wouldn't the event bubble. If you coming from this mind set that these are DOM events it's hard to see why this feature wouldn't be added, the infrastructure is already provided by the DOM.

Now I understand that this isn't how EventEmitter works it has nothing to do with the DOM it's pub sub so adding bubbling is more complicated. I would still like to see this in angular 2 at some point as it is tedious to have to pass these "events" around at the moment.

As a side note removing the word 'event' from @output completely might help with the confusion. I think a lot of long time DOM Javascripters are going to see things like EventEmitter and make the same wrong conclusion, as I did. Maybe these could become Publishers or something similar, just a thought.

After looking a bit deeper into custom events I now understand why they do not bubble. In my head I had these down as DOM events so expected them to act in the same way. I thought that angular was simply firing DOM events with something like CustomEvent() so why wouldn't the event bubble. If you coming from this mind set that these are DOM events it's hard to see why this feature wouldn't be added, the infrastructure is already provided by the DOM.

Now I understand that this isn't how EventEmitter works it has nothing to do with the DOM it's pub sub so adding bubbling is more complicated. I would still like to see this in angular 2 at some point as it is tedious to have to pass these "events" around at the moment.

As a side note removing the word 'event' from @output completely might help with the confusion. I think a lot of long time DOM Javascripters are going to see things like EventEmitter and make the same wrong conclusion, as I did. Maybe these could become Publishers or something similar, just a thought.

@timkindberg

This comment has been minimized.

Show comment
Hide comment
@timkindberg

timkindberg Dec 24, 2015

I figured it out, here is how you do custom events that bubble, if you must: http://plnkr.co/edit/EH28a7O3dfa2cH2Sq3wj?p=preview

Basically you don't register the event as an output, because Angular wants those to be EventEmitters, and then you dispatch your custom event as a normal dom event using new CustomEvent('name', { bubbles: true});.

The discussion of whether outputs should bubble or be able to bubble is still worth thinking about though. But at least we can do bubbling if we really want to. Does anyone know a shorter quicker method of dispatching a DOM event with bubbling?

I figured it out, here is how you do custom events that bubble, if you must: http://plnkr.co/edit/EH28a7O3dfa2cH2Sq3wj?p=preview

Basically you don't register the event as an output, because Angular wants those to be EventEmitters, and then you dispatch your custom event as a normal dom event using new CustomEvent('name', { bubbles: true});.

The discussion of whether outputs should bubble or be able to bubble is still worth thinking about though. But at least we can do bubbling if we really want to. Does anyone know a shorter quicker method of dispatching a DOM event with bubbling?

@Meligy

This comment has been minimized.

Show comment
Hide comment
@Meligy

Meligy May 17, 2016

Contributor

What's the status of the official support for this?

Let's take this example from Dan Wahlin's Angular 2 JumpStart repo example

customersGrid.component.html

...
<tr>
    <th>&nbsp;</th>
    <th sort-by="firstName" (sorted)="sort($event)">First Name</th>
    <th sort-by="lastName" (sorted)="sort($event)">Last Name</th>
    <th sort-by="address" (sorted)="sort($event)">Address</th>
    <th sort-by="city" (sorted)="sort($event)">City</th>
    <th sort-by="state.name" (sorted)="sort($event)">State</th>
    ...

In this example, sort-by is a directive. It only handles click event and passes it as a sorted event, using the usual EventEmitter class - Details: sortby.directive.ts.

The bit repeating (sorted)="sort($event)" is very verbose, I'd rather instead write:

...
<tr (sorted)="sort($event)">
    <th>&nbsp;</th>
    <th sort-by="firstName">First Name</th>
    <th sort-by="lastName">Last Name</th>
    <th sort-by="address">Address</th>
    <th sort-by="city">City</th>
    <th sort-by="state.name">State</th>
    ...

Meaning I write (sorted)="sort($event)" only once in the tr, instead of repeating it in every th.


Does this make sense as a use case?

Contributor

Meligy commented May 17, 2016

What's the status of the official support for this?

Let's take this example from Dan Wahlin's Angular 2 JumpStart repo example

customersGrid.component.html

...
<tr>
    <th>&nbsp;</th>
    <th sort-by="firstName" (sorted)="sort($event)">First Name</th>
    <th sort-by="lastName" (sorted)="sort($event)">Last Name</th>
    <th sort-by="address" (sorted)="sort($event)">Address</th>
    <th sort-by="city" (sorted)="sort($event)">City</th>
    <th sort-by="state.name" (sorted)="sort($event)">State</th>
    ...

In this example, sort-by is a directive. It only handles click event and passes it as a sorted event, using the usual EventEmitter class - Details: sortby.directive.ts.

The bit repeating (sorted)="sort($event)" is very verbose, I'd rather instead write:

...
<tr (sorted)="sort($event)">
    <th>&nbsp;</th>
    <th sort-by="firstName">First Name</th>
    <th sort-by="lastName">Last Name</th>
    <th sort-by="address">Address</th>
    <th sort-by="city">City</th>
    <th sort-by="state.name">State</th>
    ...

Meaning I write (sorted)="sort($event)" only once in the tr, instead of repeating it in every th.


Does this make sense as a use case?

@mhevery

This comment has been minimized.

Show comment
Hide comment
@mhevery

mhevery May 17, 2016

Member

The status is that we will revisit after the final is shipped.

Member

mhevery commented May 17, 2016

The status is that we will revisit after the final is shipped.

@Meligy

This comment has been minimized.

Show comment
Hide comment
@Meligy

Meligy May 17, 2016

Contributor

Thanks a lot @mhevery.

It looks like something that can affect the architecture of events in Angular 2 though. It raises questions about having 2 kinds of events (DOM and EventEmitter) and whether it is a good idea (mainly for difference in characteristics in general, not bubbling specifically).

That's something that can lead to some good confusion (I was already confused how first how $event object is something a value, rather than a classic event object), and visiting it is an architectural job that would be much easier done before final than after.

I think I read somewhere that as part of changing events from async to async (or was it the other way around? One other area where the difference from DOM bites), you are also revisiting the whole EventEmitter strategy.

I guess that's not happening then (the EventEmitter revisiting), which makes sense for getting close to final.

Anyway, cool. Thanks for caring to mention it.

Contributor

Meligy commented May 17, 2016

Thanks a lot @mhevery.

It looks like something that can affect the architecture of events in Angular 2 though. It raises questions about having 2 kinds of events (DOM and EventEmitter) and whether it is a good idea (mainly for difference in characteristics in general, not bubbling specifically).

That's something that can lead to some good confusion (I was already confused how first how $event object is something a value, rather than a classic event object), and visiting it is an architectural job that would be much easier done before final than after.

I think I read somewhere that as part of changing events from async to async (or was it the other way around? One other area where the difference from DOM bites), you are also revisiting the whole EventEmitter strategy.

I guess that's not happening then (the EventEmitter revisiting), which makes sense for getting close to final.

Anyway, cool. Thanks for caring to mention it.

@dwasyluk

This comment has been minimized.

Show comment
Hide comment
@dwasyluk

dwasyluk Jun 10, 2016

Thanks @timkindberg for the workaround, disappointed to not see a working example of how custom events can be used to communicate between "long distance" components outside of the re-emit pattern -which I agree is overly verbose and won't scale well in a large application (will make code really confusing compared to bubbling events as components that don't actually care about the event will need to re-emit).

@mhevery you mention "PS: #2296 (comment) can better be solved by injecting services rather then using events." I am injecting a service which dispatches an event and then listening on that service's EventEmitter in my root app component but the handler is not firing.

Here is a quick plunker: http://plnkr.co/edit/1qNZCKiOcj2hG2XM14OJ. Can you please explain what I'm doing wrong here as I thought this was the suggested implementation?

Thanks @timkindberg for the workaround, disappointed to not see a working example of how custom events can be used to communicate between "long distance" components outside of the re-emit pattern -which I agree is overly verbose and won't scale well in a large application (will make code really confusing compared to bubbling events as components that don't actually care about the event will need to re-emit).

@mhevery you mention "PS: #2296 (comment) can better be solved by injecting services rather then using events." I am injecting a service which dispatches an event and then listening on that service's EventEmitter in my root app component but the handler is not firing.

Here is a quick plunker: http://plnkr.co/edit/1qNZCKiOcj2hG2XM14OJ. Can you please explain what I'm doing wrong here as I thought this was the suggested implementation?

@larrifax

This comment has been minimized.

Show comment
Hide comment
@larrifax

larrifax Jun 10, 2016

@dwasyluk remove providers: [ApiService] from the Child-component's decorator and it works. Setting providers both in the App (parent) and the Child causes the injector to create two separate instances of ApiService.

BTW: It is recommended to use Subject from rxjs instead of the EventEmitter when not dealing with @Output (which you also shouldn't use in the ApiService. @Input and @Output only makes sense in directives and components)

@dwasyluk remove providers: [ApiService] from the Child-component's decorator and it works. Setting providers both in the App (parent) and the Child causes the injector to create two separate instances of ApiService.

BTW: It is recommended to use Subject from rxjs instead of the EventEmitter when not dealing with @Output (which you also shouldn't use in the ApiService. @Input and @Output only makes sense in directives and components)

@dwasyluk

This comment has been minimized.

Show comment
Hide comment
@dwasyluk

dwasyluk Jun 10, 2016

@larrifax wow thank you very much! Great info!

Regarding your suggestion that Subject be used when dispatching events from a service rather than @Output/@Input I'll give that a try- I saw many an ng2 example firing @Output from a service thus the patterning, if the official guidance is that observables are preferred it would be nice if the documentation was updated to reflect this.

@larrifax wow thank you very much! Great info!

Regarding your suggestion that Subject be used when dispatching events from a service rather than @Output/@Input I'll give that a try- I saw many an ng2 example firing @Output from a service thus the patterning, if the official guidance is that observables are preferred it would be nice if the documentation was updated to reflect this.

@ericmartinezr

This comment has been minimized.

Show comment
Hide comment
@ericmartinezr

ericmartinezr Jun 10, 2016

Contributor

@dwasyluk that's a bad practice, you must not use an EventEmitter in a service. https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service

Contributor

ericmartinezr commented Jun 10, 2016

@dwasyluk that's a bad practice, you must not use an EventEmitter in a service. https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service

@juanmendes

This comment has been minimized.

Show comment
Hide comment
@juanmendes

juanmendes Jun 14, 2016

Another vote for custom events bubbling up. The architecture of my app calls for widgets/addons to fire some events that I would like to listen from my top level app component. For example, when a widget finishes an action that it would like to be published to our app's activity manager, it's supposed to fire 'activitystarted|activityprogress|activityfinished' events so that components that care about the event can respond without having to wire the custom events up the hierarchy.

Another use case is we want to update the title of a section whenever a subsection gets updated, so we require subsections to fire a custom event that its title has changed. The section component can respond to that event, and if we wanted to, any widget above that should also be able to respond whenever a new sub section is loaded (For example, updating the page title to include information about the current sub section).

This has been referred to as client side HMVC, http://www.javaworld.com/article/2076128/design-patterns/hmvc--the-layered-pattern-for-developing-strong-client-tiers.html That article talks about controllers passing events up, but I have been happily using the same technique with DOM bubbling events for many years (not having to manually bubble up events) and would love to be able to use the same technique in Angular2.

Another vote for custom events bubbling up. The architecture of my app calls for widgets/addons to fire some events that I would like to listen from my top level app component. For example, when a widget finishes an action that it would like to be published to our app's activity manager, it's supposed to fire 'activitystarted|activityprogress|activityfinished' events so that components that care about the event can respond without having to wire the custom events up the hierarchy.

Another use case is we want to update the title of a section whenever a subsection gets updated, so we require subsections to fire a custom event that its title has changed. The section component can respond to that event, and if we wanted to, any widget above that should also be able to respond whenever a new sub section is loaded (For example, updating the page title to include information about the current sub section).

This has been referred to as client side HMVC, http://www.javaworld.com/article/2076128/design-patterns/hmvc--the-layered-pattern-for-developing-strong-client-tiers.html That article talks about controllers passing events up, but I have been happily using the same technique with DOM bubbling events for many years (not having to manually bubble up events) and would love to be able to use the same technique in Angular2.

@zoechi

This comment has been minimized.

Show comment
Hide comment
@oskarols

This comment has been minimized.

Show comment
Hide comment
@oskarols

oskarols Jun 15, 2016

@zoechi A shared service or observable is a very poor solution for many use-cases.

Essentially this all has to do with decoupling, and I'm a bit puzzled as to why no one was able to give @mhevery a better use-case in the beginning of the thread since this is quite fundamental to how component communication works.
This functionality has also been a fundamental part of other frameworks for a very long time (e.g. https://guides.emberjs.com/v1.10.0/views/handling-events/).

Given a component tree that looks like this:

A -----> B -----> C -----> D
                   \-----> E

Where A would be the root "smart" component (i.e. the component loading data), and D and E would be leaf components.

The B and C components should not have to care, or know about any events emitted further down in the tree. That is very poor decoupling, and the single responsibility principle goes out the window.

Given a large application any intermediate components will grow huge, and furthermore it will be very hard to make them generic since they explicitly will have to pass events from any child components up the tree.

In my mind something similar to the solution they've gone with in Ember would be a huge improvement:

  1. custom events bubble up the tree
  2. there are conventions for distinguishing custom event-handlers from the rest of the methods
  3. if custom events make it all the way to the root without being handled there's an error

oskarols commented Jun 15, 2016

@zoechi A shared service or observable is a very poor solution for many use-cases.

Essentially this all has to do with decoupling, and I'm a bit puzzled as to why no one was able to give @mhevery a better use-case in the beginning of the thread since this is quite fundamental to how component communication works.
This functionality has also been a fundamental part of other frameworks for a very long time (e.g. https://guides.emberjs.com/v1.10.0/views/handling-events/).

Given a component tree that looks like this:

A -----> B -----> C -----> D
                   \-----> E

Where A would be the root "smart" component (i.e. the component loading data), and D and E would be leaf components.

The B and C components should not have to care, or know about any events emitted further down in the tree. That is very poor decoupling, and the single responsibility principle goes out the window.

Given a large application any intermediate components will grow huge, and furthermore it will be very hard to make them generic since they explicitly will have to pass events from any child components up the tree.

In my mind something similar to the solution they've gone with in Ember would be a huge improvement:

  1. custom events bubble up the tree
  2. there are conventions for distinguishing custom event-handlers from the rest of the methods
  3. if custom events make it all the way to the root without being handled there's an error
@zoechi

This comment has been minimized.

Show comment
Hide comment
@zoechi

zoechi Jun 15, 2016

Contributor

@oskarols I don't see how using services prevents you from doing what you want. If A provides the service and D and/or E inject it, then you have a direct communication between D/E and A without B and C being bothered in any way.

Contributor

zoechi commented Jun 15, 2016

@oskarols I don't see how using services prevents you from doing what you want. If A provides the service and D and/or E inject it, then you have a direct communication between D/E and A without B and C being bothered in any way.

@oskarols

This comment has been minimized.

Show comment
Hide comment
@oskarols

oskarols Jun 15, 2016

@zoechi Because you don't want any direct communication between the components.

D and E should just display data that they're passed from parents, and emit events. As simple and generic as possible, so they can be reused and easily tested.

oskarols commented Jun 15, 2016

@zoechi Because you don't want any direct communication between the components.

D and E should just display data that they're passed from parents, and emit events. As simple and generic as possible, so they can be reused and easily tested.

@juanmendes

This comment has been minimized.

Show comment
Hide comment
@juanmendes

juanmendes Jun 15, 2016

@zoechi I know I can use a service and add what is the equivalent of
creating a global message bus, which I'm trying to avoid. Moreover, this
would not allow a component in the hierarchy to stop the event's default
behavior or to take advantage of event delegation.

I'm not saying it can't be done with services, I'm just saying that
bubbling events are powerful, and are a common pattern, why would angular
prevent custom events from behaving like they do in the DOM?

On Wed, Jun 15, 2016 at 12:03 PM, Oskar Olsson notifications@github.com
wrote:

@zoechi https://github.com/zoechi Because you don't want any direct
communication between the components.

D and E should just display data that they're passed from parents, and
emit events. As simple and generic as possible, so they can be reused.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#2296 (comment),
or mute the thread
https://github.com/notifications/unsubscribe/AAhh00DyZXILFMRKGh6bUG7H6Jeq2vfDks5qMCJWgaJpZM4E1SAj
.

Juan Mendes

@zoechi I know I can use a service and add what is the equivalent of
creating a global message bus, which I'm trying to avoid. Moreover, this
would not allow a component in the hierarchy to stop the event's default
behavior or to take advantage of event delegation.

I'm not saying it can't be done with services, I'm just saying that
bubbling events are powerful, and are a common pattern, why would angular
prevent custom events from behaving like they do in the DOM?

On Wed, Jun 15, 2016 at 12:03 PM, Oskar Olsson notifications@github.com
wrote:

@zoechi https://github.com/zoechi Because you don't want any direct
communication between the components.

D and E should just display data that they're passed from parents, and
emit events. As simple and generic as possible, so they can be reused.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#2296 (comment),
or mute the thread
https://github.com/notifications/unsubscribe/AAhh00DyZXILFMRKGh6bUG7H6Jeq2vfDks5qMCJWgaJpZM4E1SAj
.

Juan Mendes

@zoechi

This comment has been minimized.

Show comment
Hide comment
@zoechi

zoechi Jun 15, 2016

Contributor

@juanmendes this sounds a bit like I want to use Angular2 because it's so great but I want to use it differently than it is supposed to be used.

You still can use element.dispatchEvent() and (my-custom-event)="doSomething()" and you have your bubbling event.

Contributor

zoechi commented Jun 15, 2016

@juanmendes this sounds a bit like I want to use Angular2 because it's so great but I want to use it differently than it is supposed to be used.

You still can use element.dispatchEvent() and (my-custom-event)="doSomething()" and you have your bubbling event.

@Meligy

This comment has been minimized.

Show comment
Hide comment
@Meligy

Meligy Jun 15, 2016

Contributor

The fundamental problem is that EventEmitter / Subjects aren't suitable for custom events, because they work quite differently than the DOM.

It looks like this area needs another revisit, alike to what happened to the router. Except it's obviously not in the team radar before final release, which will make it much harder to happen at all (because it could be breaking, which is unlikely after final).

I'm just saying that
bubbling events are powerful, and are a common pattern, why would angular
prevent custom events from behaving like they do in the DOM?

Exactly. You even could do that in Angular 2, except it was not conventional Angular, which is why people did it less and use $scope message bus.

Angular 2 is supposed to fix all this, not just rename it and make it more effort (because you need to create your own services, and don't have a structure like $scope).

You still can use element.dispatchEvent() and (my-custom-event)="doSomething()" and you have your bubbling event.

Except, again, it's not conventional Angular 2. It's fighting the framework's power of defaults for what seems like a direction it should encourage.

Contributor

Meligy commented Jun 15, 2016

The fundamental problem is that EventEmitter / Subjects aren't suitable for custom events, because they work quite differently than the DOM.

It looks like this area needs another revisit, alike to what happened to the router. Except it's obviously not in the team radar before final release, which will make it much harder to happen at all (because it could be breaking, which is unlikely after final).

I'm just saying that
bubbling events are powerful, and are a common pattern, why would angular
prevent custom events from behaving like they do in the DOM?

Exactly. You even could do that in Angular 2, except it was not conventional Angular, which is why people did it less and use $scope message bus.

Angular 2 is supposed to fix all this, not just rename it and make it more effort (because you need to create your own services, and don't have a structure like $scope).

You still can use element.dispatchEvent() and (my-custom-event)="doSomething()" and you have your bubbling event.

Except, again, it's not conventional Angular 2. It's fighting the framework's power of defaults for what seems like a direction it should encourage.

@zoechi

This comment has been minimized.

Show comment
Hide comment
@zoechi

zoechi Jun 16, 2016

Contributor

From a comment of mhevery above

Component/Directive events do not bubble up, and as of right now I don't see a strong enough use case for them.

Could someone provide one?

If you think this is necessary provide a concrete use case for what is difficult or impossible to do without bubbling custom events. I doubt this will be added because some people would like it.

Except, again, it's not conventional Angular 2. It's fighting the framework's power of defaults for what seems like a direction it should encourage.

Why does everything have to be implemented by Angular2. Angular 2 runs in the browser. Everything the browser provides is conventional Angular2.

Contributor

zoechi commented Jun 16, 2016

From a comment of mhevery above

Component/Directive events do not bubble up, and as of right now I don't see a strong enough use case for them.

Could someone provide one?

If you think this is necessary provide a concrete use case for what is difficult or impossible to do without bubbling custom events. I doubt this will be added because some people would like it.

Except, again, it's not conventional Angular 2. It's fighting the framework's power of defaults for what seems like a direction it should encourage.

Why does everything have to be implemented by Angular2. Angular 2 runs in the browser. Everything the browser provides is conventional Angular2.

@Meligy

This comment has been minimized.

Show comment
Hide comment
@Meligy

Meligy Jun 16, 2016

Contributor

@zoechi I really don't want to turn this into some sort of blame game "You didn't" / "You didn't", but your comment about concrete example totally dishonors several comments written since September 2015.

IMHO this is very non constructive. Maybe read the comments again please and the code samples and all.

Regarding conventional Angular 2, it's confusing enough that we have 2 event systems in Angular2, one for DOM events and one for custom DOM-like-but-not-really events.

Adding another way for custom-but-also-DOM-unlike-builtin will only lead to developer confusion.

Contributor

Meligy commented Jun 16, 2016

@zoechi I really don't want to turn this into some sort of blame game "You didn't" / "You didn't", but your comment about concrete example totally dishonors several comments written since September 2015.

IMHO this is very non constructive. Maybe read the comments again please and the code samples and all.

Regarding conventional Angular 2, it's confusing enough that we have 2 event systems in Angular2, one for DOM events and one for custom DOM-like-but-not-really events.

Adding another way for custom-but-also-DOM-unlike-builtin will only lead to developer confusion.

@zoechi

This comment has been minimized.

Show comment
Hide comment
@zoechi

zoechi Jun 16, 2016

Contributor

@Meligy
I'm not opposed. I just try to "motivate" you to post concrete examples about use cases that are difficult to implement because of this missing feature. The one already posted might not be common enough to pay off for the complexity this feature might add.

The issue is still open which indicates that the Angular team is still considering adding it.
They might even be convinced, but didn't consider it highest priority because there are workarounds available.

If you want to convince that Angular team to add this feature or to increase priority, provide use cases that demonstrate this is required or it makes your use case difficult to implement.

Arguing about whether one would like or dislike a feature is rather unlikely to convince them.

Contributor

zoechi commented Jun 16, 2016

@Meligy
I'm not opposed. I just try to "motivate" you to post concrete examples about use cases that are difficult to implement because of this missing feature. The one already posted might not be common enough to pay off for the complexity this feature might add.

The issue is still open which indicates that the Angular team is still considering adding it.
They might even be convinced, but didn't consider it highest priority because there are workarounds available.

If you want to convince that Angular team to add this feature or to increase priority, provide use cases that demonstrate this is required or it makes your use case difficult to implement.

Arguing about whether one would like or dislike a feature is rather unlikely to convince them.

@juanmendes

This comment has been minimized.

Show comment
Hide comment
@juanmendes

juanmendes Jun 16, 2016

@zoechi At the risk of sounding as rude as you, "This sounds a bit like I
want to use Angular2 because it's so great but I want to use it differently
than it is supposed to be used."

There are other frameworks that are also great, I'm choosing between
frameworks and this is one of the features I'm looking for.

On Thu, Jun 16, 2016 at 4:44 AM, Oskar Olsson notifications@github.com
wrote:

@zoechi https://github.com/zoechi There are plenty of use-cases and
reasons given in the thread. Just because you for some reason don't
find them pertinent doesn't mean they aren't relevant. Please keep the
thread constructive.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#2296 (comment),
or mute the thread
https://github.com/notifications/unsubscribe/AAhh09x5zC22BCyEZWJKkWme8SLb45Rqks5qMQz5gaJpZM4E1SAj
.

Juan Mendes

@zoechi At the risk of sounding as rude as you, "This sounds a bit like I
want to use Angular2 because it's so great but I want to use it differently
than it is supposed to be used."

There are other frameworks that are also great, I'm choosing between
frameworks and this is one of the features I'm looking for.

On Thu, Jun 16, 2016 at 4:44 AM, Oskar Olsson notifications@github.com
wrote:

@zoechi https://github.com/zoechi There are plenty of use-cases and
reasons given in the thread. Just because you for some reason don't
find them pertinent doesn't mean they aren't relevant. Please keep the
thread constructive.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#2296 (comment),
or mute the thread
https://github.com/notifications/unsubscribe/AAhh09x5zC22BCyEZWJKkWme8SLb45Rqks5qMQz5gaJpZM4E1SAj
.

Juan Mendes

@zoechi

This comment has been minimized.

Show comment
Hide comment
@zoechi

zoechi Jun 16, 2016

Contributor

@juanmendes sorry, sounding rude was not my intention, not at all. When I try to write English in a more friendly tone my sentences usually become quite unwieldy, therefore I just try to get my point accross.

Every feature comes with very high costs. I personally would avoid adding one just because a few like it (It's not my call though, I'm not even a member of the Angular team)
Therefore I think adding comments like "I want this! Why is this not yet implemented!", "Xxx has this as well", or similar, are pointless.
If you try to provide good reasons (concrete use cases) why such a feature would be worth its money, this would help much more to get it added.

I just try to provide some support in case people missed some other Angular2 features that help them to get the job done as well. My opposing implementing a new feature goes only so far that I want people to actually consider alternatives.

Contributor

zoechi commented Jun 16, 2016

@juanmendes sorry, sounding rude was not my intention, not at all. When I try to write English in a more friendly tone my sentences usually become quite unwieldy, therefore I just try to get my point accross.

Every feature comes with very high costs. I personally would avoid adding one just because a few like it (It's not my call though, I'm not even a member of the Angular team)
Therefore I think adding comments like "I want this! Why is this not yet implemented!", "Xxx has this as well", or similar, are pointless.
If you try to provide good reasons (concrete use cases) why such a feature would be worth its money, this would help much more to get it added.

I just try to provide some support in case people missed some other Angular2 features that help them to get the job done as well. My opposing implementing a new feature goes only so far that I want people to actually consider alternatives.

@juanmendes

This comment has been minimized.

Show comment
Hide comment
@juanmendes

juanmendes Jun 16, 2016

@zoechi I think voting for a feature is not pointless. I did explain some
reasons why I prefer the bubbling event approach instead of a global bus. I
know you can work around it with shared services, but...

The service approach to sharing data on a global bus is asking for two way
data flow between components at a time when most are trying to design apps
that are easier to understand using a one-way data flow.

Flux is a very popular framework that works with Angular2, which also
provides a way to avoid the two-way data flow, it's not bound to whatever
Angular2 thinks you should do. But having this feature would allow me not
to need Flux with added benefits.

On Thu, Jun 16, 2016 at 7:14 AM, Günter Zöchbauer notifications@github.com
wrote:

@juanmendes https://github.com/juanmendes sorry, sounding rude was not
my intention, not at all. When I try to write English in a more friendly
tone my sentences usually become quite unwieldy, therefore I just try to
get my point accross.

Every feature comes with very high costs. I personally would avoid adding
one just because a few like it (It's not my call though, I'm not even a
member of the Angular team)
Therefore I think adding comments like "I want this! Why is this not yet
implemented!", "Xxx has this as well", or similar, are pointless.

If you try to provide good reasons (concrete use cases) why such a feature
would be worth its money, this would help much more to get it added.

I just try to provide some support in case people missed some other
Angular2 features that help them to get the job done as well. My opposing
implementing a new feature goes only so far that I want people to actually
consider alternatives.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#2296 (comment),
or mute the thread
https://github.com/notifications/unsubscribe/AAhh03Euf0sYWahRSdGvMjJH8d8UlOAhks5qMTAJgaJpZM4E1SAj
.

Juan Mendes

@zoechi I think voting for a feature is not pointless. I did explain some
reasons why I prefer the bubbling event approach instead of a global bus. I
know you can work around it with shared services, but...

The service approach to sharing data on a global bus is asking for two way
data flow between components at a time when most are trying to design apps
that are easier to understand using a one-way data flow.

Flux is a very popular framework that works with Angular2, which also
provides a way to avoid the two-way data flow, it's not bound to whatever
Angular2 thinks you should do. But having this feature would allow me not
to need Flux with added benefits.

On Thu, Jun 16, 2016 at 7:14 AM, Günter Zöchbauer notifications@github.com
wrote:

@juanmendes https://github.com/juanmendes sorry, sounding rude was not
my intention, not at all. When I try to write English in a more friendly
tone my sentences usually become quite unwieldy, therefore I just try to
get my point accross.

Every feature comes with very high costs. I personally would avoid adding
one just because a few like it (It's not my call though, I'm not even a
member of the Angular team)
Therefore I think adding comments like "I want this! Why is this not yet
implemented!", "Xxx has this as well", or similar, are pointless.

If you try to provide good reasons (concrete use cases) why such a feature
would be worth its money, this would help much more to get it added.

I just try to provide some support in case people missed some other
Angular2 features that help them to get the job done as well. My opposing
implementing a new feature goes only so far that I want people to actually
consider alternatives.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#2296 (comment),
or mute the thread
https://github.com/notifications/unsubscribe/AAhh03Euf0sYWahRSdGvMjJH8d8UlOAhks5qMTAJgaJpZM4E1SAj
.

Juan Mendes

@Meligy

This comment has been minimized.

Show comment
Hide comment
@Meligy

Meligy Jun 16, 2016

Contributor

Not to mention the confusion, which is my personal concern here. When I have an event, knowing whether it bubbles depends on:

  1. Whether it's a builtin DOM event or not
  2. If not, whether it's raised using a DOM API or an EventEmitter

2 of the 3 cases would bubble (1 of the 2 is less popular now, but possible), 1 won't.

With the framework that introduced Zones and monkeypatched several DOM APIs to avoid similar confusions in the change tracking side of things. This introduced confusion makes me wonder if this is the best choice for implementing events in Angular 2 at all - just like the other difference where sometimes you get an event object, and sometimes your event is actually a concrete value not a full event object.

Similar questions have been asked in the router area, and caused two rewrites.

You can see the verbosity example with the table header in my earlier comment. Another common case would be trying to get slightly more perf in repeaters by having event handlers set in the container of the repeater instead of each item in the list, although admittedly the actual perf gain from this will be minimal in a lot of cases.

But going into a "semi-native" syntax with events instead of ng-specific-event-name makes you want to treat it like events and write code that uses your learnings about how "native-like" events work.

However, I think @zoechi has made his point and the point is obvious to others. I wonder if the actual Angular team has a comment or question regarding the long series of examples and explanations provided in this thread -- sorry team in advance for duplicate arguing near the bottom here, at least from me.

Contributor

Meligy commented Jun 16, 2016

Not to mention the confusion, which is my personal concern here. When I have an event, knowing whether it bubbles depends on:

  1. Whether it's a builtin DOM event or not
  2. If not, whether it's raised using a DOM API or an EventEmitter

2 of the 3 cases would bubble (1 of the 2 is less popular now, but possible), 1 won't.

With the framework that introduced Zones and monkeypatched several DOM APIs to avoid similar confusions in the change tracking side of things. This introduced confusion makes me wonder if this is the best choice for implementing events in Angular 2 at all - just like the other difference where sometimes you get an event object, and sometimes your event is actually a concrete value not a full event object.

Similar questions have been asked in the router area, and caused two rewrites.

You can see the verbosity example with the table header in my earlier comment. Another common case would be trying to get slightly more perf in repeaters by having event handlers set in the container of the repeater instead of each item in the list, although admittedly the actual perf gain from this will be minimal in a lot of cases.

But going into a "semi-native" syntax with events instead of ng-specific-event-name makes you want to treat it like events and write code that uses your learnings about how "native-like" events work.

However, I think @zoechi has made his point and the point is obvious to others. I wonder if the actual Angular team has a comment or question regarding the long series of examples and explanations provided in this thread -- sorry team in advance for duplicate arguing near the bottom here, at least from me.

@awerlang

This comment has been minimized.

Show comment
Hide comment
@awerlang

awerlang Jun 16, 2016

Contributor

It has been said that allowing output events to bubble leads to decoupling.

A -----> B -----> C -----> D
                   \-----> E

So we want to listen D and E output events in A, and let's suppose we are able to do that.
Then I replace D with other whatever component that emits a different event.
I go on and move E from C to another separate tree altogether.

I certainly will have to change A due to something that is internal to C.
In this case bubbling output events does not do any better than a shared service.
And if children emit events under the same name but different payloads? Should I switch on the listener?

About the sentence from @juanmendes that most developers are choosing codebases easier to understand through one-way data flow, do you have data supporting this?
Because in my experience, most people would choose to follow a pattern which is most confortable to them. They want a tool to get the job done. By definition, most people are not early adopters who want to spend time chasing best practices.
Saying that one-way data flow is easier to understand, this is your opinion, not a fact, right?
If that is so, I would be interested in pursuing this way, seriously. (I have just started with ngrx, fwiw)
And if we look at gitter rooms, we see only about 5% of people in ngrx/store compared to angular/angular. This means something, I think.

I don't have a strong opinion about either have this or not, let alone which path I'll end up with.
Only that I see that it makes it easier to support differents approaches to app development.
So I think it would worth adding, as an optional feature.

Contributor

awerlang commented Jun 16, 2016

It has been said that allowing output events to bubble leads to decoupling.

A -----> B -----> C -----> D
                   \-----> E

So we want to listen D and E output events in A, and let's suppose we are able to do that.
Then I replace D with other whatever component that emits a different event.
I go on and move E from C to another separate tree altogether.

I certainly will have to change A due to something that is internal to C.
In this case bubbling output events does not do any better than a shared service.
And if children emit events under the same name but different payloads? Should I switch on the listener?

About the sentence from @juanmendes that most developers are choosing codebases easier to understand through one-way data flow, do you have data supporting this?
Because in my experience, most people would choose to follow a pattern which is most confortable to them. They want a tool to get the job done. By definition, most people are not early adopters who want to spend time chasing best practices.
Saying that one-way data flow is easier to understand, this is your opinion, not a fact, right?
If that is so, I would be interested in pursuing this way, seriously. (I have just started with ngrx, fwiw)
And if we look at gitter rooms, we see only about 5% of people in ngrx/store compared to angular/angular. This means something, I think.

I don't have a strong opinion about either have this or not, let alone which path I'll end up with.
Only that I see that it makes it easier to support differents approaches to app development.
So I think it would worth adding, as an optional feature.

@scottwio

This comment has been minimized.

Show comment
Hide comment
@scottwio

scottwio Jun 16, 2016

If you scroll way back up this thread I was one of the people complaining that events do not bubble. After using Angular 2 more I now understand why and believe they should not bubble, I was wrong. Bubbling events promotes code that is decoupled and confusing to follow. A event can be broadcast in one file and then picked up in a completely differently file. Another developer looking at your code has no logical path to follow in order to find out what is listening and reacting to that event.

If you need event bubbling or similar use a service with an observable. It's the new world order and leads to better code. It's time to get our heads out of the DOM.

scottwio commented Jun 16, 2016

If you scroll way back up this thread I was one of the people complaining that events do not bubble. After using Angular 2 more I now understand why and believe they should not bubble, I was wrong. Bubbling events promotes code that is decoupled and confusing to follow. A event can be broadcast in one file and then picked up in a completely differently file. Another developer looking at your code has no logical path to follow in order to find out what is listening and reacting to that event.

If you need event bubbling or similar use a service with an observable. It's the new world order and leads to better code. It's time to get our heads out of the DOM.

@timkindberg

This comment has been minimized.

Show comment
Hide comment
@timkindberg

timkindberg Jun 16, 2016

I tend to agree that bubbled events are still coupled to the components that listen to them. I also agree its hard to read and follow event-based logic flows as @scottwio has said (it's easier to write though :).

If we do bubble I might recommend namespaced events to more easily track where an even it coming from. e.g. In this example it's hard to determine where the event comes from:

<parent (some-event)="doIt()">
  <foo/>
  <bar/>
  <baz/>
</parent>

In angular 1 components we've used scope events with namespaces, such as $scope.emit('ComponentName:eventName'), so perhaps a similar approach here, like this:

<parent (baz:some-event)="doIt()">
  <foo/>
  <bar/>
  <baz/>
</parent>

Now it's clear the event comes from baz. If you want to listen to all children you can leave off the namespace, but its there to optionally use for clearer code.

Though I can easily see all sorts of rebuttals to this proposal, it might add more complexity than it's worth.

I tend to agree that bubbled events are still coupled to the components that listen to them. I also agree its hard to read and follow event-based logic flows as @scottwio has said (it's easier to write though :).

If we do bubble I might recommend namespaced events to more easily track where an even it coming from. e.g. In this example it's hard to determine where the event comes from:

<parent (some-event)="doIt()">
  <foo/>
  <bar/>
  <baz/>
</parent>

In angular 1 components we've used scope events with namespaces, such as $scope.emit('ComponentName:eventName'), so perhaps a similar approach here, like this:

<parent (baz:some-event)="doIt()">
  <foo/>
  <bar/>
  <baz/>
</parent>

Now it's clear the event comes from baz. If you want to listen to all children you can leave off the namespace, but its there to optionally use for clearer code.

Though I can easily see all sorts of rebuttals to this proposal, it might add more complexity than it's worth.

@Elvynia

This comment has been minimized.

Show comment
Hide comment
@Elvynia

Elvynia Sep 23, 2016

@mhevery Could you make a quick status update on this ? Does @timkindberg's solution with namespaces look like a acceptable approach ?

Custom events are definitely not like DOM events but well... It looks like a lot of us, developers, would want to treat them alike !
In the meantime, creating services only to share an Observable is still the better solution right ?

Elvynia commented Sep 23, 2016

@mhevery Could you make a quick status update on this ? Does @timkindberg's solution with namespaces look like a acceptable approach ?

Custom events are definitely not like DOM events but well... It looks like a lot of us, developers, would want to treat them alike !
In the meantime, creating services only to share an Observable is still the better solution right ?

@zoechi

This comment has been minimized.

Show comment
Hide comment
@zoechi

zoechi Sep 25, 2016

Contributor

You can dispatch custom DOM events if you need bubbling

Contributor

zoechi commented Sep 25, 2016

You can dispatch custom DOM events if you need bubbling

@timkindberg

This comment has been minimized.

Show comment
Hide comment
@timkindberg

timkindberg Sep 25, 2016

Yep, like this: http://plnkr.co/edit/LoF7SssMsUzqoyKSrL2K?p=preview

However, isn't that coupling to the DOM element? So it won't be universal-friendly.

Yep, like this: http://plnkr.co/edit/LoF7SssMsUzqoyKSrL2K?p=preview

However, isn't that coupling to the DOM element? So it won't be universal-friendly.

@zoechi

This comment has been minimized.

Show comment
Hide comment
@zoechi

zoechi Sep 25, 2016

Contributor

@timkindberg You can use the renderer to dispatch the event and this way shouldn't hurt universal
See http://stackoverflow.com/a/36348311/217408 for an example

Contributor

zoechi commented Sep 25, 2016

@timkindberg You can use the renderer to dispatch the event and this way shouldn't hurt universal
See http://stackoverflow.com/a/36348311/217408 for an example

@Elvynia

This comment has been minimized.

Show comment
Hide comment
@Elvynia

Elvynia Sep 28, 2016

@timkindberg, @zoechi Thanks a lot for the information. I'm finally mainly using BehaviorSubject in services and EventEmitter in Components. I'll try to bubble with the Renderer only when I'll really need it. Seems to do the job perfectly.

Elvynia commented Sep 28, 2016

@timkindberg, @zoechi Thanks a lot for the information. I'm finally mainly using BehaviorSubject in services and EventEmitter in Components. I'll try to bubble with the Renderer only when I'll really need it. Seems to do the job perfectly.

@cquillen2003

This comment has been minimized.

Show comment
Hide comment
@cquillen2003

cquillen2003 Nov 1, 2016

Will the event bubbling/emission solution be compatible with "routed" components?

Meaning components placed in the DOM via <router-outlet></router-outlet>. As of now, there is no way to emit events from "routed" components as far as I know.

IMO, complex applications will make heavy use of the router, not only for "pages", but also for tabs and such. Ideally, these routed components would use the same component model as custom tags in terms of input and output.

cquillen2003 commented Nov 1, 2016

Will the event bubbling/emission solution be compatible with "routed" components?

Meaning components placed in the DOM via <router-outlet></router-outlet>. As of now, there is no way to emit events from "routed" components as far as I know.

IMO, complex applications will make heavy use of the router, not only for "pages", but also for tabs and such. Ideally, these routed components would use the same component model as custom tags in terms of input and output.

@zoechi

This comment has been minimized.

Show comment
Hide comment
@zoechi

zoechi Nov 1, 2016

Contributor

you can dispatch DOM events and they bubble as usual, but as of now there is no way to have bubbling events from outputs

Contributor

zoechi commented Nov 1, 2016

you can dispatch DOM events and they bubble as usual, but as of now there is no way to have bubbling events from outputs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment