Deep Dive on Ember Events
This is a modal window.
The media could not be loaded, either because the server or network failed or because the format is not supported.
Formal Metadata
Title |
| |
Title of Series | ||
Number of Parts | 27 | |
Author | ||
License | CC Attribution - ShareAlike 3.0 Unported: You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this | |
Identifiers | 10.5446/35710 (DOI) | |
Publisher | ||
Release Date | ||
Language | ||
Producer | ||
Production Year | 2018 |
Content Metadata
Subject Area | ||
Genre | ||
Abstract |
|
EmberConf 20184 / 27
3
4
6
8
12
13
15
16
18
21
22
23
25
26
00:00
VideoconferencingEvent horizonLinker (computing)Web pageComputer hardwareAreaMultiplication signComputing platformSoftware developerCASE <Informatik>ACIDSoftwareSurgeryEvent horizonTwitterMobile appMassSoftware engineeringSquare numberXMLComputer animation
01:02
InformationMobile appMassBitMultiplication signMenu (computing)QuicksortComputer animation
01:44
Menu (computing)Group actionVideo gameMathematicsCodeOrder (biology)Menu (computing)Computer animation
02:19
Menu (computing)Menu (computing)Source codeTracing (software)FlowchartResultantDataflowComputer animationMeeting/Interview
02:53
Event horizonWeb browserDOM <Programmierumgebung>Web pageCombinational logicPoint (geometry)Event horizonCodeMathematicsDifferent (Kate Ryan album)Object modelWeb pageWeb browserOrder (biology)Object (grammar)Computer fileMeeting/InterviewComputer animation
03:25
Event horizonSingle-precision floating-point formatData structureWeb pageNetwork topologyComputer fileHierarchyDivision (mathematics)Computer animation
03:46
Event horizonFunction (mathematics)Video game consoleScripting languageNetwork topologyProcess (computing)Default (computer science)Inheritance (object-oriented programming)Event horizonWeb pageTouch typingResultantInheritance (object-oriented programming)Default (computer science)PropagatorLine (geometry)String (computer science)CuboidRegular graphQuicksortCASE <Informatik>Video game consoleMobile WebElement (mathematics)Attribute grammarInteractive televisionFinite element methodBackpropagation-AlgorithmusComputer iconSet (mathematics)WritingComputer fileComputer animation
05:54
Event horizonAbstractionVideo game consoleGroup actionGame controllerLogarithmEvent horizonAbstractionString (computer science)PropagatorGroup actionRegular graphState of matterTemplate (C++)Forcing (mathematics)Connectivity (graph theory)Game controllerCorrespondence (mathematics)Computer animation
06:43
Event horizonIterationWeb browserEvent horizonAnalytic continuationCycle (graph theory)Multiplication signState of matterSource codeFerry CorstenPropagatorWeb browserStaff (military)Inheritance (object-oriented programming)Cartesian coordinate system
07:55
Inheritance (object-oriented programming)View (database)Physical systemEvent horizonFunction (mathematics)Element (mathematics)RootEuclidean vectorGroup actionCross-site scriptingEvent horizonMessage passingMultiplication signDirection (geometry)Point (geometry)Branch (computer science)Mobile appParameter (computer programming)Slide ruleElement (mathematics)Electronic signatureComputer fileQuicksortElectronic mailing listDifferent (Kate Ryan album)Cartesian coordinate systemRootFunctional (mathematics)Content (media)Source codeTime zoneOrder (biology)Network topologyExtreme programmingSystem callProcess (computing)Set (mathematics)Food energyCategory of beingTwitterAnalytic continuationCASE <Informatik>Fraction (mathematics)Template (C++)Graph coloringLattice (order)RoutingSocial classInverse elementComputer animation
10:52
RootElement (mathematics)Euclidean vectorFunctional (mathematics)Connectivity (graph theory)Element (mathematics)RootCartesian coordinate systemEvent horizonSocial classPoint (geometry)QuicksortSingle-precision floating-point formatSystem callMultiplication signRoutingPropagator
11:54
Event horizonQuery languageProcess (computing)Element (mathematics)Electric currentVideo game consoleInheritance (object-oriented programming)Web browserPropagatorNormal (geometry)System callLevel (video gaming)Event horizonInformationRootCartesian coordinate systemElement (mathematics)Mobile appContent (media)QuicksortWeb browserInheritance (object-oriented programming)Entire functionCycle (graph theory)Video game1 (number)Category of beingMathematical analysisIntegrated development environmentProcess (computing)Type theoryComputer animation
13:25
CodeSample (statistics)Event horizonDifferent (Kate Ryan album)Cartesian coordinate systemElement (mathematics)Group actionType theoryFunctional (mathematics)Mobile appRegular graphState of matterTemplate (C++)Context awarenessMappingKey (cryptography)Connectivity (graph theory)Algebraic closureText editorWordCoefficient of determinationVideo gameDefault (computer science)Scripting languageQuery languageCycle (graph theory)Computer animation
15:13
MKS system of unitsGroup actionFigurate numberEvent horizonDifferent (Kate Ryan album)CodeSampling (statistics)Group actionInheritance (object-oriented programming)PropagatorQuicksortMenu (computing)Interior (topology)Order (biology)CASE <Informatik>Category of beingComputer virusComputer animation
16:16
Event horizonGroup actionComputer configurationVideo game consoleGame controllerLogarithmComputer virusEuclidean vectorCodeSample (statistics)Event horizonException handlingPlotterPropagatorDifferent (Kate Ryan album)Inheritance (object-oriented programming)Group actionParameter (computer programming)Order (biology)Object (grammar)Interior (topology)AbstractionState of matterKey (cryptography)Electronic mailing listAlgebraic closureCodeElement (mathematics)Software bugMultiplication signConnectivity (graph theory)Functional (mathematics)SummierbarkeitCASE <Informatik>Line (geometry)Default (computer science)Right angleComputer animation
19:36
Group actionDivision (mathematics)Event horizonCodeMultiplication signOrder (biology)CASE <Informatik>AbstractionObject (grammar)Strategy gameQuicksortEvent horizonPropagatorGroup actionInheritance (object-oriented programming)Algebraic closureElement (mathematics)MassCartesian coordinate systemPoint (geometry)Right angleFreezingMereologyComputer animation
21:45
Mobile appConnectivity (graph theory)Web pageTheoryMultiplication signLevel (video gaming)Profil (magazine)Google ChromeDifferent (Kate Ryan album)Event horizonElement (mathematics)Computer animation
22:21
NumberComponent-based software engineeringVolumenvisualisierungEvent horizonRead-only memoryEvent horizonWeb pageConnectivity (graph theory)Mobile appTrailOrder (biology)State of matterSemiconductor memoryWordDiagram
22:56
Read-only memoryVolumenvisualisierungComponent-based software engineeringSemiconductor memoryEvent horizonWeb browserDiagramComputer animation
23:18
UsabilityConsistencyMultiplication signStrategy gameInformation overloadCausalityEvent horizonOrder (biology)InformationDecision theoryNumberWeb browserCodeSemiconductor memoryMobile appConsistencyComputer animation
24:11
Group actionElement (mathematics)Error messageCompilerComputer configurationBlock (periodic table)Event horizonEvent horizonElement (mathematics)Statement (computer science)Ferry CorstenCompilerFlow separationFunctional (mathematics)Semantics (computer science)Database normalizationError messageBitComputer configurationBlock (periodic table)State of matterWeb browserDifferent (Kate Ryan album)OvalCASE <Informatik>Game theoryComputer animation
25:54
Event horizonPredictabilityConsistencyEvent horizonSoftware bugWordCASE <Informatik>Presentation of a groupConsistencyCartesian coordinate systemPredictabilityException handlingPoint (geometry)Computer animation
26:41
InfinitySign (mathematics)Square numberBlogOrder (biology)Confidence intervalEvent horizonPoint (geometry)BlogFeedbackLink (knot theory)TwitterSlide ruleSquare numberMultiplication signExecution unitComputer animation
27:16
Linker (computing)Square numberAverageRSA (algorithm)Row (database)Coma BerenicesComputer animationXML
27:39
Block (periodic table)Data typeComputer animation
Transcript: English(auto-generated)
00:02
My name is Marie Chatfield. You might also know me as at Marie Chatfield on Twitter, GitHub, Slack, all the places.
00:25
And I am here today to take you on a learning journey all about events and Ember. So I'm a software engineer at Square where we make commerce easy. You might know us for our hardware that lets you take payments on the go or really anywhere. We also have a developer platform with APIs and SDKs, and we've got a ton of software
00:44
that helps our merchants run their businesses really easily. Things like appointments, invoices, payroll, and the vast majority of all of that software lives in this massive Ember app that we call our Square dashboard. And it's where I and a lot of other Ember developers at Square spend a lot of our time.
01:02
So a couple months ago, I was working with my team in that massive Ember app to add a new feature. And so the idea was that we had this button that you could click and it would open a menu, you could click it again, and the menu goes away, which is, you know, like really groundbreaking stuff here.
01:20
So we decided to show our users a little bit of extra information the first time they saw the feature because it was kind of new. So we decided to add a walkthrough tour. So this time, the first time they saw the feature, we would give them this popover with some information. It had a button that they could click, and it would advance the tour by opening the menu for them and then giving them a little information about what they could find there.
01:43
So the way that we implemented this was we had a tooltip div, and inside of that was our button that we were actually going to have users click in order to advance the tour. And then that was actually inside of the button that we wanted people to click to open that menu and shut it.
02:02
So I made one very small code change, and everything broke. So let's go ahead and take a look at the code change that ruined my life. That's it. That's the only thing that changed. So let's see what happens now.
02:21
The user clicks on the button to advance the tour. The menu opens, and then the menu shuts, which is not what I expected to happen. So this kicked off about 72 hours of me debugging madly. I mean, I was looking at stack traces. I was reading Ember source code.
02:41
I was making Ember twiddles. I was doing flow charts, like, on paper. Like, I was trying to figure out what in the world was going on. And the result of all of that investigation and research was that I realized that before I had been exclusively listening for events with Ember, and after I was listening for events with a combination of Ember and the native DOM.
03:03
At what point you might be thinking, like, wait, hang on, what is the difference between those two things, and how did that code change have such big implications? So let's back it all the way up. So what is the DOM in the first place? It's a document object model, and it's basically the API that describes how web
03:21
pages work. So browsers implement the DOM spec in order to actually turn just static HTML in a file to this living web page that you can interact with. And there's this really important data structure here that we call the DOM tree, and it's hierarchical data structure, and everything in your web page can be represented as a node somewhere in this tree, starting with the top-level document and then all the way
03:43
down to every single div and button. It's a node in this tree. We also have a concept of events in the DOM. This is an API that describes basically that something happened on the page. So usually this is the result of some user interaction, like a click or a key press or a touch event on mobile. And the DOM events API gives us a way to have our DOM nodes do something when an event is
04:07
triggered on them. For example, we can say that when a user clicks this button, I want you to log hello to the console. And so one of the easiest ways of doing this is to use the on event attributes in HTML, where we just say, for example, on click equals, and then we just write JavaScript
04:23
inside of a string, and then whenever the button is clicked, then that JavaScript inside our string is going to run. But maybe if we're doing some more complicated things, we don't want to write all of our JavaScript inside a string directly in line with our HTML. So we can also do things like, say, give that button an ID, and then somewhere else
04:44
in our file, use JavaScript, just the totally regular DOM APIs that come out of the box to find that element and then add a click listener. So that brings us to event propagation. This is a really important concept in the DOM, which is that every single parent of a node
05:02
that had an event triggered on it also has a chance to respond to that same event. And this is the sort of default behavior that happens. So if we have a parent and a child node, and they both have click listeners, if we click that child node, first its event listener will fire, and then its parents. And why we do this kind of makes sense.
05:22
If we think about, say, we have a button, and the button has an icon, and then some text inside of it. If our user manages to click exactly on that icon, we probably still want the button to fire, but we don't want to have to add event listeners to the button, to the text, to the icon, anything else inside of it. But there are some cases when we don't want this to happen, so we can always
05:43
call stop propagation on our event. In which case, when we click on that child node, its event listener will run, it'll stop propagation, and nothing else fires above it. So all of that has been just regular DOM event listeners, but what about Ember event listeners? So this is an abstraction that Ember provides on top of those DOM event listeners.
06:04
And it's pretty handy, it works a lot with the way that we kind of expect our Ember apps to go. So if we take our regular DOM event listener, we can make this an Ember event listener by using our action template helper. And specifically this is going to be in some handlebars file, and then in the corresponding component or controller, we're going to define an action, and maybe we actually want to use
06:23
our Ember state instead of just hard-coding a string there, we can do that. But notice here, we don't have access to that DOM event anymore, so how do we stop propagation? Well, Ember provides abstractions for that too. We can just say bubbles equals false, and then that'll stop propagation for us with
06:41
our Ember event listener. So now that we have this concept of DOM event listeners and Ember event listeners, how do these actually fit together in our application? Well when an event is created in your Ember app, first all of the DOM event listeners are going to fire, and then the Ember event listeners. So when we're looking at these DOM event listeners, we're going to start at the target
07:03
node, wherever that event first originated, we're going to cycle through all of its parents, and in every step of the way, we're going to see if there's a DOM event listener, fire it, if any of those stop propagation will immediately exit and don't continue. But if we make it all the way through our document tree, we'll start all the way back
07:20
over at that original DOM node, cycle all the way back up through all of the parents, this time looking for Ember event listeners, firing them, and once again if any of them stop propagation, we'll immediately exit. So the important thing to realize here is that when we're working with our DOM event listeners, it's actually the browser that is handling all of that event listener state
07:41
and calling those event listeners using our DOM APIs, and when we're working with our Ember events, it's actually Ember JS source code that is handling the state of all of those event listeners and actually calling them. So how does that actually fit together? So when you render content in an Ember application, you're probably normally thinking of the
08:01
actual things that you're writing in your templates, but all of that is actually rendered inside this root element. So this is a node that Ember itself initializes when it's first booting up your application for the first time, and Ember is installing DOM event listeners on that node that's going to kick off its own internal events process.
08:20
So getting your warning, we're about to dive pretty deep into the internals of Ember source code in order to figure out how this works, so if that is something that you really don't care about, feel free to zone out for the next five minutes, check Twitter, do whatever, and I will let you know when we're sort of surfacing back up to a reasonable depth and continuing on with the rest of the talk. So for those of you that are paying attention, there's this great file in the Ember source
08:43
code called event dispatcher, and it has this list of all of these different events that Ember cares about, and when the app is initializing, we call this function called setup handler on the root element with each one of those events. So let's say we're calling setup handler with the click event.
09:00
What we're going to do is we're actually going to add jQuery event listeners on the and those handlers are going to actually dispatch to the Ember event listeners for different elements in our app. Okay, I know some of you are probably thinking at this point, hang on, jQuery event listeners, I thought jQuery was optional. Yes, it is optional, but trying to get the branch of both if you have jQuery,
09:23
use jQuery, and if you don't, then do this other stuff on one slide is a little tricky. So just trust me that the one without jQuery does pretty much the same thing. It's just simpler to look at the jQuery example. But in the jQuery example, there's this extra argument that's passed that I hadn't seen before,
09:42
which is the CSS selector, which is a little weird. I'm used to just using jQuery event handlers that just pass a single thing. So let's take a look at that function signature. What we're doing is we're passing an event that we want to attach, a CSS selector, and then the handler function. So normally in jQuery, when you are adding a handler function to a node,
10:05
it's a direct event handler. And so the idea is when an event happens on that node, you call the handler directly one time. But in this case, we're working with a delegated event handler, so we also have the CSS selector that we're passing. So we attach our handler to some node somewhere in the DOM,
10:22
and then when an event happens on one of the children of that node, eventually that event is going to propagate all the way up to the node where a handler was installed, at which point we're not going to call our handler function directly. Instead, we're going to find every single child in that path that matches a CSS selector,
10:44
and we're going to call our handler function once for each of those, which is pretty cool. That's why it's delegated. So if we look at our Ember example, we can see that we're attaching a click listener to the root element. We have this EmberView class that we're going to be looking for.
11:00
That's a class that is added on every single component when it's rendered into the DOM, and we have this handler function that's going to handle clicks on components. So we attach this handle component click listener to our root element when the application is first initialized, and then when a button somewhere inside of our application is clicked,
11:20
eventually that event is going to propagate all the way up to our root element, at which point we're going to find every single element sort of in that path that has this EmberView class on it, and then we're going to call our handler on each of those events, and this event handler is going to say, I'm looking at a component. Does this component have any click event listeners that are attached with Ember?
11:42
If it does, go ahead and call that, stop propagation, do whatever, and then just keep doing that for every single other component in the path between the target where the event originated and our root element. And then the really cool thing about delegated event handlers is that you can use the same handlers throughout the entire lifecycle of your app,
12:02
no matter what content you're adding and removing from the DOM inside of your app, because the actual path of elements that you are calling your handler on is calculated when the event happens and not when you install the handler. So you can reuse the exact same handlers throughout the entire lifecycle of your app without adding any new ones. So if you were zoning out, feel free to come back, take a breath.
12:24
We're sort of surfacing back up to like a normal level of depth, and we're going to take a look at what happens when we actually click something in our Ember application. So let's say we have our child node and our parent node, and we actually go ahead and handle that click. The first thing we're going to do is the browser
12:40
is going to look for any native event listeners on that child and call them, propagate up to the parent, look for any DOM event listeners there and call them, propagate all the way up to our root element where it is going to find the delegated event listeners that our Ember application installed when it was initialized, and we're going to kick off our Ember events process.
13:02
So now we're going to go start back down at that child node, look for Ember event listeners and call them, propagate up to the parent, look for Ember event listeners and call those. So the really important information here is that our DOM event listeners are always called before our Ember event listeners, which means that your Ember event listeners
13:21
are never going to be able to stop propagation to DOM event listeners. Okay, so it seems like the difference between Ember event listeners and DOM event listeners is pretty important. But how do I know which one is which when I'm actually adding event listeners in my app? So let's take a look at some different ways that you can attach event listeners in Ember.
13:43
Probably the most straightforward way of adding a native DOM event listener is to just add one yourself somewhere in the lifecycle of your application using jQuery, using regular DOM APIs. This one looks like a native DOM event listener, so it kind of makes sense that it is. Here's the most likely way
14:01
that you're going to add DOM event listeners to your app. You're going to use that on event equals syntax in HTML. This is confusing because notice that that Ember template helper is showing up here. But this is creating a closure action. What you're actually doing is wrapping all of the Ember state available in that context into a pure JavaScript function,
14:20
passing that off to the DOM, and the DOM is just going to handle it normally. Now this is extra confusing because you can create Ember event listeners by just getting rid of that on event equals syntax. What you're doing here is you're using this element modifier syntax where you're just dropping that action template helper in the middle of a DOM tag.
14:41
And that's what Handlebars is going to do to actually add event listeners using Ember event listeners. And the same is true if you just override the type of event that you're looking for. By default, it's click, but you could do anyone. That's still an Ember event listener. If you pass a function to a component that has a special name like click or key press
15:01
that maps to one of the DOM events Ember cares about, you're going to create an Ember event listener. And the same is true if you do that in your JavaScript instead of in your template. Those are all Ember event listeners. So now that we understand some of the difference between Ember event listeners and DOM event listeners, let's see if we can go back
15:21
to my original buggy code example and figure out what went wrong. So we can see once again that we have that inner child action that is going to advance the tour by sort of opening the menu and it's gonna stop propagation. And then we have our parent action that is going to actually toggle the menu. So when we click on this enter button,
15:43
the first action that fires is the parent because that's a DOM event listener. So that is what is going to open our menu and then we get down to our action that is going to advance the tour by closing the menu and that's going to stop propagation. So nothing else will fire after that.
16:01
So one of the easiest ways to fix this is just to make that parent one into an Ember event listener in which case they're going to fire in the order that we expect. So the first thing that will fire in this case is our child action that's going to advance the tour and it does successfully stop propagation. So everything works. Great, right?
16:20
Except there's actually a lot of other tricky situations that you can get into when you're mixing Ember event listeners and DOM event listeners. So we're gonna do a pop quiz. Okay, get ready for it. It's time to test your knowledge. We're gonna run through some different tricky scenarios and see if you can figure out what the bug is and how to fix it.
16:40
So the first one, I stopped propagation with my listener but the parent is still firing. Okay, so in this case, we have this parent action that should not be firing and then inside of that, we have an action that's going to stop propagation, right? So when we click on that innermost component,
17:00
the first thing that's going to fire is in fact that child event listener because it's a DOM event listener. Unfortunately, it's a DOM event listener and we're trying to stop propagation using an Ember abstraction. Your Ember abstractions are meaningless to the DOM. It does not care. It is not going to stop propagation. That parent is still going to fire.
17:20
So we have a couple different ways of fixing this. We could just make this into an Ember action. So because these are both Ember actions, they are going to fire in the order that we expect. So the first thing that's going to fire is the one where the click actually happened. That does stop propagation, so this works. Alternatively, we could go all in
17:40
on our DOM event listeners. So in this case, what we could do is actually just stop propagation within our handler function. We're going to have access to that original DOM event and we can just call stop propagation on it there. So once again, that inner child action is going to be called first because it is a DOM event listener. It's going to successfully stop propagation and the parent won't be fired.
18:02
Okay, so what about this case? What if my event listener is being called but the event object is undefined? It's kind of hard to stop propagation on something that's undefined. So this case, our handler is just going to log out all of the arguments that it gets. So let's first attach it using our element modifier syntax.
18:21
This is an Ember event listener, right? So when we click on this action, we get nothing. No DOM event, bummer. So if you are using this element modifier syntax and you want to stop propagation or prevent default, you have to use the Ember abstractions.
18:40
You do not get access to that original DOM event. Okay, but what if I pass it as a click function to a component? What do I get then? You do have access to the original DOM event when you are passing things to a component using one of these specially named click handlers
19:00
or key press or whatever, which is cool. But hang on, what if I want to pass some extra state in my action and do something else with my closure actions? Do I still have access to the DOM event? You do. It's just appended to the list of all the other arguments that you pass in. Okay, so let's take a look back at all of those different code examples
19:22
that we had about how to attach clicks. We can see that every single one of them, except the element modifier syntax, does have access to that original DOM event and it can do things with that DOM event. So that's kind of important to know. Okay, are you still with me? Still there hanging in?
19:41
I know it's after lunch. I have another buggy code example for you and this one is a doozy. I added a listener. It's not firing no matter how many times I clicked it and I clicked it a lot. We start out with this parent action that we are expecting to not be fired.
20:01
Inside of that is an action that's going to stop propagation and inside of that is something that's just going to say hello. So we expect that if we click on that most, innermost action that we're gonna say hello, right? Unfortunately, the first thing that fires is our DOM event listener, which stops propagation. So we don't do anything else at this point,
20:22
including saying hello. So we could just make this into an ember event listener too, in which case our actions will fire in the order that we expect. So if we click on that innermost button once again, we're going to say hello and then we're going to stop propagation, except we're not actually going to stop propagation,
20:40
are we, because we were expecting to get a DOM event object. That's gonna be undefined because we're using element modifier syntax so that parent action is going to fire. So if we really want this to work as expected, we're going to have to use our ember abstractions and say bubbles equals false in order to correctly stop propagation so that we say hello
21:00
and then actually handle the click and stop propagation the way that we expected. So the takeaway here is just pick one event listener strategy and stick with it. I don't really care which one you pick. I think they both have pros and cons. So for example, when I am working in this sort of massive monorepo of ember that I use at work, a lot of times I do prefer to use ember event listeners,
21:22
just because I know that if I stop propagation, it's less likely to wreak havoc if other people are using what other kinds of event listeners that they're using. But in my personal projects, I tend to prefer to use DOM event listeners because I find that closure actions are just a lot friendlier syntax. I like the way that they look and I just find them a lot easier to work with.
21:41
So it doesn't really matter which one you pick, as long as you just pick one. So if you have to pick one, I'm sure some of you are wondering, what about performance? If I just have to pick one strategy, I want the one that's the fastest, the most performant, gonna make my app really snappy. So I saved your click and I tried adding up to 10,000 components on a page at a time
22:02
where each of the components used a different kind of click listener. Once with a DOM event listener, once with the element modifier listeners, and once with component listeners. And I did some very unscientific profiling in Google Chrome on my MacBook Pro, so just take it with a grain of salt. But this is more of a high level picture.
22:22
So as you might expect, when you are using DOM event listeners for every one of your components, if you add 10,000 components to a page, you add 10,000 DOM event listeners to the page. But if you're using Ember event listeners, which use the same event listeners from the app to delegate out to Ember event listeners,
22:40
you actually use only about, I think it's 32 in order to render 10,000 components. So that's a lot less event listeners in the DOM. But hang on, if the DOM's not keeping track of that state, surely Ember's keeping track of that state. So am I using more memory? Yeah, you are. You are using more memory. It's, honestly, I wouldn't consider it
23:01
a horrendous amount more memory for the browser to handle. It's kind of a trade-off here, but you are using more memory when you're using Ember event listeners. Okay, what about speed? If Ember event listeners are delegated, does that mean that it's gonna take longer for my event listeners to fire? No, they run at about the same.
23:21
You really don't have to worry about the speed for the event listeners to actually fire. Okay, so are one of these strategies more performant? It's kind of hard to tell, at least for me. So delegated event listeners were added at a time when adding a bunch of DOM event listeners to the DOM did cause serious performance problems. That's why delegated event listeners came into popularity.
23:43
Now most modern browsers can actually handle that number of DOM event listeners, but they can probably also handle that extra memory overload. So I would say that there's not really a clear winner in my mind based on performance in most modern browsers, but really you have the information that you need in order to make a good decision for your app.
24:01
And honestly, I would say that you should probably pick the event listener strategy that's going to help you write the most clear, correct, and consistent code. And just save yourself the pain when you're debugging. Okay, here's a feature request that's kind of interesting. What if you want to optionally add a listener?
24:22
So let's say we have some element and it's got an active state and an inactive state. And when it's active, we want to have you be able to click it, and when it's not, you don't. So how do you do this? In a perfect and beautiful world, you could say something like, if it's active, then I want you to add this event handler, but you can't do that, you get a compiler error.
24:42
You can't use the if statement in that element modifier syntax like that. So how do you do this? Well, honestly, your best option is to just use semantic HTML. Don't try to reinvent the wheel. We have things like buttons that you can do, and you can pass them a disabled state. And then the browser will take care of making sure
25:02
that those events aren't actually fired and in showing you the correct disabled state. That's really what you're trying to do, is reinventing disabled styling on a div. But if for some reason you really can't use semantic HTML, what you could do is just split everything into separate if blocks and have it be very clear
25:21
exactly what you're doing in each of your different states. But that can get a little redundant. You could just exit early from your handler if you're not active, so you always attach it, you just don't do anything if you aren't supposed to. Or you could just use a DOM event listener. Because you aren't using that if statement
25:42
and an element modifier syntax in this case, what you're actually doing is you're optionally passing a function to the DOM, and the DOM doesn't care if that's null. That's totally valid handlebars. So that is a little bit easier to use than Ember event listeners. Just a quick word of warning here. This is actually what I was doing
26:01
when I caused that bug that started this entire presentation. So if you are using Ember event listeners elsewhere in your app and you're trying to optionally add an event listener, just be careful if you decide to just switch it up and use a DOM event listener just for this one case. So the really important takeaway here that I want all of you to remember is that DOM event listeners always, always,
26:21
always fire before Ember event listeners. There are no exceptions, this always happens. And the second thing is that I really want you to remember that consistency and predictability are so important when you're handling events in your application. This is really what is going to save you a lot of pain when you're implementing and debugging things.
26:41
So I hope at this point that all of you have all of the knowledge that you need in order to implement your event listeners with confidence and debug with clarity. If you have any feedback on this talk or any other questions, once again, I'm at Marie Chatfield on Twitter. You can find links to the slides for this talk at mariechatfield.com slash talks.
27:00
And if you're interested in reading the original blog post that I wrote after that 72 hour dive into Ember events that eventually was turned into this talk, you can find that on the Square Corner blog on Medium. Thank you so much for your time. I'll see you next time.