I was reading Angular 2 documentation where I found:
Passing the $event is not a good practice
Typing the event object reveals a significant objection to passing the entire DOM event into the method: the component has too much awareness of the template details. It can't extract information without knowing more than it should about the HTML implementation. That breaks the separation of concerns between the template (what the user sees) and the component (how the application processes user data).
For some reason I can't exactly fit my head around what it says. Seems like there are no explanation available either anywhere.
Can someone explain the exact meaning of this in simpler terms (with an example, if possible)?
The $event object often contains information the method needs, such as a user's name or an image URL. The target event determines the shape of the $event object. If the target event is a native DOM element event, then $event is a DOM event object, with properties such as target and target.
In Angular 8, event binding is used to handle the events raised by the user actions like button click, mouse movement, keystrokes, etc. When the DOM event happens at an element(e.g. click, keydown, keyup), it calls the specified method in the particular component.
Angular includes $event that contains the information about an event. The type of $event depends on the target event, e.g., if the target event is a native DOM element event, then it is an object. A component should define the onShow(event) method where the type of the parameter can be KeyboardEvent, MouseEvent, etc.
HTML DOM events allow JavaScript to register different event handlers on elements in an HTML document. Events are normally used in combination with functions, and the function will not be executed before the event occurs (such as when a user clicks a button).
Look at the examples the docs already provide for before and after:
@Component({ selector: 'key-up1', template: ` <input #box (keyup)="onKey($event)"> <p>{{values}}</p> ` }) export class KeyUpComponent_v1 { values = ''; onKey(event: KeyboardEvent) { this.values += (<HTMLInputElement>event.target).value + ' | '; } }
Here the component has to know that the event has a target, which is an input element, which has a value. Now v2:
@Component({ selector: 'key-up2', template: ` <input #box (keyup)="onKey(box.value)"> <p>{{values}}</p> ` }) export class KeyUpComponent_v2 { values = ''; onKey(value: string) { this.values += value + ' | '; } }
Here the template is responsible for extracting the correct value from its own structure, and all the component knows is that it's getting a string. Now imagine:
You need to change the input
element to a select
, to restrict the range of inputs. What has to change in each version? Just the template, or does the component have to change too?
You want to test the handling method. How easy is this for each version? Can you just pass in a string, or do you have to build an event with an element of the appropriate structure?
This is what separation of concerns really means - how far does a change propagate? How much does each piece of your system need to know about the other pieces to continue working? Per Wikipedia, for example:
Of special value is the ability to later improve or modify one section of code without having to know the details of other sections, and without having to make corresponding changes to those sections.
However, as snorkpete suggests, note that the reservation around passing $event
to component methods only applies when $event
refers to DOM events. In the case where you're using an EventEmitter
to raise your own events, $event
will (most likely) be an object from the business domain, and is perfectly fine to use as is.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With