 All right. Hello and welcome everyone. My name is Jay Bugha and I'm a UI engineer at HashiCorp. I work on the Nomad team. A quick fun fact about me is that I'm really new to web development. I learned how to code about three years ago, and I have less than a year of experience with Ember. I think that's an important story to mention in the very beginning. Today, I am covering element modifiers under the hood, and what I think the purpose of this talk isn't to make you some expert overnight. Instead, my goal is, I want to show you as someone who's new to Ember, here's how I think through problems, and what mental models I use to get myself unblocked. I think that's a very important thing, because when I first started developing, things started off and they were like a breeze at first. My tickets would be super well-defined and they would be well-scoped. It'd be like, hey, can you change the copy on this one view that we have? Could you give this component to makeover? Maybe we're reordering the markup that we have, and I was doing great at that. But then when there was a bigger challenge, like, hey, can you render a template based on authorization, or could you implement a bunch of special requests? Maybe have this component render outside of the normal DOM tree, and then make sure that it closes only when these events happen, and not these events. And then I would get stuck. And basically, the issue was that if I had documentation or tutorial, I could easily knock it out. But if it was anything beyond that, I would be stuck for a while. There's a lot of things that stump me on a pretty regular basis. I've inherited a code base of more than 70,000 lines of code that I didn't write, and the majority of it is still in the Ember classic pattern. So if I need to upgrade to Octane or I was up on Ember 3.20 up until maybe about two weeks ago. Now I've gotten to the latest version, but upgrading Ember or learning how to work with certain add-ons, those types of things were very difficult for me because I didn't have an understanding about how Ember was working. And not having that understanding meant that I would have to go to someone else for help. And I almost view it like there's this very big chasm between where someone like myself, a beginner product engineer, has to start solving bigger problems. And so I say this thing where in today's world, it's never been easier to stand your application up. Like building your app and getting something working is super fast today. But maintaining the application itself, that's where a lot of the challenge occurs. And being able to maintain an application is where I don't think that there's a lot of resources. And this talk is supposed to go through my mental model of how I think through that. And as I think about crossing this chasm or thinking about these situations where I'm starting to be attacked by things that I don't necessarily understand, I think about it very similar to like dragons that are attacking my city here. And when I think about dragons that are attacking my city, I think that I have a few options here. My first option is I can escape, which is the case of I can have one of my coworkers who are super knowledgeable come bail me out. That's one thing I can do. Another thing I can do is I can defend. I can choose to not upgrade any of these patterns that I'm seeing. I can just stick with the classic model. I can just stick with the pattern. I see somewhere else on the code base. Or my third option is I can learn how to use my tools and master them so that I can attack these dragons. I think usually it makes sense to play defense. I think a lot of times that's what we wanna do because we know that there's a lot of business value to technical debt and the fact that it's working in production right now. So why bother breaking it? Well, one of the things is when dragons are attacking and if all you do is immediately go into defense mode and you're not attacking them head on, those dragons just keep getting stronger. Or in my case, technical debt continues to accrue. And now it may get to a size where I always need to ask someone else to bail me out. Or it might even get to the size where the person that needs to come bail me out and is capable of bailing me out can no longer bail me out because the situation has gotten too bad. So that's why in this presentation, I'm really gonna focus on, how do I think through these things as I'm learning how to attain these dragons? This is my way of thinking about things. By no way is this perfect. By no way is this absolutely accurate. This is my system of thinking and how I solve the problems that I deal with on a regular basis. And some of it may not be absolute perfect to spec. So I just wanna keep that in mind because I'm a beginner and I'm a work in progress. But I think about things in three M's. So first, I wanna understand the model of what I'm looking at. And so in the case of element modifiers, I think we wanna go all the way up to glimmer, be able to understand glimmer just enough in context. The reason behind that is, when I'm going through Splunking because I just got through a bug, I'm wondering where should I look? When I understand the boundaries of what something does and doesn't do, that tells me how far I should be looking. That tells me what keywords I should be using. So that's why we come all the way up to the model. Have a solid understanding of it, but know that you're not supposed to be an expert on this stuff. Next thing is the mystery, the actual element modifier itself. What can it do? What can it not do? What are some things behind the scenes that we don't see? What's that mystery piece? Once I understand that, again, that's gonna tell me the boundaries of where I should be Splunking. And then lastly, there's the actual method itself saying, hey, I have some business requirement. How does that kind of compile down to what I know as a developer? What tools should I be looking out for? And that's gonna be that last step there. So my intention and outcome for this talk, there's a fourth M word that I really just don't like. And it's the word magic. And when I first started working in Ember or even like in web development general, if I tried to understand something that was beyond my level, everyone would just keep telling me that it was some magic. But the more you say the word magic, the more impositions are my feel. Because if I can't understand the magic, but it seems like you're able to, the senior developer, seems like you're a magician and I'm never gonna be there. Like I'm just gonna be someone in the crowd. So I do think that this is a word that I want people to stop using and to start explaining things in terms of JavaScript or in terms of what we know as developers so that it can be communicated in some way. Next, I wanna bridge the gap between product and infrastructure engineers. I view product engineers as someone who gets, you know, a set of user stories. They work with some business stakeholders and they build an application. Infrastructure engineers are working with the APIs that we have and they're thinking about, you know, they think a little bit about how browsers work. They might think a little bit about how hardware works and they definitely do think about how software fits into the mix here. Now, increasingly I do think that crossing that chasm of being able to work with different dependencies, build tools and all those other things that are gonna help you become an intermediate to advanced developer requires you to start thinking like that and you can't just have like that straight up product hat anymore. You have to think about how to solve some of those other issues even if you're not incentivized to solve them. Otherwise those dragons are gonna keep getting bigger. And then my third point is hopefully I can inspire and empower you to contribute to open source. Whether you're gonna contribute to documentation or whether you're gonna fix some low or high level bugs. I do think that if we're all using open source software we should try to contribute in some way, shape or form by helping with documentation, teaching or contributing to the APIs themselves. So that's what my intentions and outcomes are. So let's get into it. We have our first dragon here and our first dragon is Glimmer. So one of my biggest pet peeves when I was first learning Ember was that I kept seeing Glimmer when I was learning Ember and when I asked about what Glimmer was people said, don't worry about it, it's just magic. And that didn't help me at all because then I was stuck thinking, wondering whether my bug was related to Glimmer or not. So understanding Glimmer with first principles is important. I think about Glimmer with these first principles in mind. Number one, it compiles our templates into a JSON blob and its goal is to reduce over the wire size. I'll dive more into what that looks like when I cover what happens when we actually go to the browser. Number two, it's architected like a virtual machine and it has two main subsystems that we wanna keep track of. Number one are references. So anything that we're pointing to that isn't like a static value, it's a dynamic value. Number three, revision tags. These dynamic references, are they up to date or are they not up to date? And if they're not up to date, then we need to make sure that those values get recomputed. And then the third thing that we do is we render some DOM, right? So where we think about Glimmer is, it's helping us go from this stage of we've fetched information from our website and now we need to go paint what's on our screen. So in our browser, we have this client server paradigm. I'll go to twitter.com, I'll ping the Twitter server by way of just typing in twitter.com which makes that request. Twitter.com sends us some information back. They can send this information back in a few different ways. One way, the very popular way before single page applications came about was sending back a string of HTML which then gets parsed into a DOM tree and then paint it onto the DOM. Now a lot of front end frameworks are sending JavaScript over the wire but if we're sending JavaScript over some string of HTML, now we have a very expensive parsing operation. So the beauty of what Glimmer is doing is it's finding that happy medium between being able to parse that string of HTML or interpret what that JS is by way of making sure that we're just getting this huge JSON block which drastically reduces that size and it's super easy to read. So this is where Glimmer is helping us out. And I think it's pretty important to know what Glimmer is doing because now you feel confident about one part of the stack. Once you have confidence growing in one area, you start to have confidence that we'll build in other areas. So let's continue building out this mental model of what's going on in Glimmer. There's probably about six stages that I think about. Stage one where all of our handlebar files get compiled down in this pre-compile stage to this intermediate representation where we're gonna start to form this abstract syntax tree of what our DOM is going to look like. It'll be validated to make sure that we're sending back what we'll convert into a valid DOM later on. Then we'll have our build time compiler which will then create that JSON blob that I was referring to earlier. And then we're gonna have this module table where our template helpers and our element modifiers live that we're gonna reference. And then lastly, we're gonna paint our DOM and whenever we have updates happening, we have this runtime compiler that we'll be making sure that we're triggering the correct operations. And that's another big step that we need to understand about Glimmer with respect to beginner to intermediate level. Now that brings us into our next subject which are element modifiers, right? So our element modifiers are Ember's way of giving us DOM manipulation rather than us manipulating the DOM on our own which is something we probably don't wanna do. We wanna tap into Ember in order to do that. And using element modifiers, we number one, we attach event handlers to our elements. Number two, we can fire callback functions that are associated to the life cycle of an element. I'll tie into how we're able to do that in the next slide. Number three, we're gonna be able to manipulate element properties. So imagine I wanna dynamically change the attributes of the elements that I'm working with. Number four, I may wanna communicate with other elements inside or outside of the component that I'm working in by way of having a reference or being able to just attach an event listener to the entire DOM itself, which is what, I think some other Ember add-ons like Ember on outside click modifier, it's able to do something like that. In plain English, I think the big thing for beginners like myself is that if I wanna do something that's JavaScript-y inside of my template, I'll reach for an element modifier if I need to manipulate the attributes of an element dynamically, or if I need to fire off some side effect after alongside my events on some type of input event, whether it be some mouse events or an input event like the key down or keystroke. And then I'll use a template helper in the event I wanna fire off some custom JavaScript logic that's gonna yield out a property. Maybe I wanna display a property in its correct date format. I may be able to just use a quick template helper in order to do that. So that's what an element modifier is and the types of things that it helps us do. How are they created? So Ember has exposed this API for working with managers that we don't need to touch. This is the modifier manager, but I think the important thing to know is that we have this manager pattern and the manager pattern is when we have an object that's responsible for coordinating the lifecycle events for its underlying property. And we have a lifecycle with element modifiers that we can tap into. We have its creation. So when it actually is being registered into our application, when once it's registered into our application that allows us to tap into Ember's dependency injection system. Then there's when we actually invoke it or install it once the element is painted onto the DOM. There's what we do when any of the properties that we're relying on. So maybe arguments that we've passed into our element modifier update. And then of course, if that element is being removed off from the DOM, we wanna make sure to destroy any listeners we have and avoid any stale closure that we might run into. If we wanna create our own modifier, Ember has released a high level wrapper around that low level API that I just talked about with the modifier manager and the modifier itself. So why don't we take a look at what that looks like right now. So at a glance, we see that we're importing from another module and there's a function and we have this higher order function of a modifier. It's gonna take a function as its parameter. And that function itself, this callback function that we see being executed here, that function itself has a function signature where it can take three inputs. The first input that it's guaranteed to take is the element that it's going to be attached to based on whatever reference we currently have, which I think is very important to make sure that we're working with an element that's actually on the DOM. Next, we have positional arguments. So it's arguments that would be in a particular order that do not have a name. And then it could take a third optional parameter of named arguments that we may wanna use later on. And then this function itself is also a higher order function in the sense that it returns out a function on its own. That function that it returns out is what will be fired once we hit the destroy part of the life cycle. So this is whenever we're planning to do some cleanup effect. And we wanna do a cleanup effect in the event that we have something we're subscribing to. So we're subscribing to an event by way of an event listener. When it's time to tear down, we wanna make sure to remove that so that we don't have those listeners just hanging around everywhere. All right, so that's like the quick way to understand that. So now we've just gotten through two of our big models here. First, we understand the model of where Glimmer fits into the mix. Now we understand when we wanna reach for an element modifier, what API is gonna help us use it, and the signature of the function that we're gonna use to go ahead and create that API. So that's awesome. So now we have our final dragon. This is dealing with business requirements. This is usually the place where I normally wanna give up because I can understand how things work, but then I have all this code that I need to deal with. And in this case, this is why you wanna have a very strong understanding of the model and the mystery of the APIs that you're using so you know what your best solution is gonna be and how you can get to that optimal solution. So in our situation, we're gonna try to create our own accessibility modifier. And there's a quick note that I wanna make is that I am probably only one to two Google searches ahead of you on understanding accessibility. Up until this talk, I had only thought about accessibility as enabling screen readers and I was totally wrong. So there's two quick pieces that I wanna share. So number one, sometimes the apps that we're making are gonna end up turning into more of an obstacle for folks than a convenience for other people. And I do think that later on, you're gonna see this amazing presentation from Zoe about space jamming accessibility and you're gonna be able to say, wow, this new website doesn't seem as if it's as convenient as the old version of this other website and they'll walk you through why that's the case. So I think that's one important note to have. The other important note is that when we talk about accessibility, we're not just talking about visual accessibility. Sometimes it can appear in motor and cognitive limitations as well. If you wanna learn more, there's tons of resources at W3C. So you can go to w3.org forward slash W-A-I or you can click that full link right there. You'll see a full guide for developers and you'll even see tutorials on how we create certain very common UI elements that all come together. So the example we're gonna work with today is gonna be creating a more accessible dropdown menu. That's what we're going to try to create. So the way that I'm doing that as someone that's super new to development is I'm gonna turn this into a user story. So as a user with motor limitations, I'd like the dropdown menu to stay visible long enough so that I can read and select the dropdown menu item. And an acceptance criteria that we have for this is that our dropdown menu should stay open for about 0.8 seconds. I don't know where I got that number from. I may, maybe I just picked it because it was a memorable number to be honest rather than one. So now that is our user story. So let's get to our demo application now, all right? I'm gonna exit out a full screen and here we have our demo app. And this demo app is made to be, you know, just what the nav bar of like another Ember agency would look like. And so once we come over services, we see that there's a few other pages that show up underneath here. But the second I stop hovering over this goes away which I'm not fast enough to do that or, you know, I might have a little bit of a shaky hand. So how can I do that? So now let's come over to our actual application. And one of the first things that we're gonna wanna do here is we're gonna want to install Ember modifiers. So let's go ahead and do that. I'm gonna kill this server first and I'm killing it because once I add an Ember package that's like, it's normally like a build time concern. So I'm gonna go ahead and install this. Okay, so I'll say Ember install, Ember modifier. And I'm pretty sure that is the case. It looks like we already have this installed thankfully. I think I probably should hit that pause button real quick. All right, great. And so now my next move is I'm gonna go ahead and create a brand new modifier. And so the way that I'll do that is I'll say Ember generate modifier and I'll call this modifier hover. And so now let's think through our solution real quick. So I have, you know, I have this property that when I hover over this, we'll start to show the list that's underneath it. And so it looks like, you know, if I take a look at this CSS that whenever we hover we're gonna show this property. Instead, we may wanna turn that into some CSS class. So that's how I'm thinking about creating this modifier. And so let's come over here and let's write a quick modifier for ourselves. So the first thing that we're gonna wanna do is we're going to want to add an event listener that will hook into our mouse over as well as our mouse out. And so I'm gonna just use what we would see from W3C on how they would go ahead and solve an issue like this. So we're gonna add this event listener and this event listener is going to happen on mouse over right. And now let's go ahead and let's create our callback here. And so we will add to our element class name. We're gonna change this a little bit from has sub menu to also have this open property. And then this will also mean that we need to change some of our CSS. Also gonna wanna clear our timer. Amazing. And now we'll probably have this second element modifier here or this event listener for what's gonna happen on mouse out. And this will remove that name out for us so that we don't need to worry about it, but we're gonna do that on a timer. So the new suite. Now let's come over here. Let's get this actually into a timeout. Okay, so timeout, this will be some function here. And we will do that every 800 seconds or every 0.8 seconds. This looks like this work just fine. This probably just needs a semi-colon or does it need a comma because that's over. Okay, sweet. This is probably just an issue with my linter yelling at me. And all right, sweet. And now let's make sure that when this function returns that we're removing these. So let's get two of these event listeners. So comment.remove event listener and let's do this first one on our mouseover. And then of course we'll have this effect run. And then let's go ahead and do this once more. Mouse out. Okay, sweet. And now let's just make sure that these remove these. Sweet. And I'm pretty sure if I just run yarn lint fix after saving this that this file will look just fine. All right, amazing. And now we probably just have one more change to make here to make sure that we factor in for our open class. And now we'll add this into our template where it's needed. So we can add this modifier right into here. We just need to make sure that, you know that our element modifier has registered itself. Okay, it looks like this isn't registering just yet. Let's debug what the case of that could be. My first guess is that this is occurring because we just need to go ahead and rebuild. Let's give this a rebuild. Okay, yep. And all we needed to do was trigger that rebuild. So now we'll hover over here and we will move over and we see that this is open for about a good second here. So now there we have it. All it took was creating this element modifier right here and then using this directly in the element space that we have available. Now, of course, this could be refactored a little bit so that this could be more generic, that it can be a little bit dynamic as well. And I don't want you thinking that, oh my gosh this was such a long walk for a short drink of water because although it does feel like it was a long walk for a short drink of water what I do think is super important is that we need to be able to learn how to tame the dragon that you're dealing with. And so my system for going about doing that as a total Ember Nude is being able to say, okay well, if I have this business requirement well, how do I do X in Ember? So how do I fire a callback after the user takes some action in Ember? Well, now I know the answer to that is an element modifier. And if I go one step above that to say, okay well, what's above an element modifier? And I start my understanding saying, hmm what do I need to know about Glimmer that is in the context of an element modifier? Now, what do I need to know about element modifiers and how they work one level deeper than what I would do maybe akin to what a library author would have to know. Then my job becomes a lot easier because now I know where to look to debug I also know how to start dealing with some of the larger issues that I'm facing with. And instead of retreating or trying to escape the city I still feel confident to attack that dragon which allows me to feel like I'm beginning to master Ember that I'm much more autonomous and that I do have a greater sense of purpose. So hopefully that'll allow you to do the same. I wanna leave you on one note here. You know, and I said the same thing at Emberfest which is when I was first getting started learning was very difficult for me. And I do notice that a lot of people do read the RFCs and there is a very good RFC culture here which is pretty amazing. But when you read, you read to collect the dots and then when you write out into the world you're able to connect the dots. So I do think it's super important to make sure that you're contributing back whether it's a blog or a conference talk to explain how you're thinking about these types of issues from your perspective because it'll really help a beginner like myself. And then my last note here, again, my name is Jay Bugga, UI engineer at HashiCorp and one big thing that I'm really gonna try to do over the course of the next year is create a free course on UI patterns for understanding glimmer. And then hopefully eventually one day down the line I'll have my own Ember course. But that's down the line. Thank you again, everyone. Appreciate everyone sticking through all the way to the tail end for this. All right, have a good one.