38

I have played with Angular 2 components and their compositions and I have run into ugly behavior, which is caused by native event bubbling and @Output name collision.

I have component app-form with form in template

<form (ngSubmit)="submitButtonClicked($event)">
  <input type="text"/>
  <button type="submit">Send</button>
</form>

I use this form component in app-middle component, which has own event emitter with name submit.

@Component({
  selector: 'app-middle',
  templateUrl: './middle.component.html',
  styleUrls: ['./middle.component.css']
})
export class MiddleComponent implements OnInit {

  @Output() submit = new EventEmitter<string>();

  constructor() { }

  emitSubmitEvent() {
    this.submit.emit("some data");
  }

}

template:

<div>

  <app-form></app-form>

</div>

And app component with template:

<app-middle (submit)="submitListener($event)"></app-middle>

Now, submitListener will be called

  • when submit on app-middle is called (wanted behavior)
  • when form is submitted, because native event bubble to the top ("parasitic" behavior)

I suppose, "parasitic" behavior is based on DOM event bubbling. I can stop it by event.stopPropagation() in submitButtonClicked handler, but if I forgot stop it, I get pretty ugly errors.

Generally, I consider this behavior quite dangerous. If I am not wrong, every event binding expression handler can be potentially called "parasitically" by native event from inner components. if has same name as any of DOM events (https://developer.mozilla.org/en-US/docs/Web/Events) And I don't talk about forward compatibility....

Same problem you can see here: https://bitbucket.org/winsik/submit-event-issue/src

Did you run into this problem? How do you name your @Outputs?

milanlempera
  • 2,203
  • 1
  • 17
  • 21

1 Answers1

36

I'm prefixing @Output events with the name of my components, which seems to work pretty well and to provide a consistent and clear convention which avoids the problems you describe. For example, suppose I have a component named, e.g. TurnEditorComponent -- @Output events might be named turnEditorChange, turnEditorFocus, turnEditorBlur and so on.

simon
  • 15,344
  • 5
  • 45
  • 67
  • 2
    I've been looking for a solution to this naming issue and I really like this one – mbrookson Nov 10 '17 at 12:36
  • 4
    **Simply prefix all events with "`by`", like "`byClick`"** (meaning an event resulted `by Click`ing something, which is Human-readable, like: `(byClick)="doSomething()"`). Furthermore (you may already use this one), **prefix all listeners with "`on`", like "`onClick`"**, Quite self explaining: `onClick() { doSomething(); }` or `(byClick)="onClick()"` (BTW, lint may forbid `on` as `@Output` prefix) – Top-Master Nov 09 '21 at 16:07
  • 4
    prefixing by "by" sounds cool. Prefixing by **"on" is discouraged by Angular:** https://angular.io/guide/styleguide#style-05-16 ("don't prefix output properties") – devaga Jan 20 '22 at 06:47
  • 2
    @devaga, he said prefix **listeners** (aka - the event handlers that consume the output events) with `on`, which is recommended in the style guide. – Jaime Still Jul 29 '22 at 19:04
  • I prefer `outClick` for the emitter and `onClick` for the handler. – Irfanullah Jan Jun 13 '23 at 13:16