 My name is Brenna for TED Talks, where we write a lot of our internal apps and tools. In Ember, we are looking for Ember Dev, so come talk to me if you're interested in that. I have a feeling that some of the code might be hard to read, so there's a link to my slides available. It's talks.brenneobryan.com slash ember-select if you wanted to follow along. Okay, so hands up. Who's built an Ember app? Before. A lot of hands. Awesome. Who has used the select element in an Ember app before? Okay. Now keep your hand up if you have been frustrated by the select element in Ember before. Right. A lot of hands, and I'm keeping mine way up high, because when I started out with Ember about a year ago, this was the bane of my Ember existence. It haunted me from project to project, and consistently gave me a lot of troubles. So about a year ago, this is how you did a select element in Ember. It is a built-in view that did a little something like this, and it did magic, and made a select for you. So magic can be really good a lot of the times, where it reduces the overhead that you as a developer need to go to, to do common tasks. But I think we need to also be aware of magic sometimes. Basically it's great when it does what you want, and then when it doesn't do what you want, it's extremely frustrating. So one of the first things that I found really difficult to deal with with the Ember select was the fact that it was two-way bound by default. So what do I mean by two-way binding? This is a simple example where, say, in your select element, the value in the select is reflected in the UI elsewhere. Those values are coupled, they're two-way bound, change to one ends up being a change to the other. In a lot of situations where you have kind of isolated information, this is totally appropriate and a good way to go, and it simplifies things a lot. But I ran into some use cases. This is actually something that I was asked to build where the select element state didn't match with what it reflected in the UI. Here's an example of a filter that when a choice is made in the select, it would just update a running list elsewhere. So two-way binding wasn't appropriate there, and I had to jump through a lot of hoops basically wrapping my Ember select in its own component to sort of simulate a one-way binding and not have my data leaking out. The other thing that I found really difficult was I had no idea what HTML, what DOM, this thing was actually rendering. I had a simple request to make some elements in a select disabled. And the solution I found, here's a quote from Stack Overflow. This is a simple approach for rendering a disabled option with Ember select. Basically, you have to reopen the built-in view and add the support for disabled. As a new developer, that's a scary thing to do to go kind of modify and extend core code. It's not super approachable. And if you're used to writing a select in HTML, you're used to just throwing an attribute on there. And so this is a bit of a barrier. So like I said, this haunted me on several projects that I worked on. This is a real quote from our EmberJS chat at TED. This went on and on and on, light at the end of the tunnel, a little later in the year when I found out that Ember select is going to be deprecated. So I was happy about that. And I took an interest in learning about what my alternatives were basically. So that's what I'm here to talk to you about today. I'm going to talk to you about building a better select with modern Ember patterns. So we're going to use real HTML so that we have almost complete control over what we want it to do. We're going to use the data down actions up pattern. And along the way, we're going to learn about a lot of cool new Ember features that have landed since that select element was deprecated. All set? All right, so let's take a look at first just building this out with plain old HTML. If you've ever done this in HTML, it should look pretty familiar. We're just going to use a little convenience with some HTML bars and using each loop to iterate over our options to make that a little less tedious. So this kind of assumes that you've got like an array of objects that you're going to use for your options list that can come from a static list or a model in your app and we're just going to access something like you're doing a drop down of languages. We'll use the language code for the value and we'll use the language name for the label on our option. So now let's talk about this data down actions up part. This is a kind of mantra in Ember lately. You might also see DDAU, if you want to confuse your non Ember colleagues, throw that acronym in somewhere. So what that basically means is we want our data flow to be sending data down, like into components into stuff that we're rendering. And then we want to respond to actions that are like bubbling up. So this is actually really great because it's similar to what you might be used to dealing with if you're just using plain old JavaScript or jQuery with a select. How do we usually deal with form elements changing? We respond to an on change action and that action bubbles up your DOM. So that's exactly what we're going to do with our real HTML rendered Ember better select. So what does that look like? All we need to do really is add to our existing code this on change attribute and we can tell that to fire an action. And I'm going to call that action language did change. And along with that action, I can go ahead and send the value of whichever option dispatch the change event. So this will be in wherever template you're rendering the select. And then in the controller or in a component, obviously later, you're going to catch that action, grab the value as a param. And then you can go ahead and do whatever you want with it. So in this case, I'm just going to set a property called selected language code to whatever value and you end up with something like this. So I pick my language, the code sends an action up and then I'm handling it in this particular template by just displaying the value. So that's the actions up part of this. Let's also make sure we send action data down. So the most common use case for this is usually when you want to send in something like an initial value, when you get to the page, if that selects already holding an existing value. You also might want to send data down if for some reason this updates in another part of your app state. You can also do the same thing. So in regular HTML, we indicate that a select element option is selected with the selected attribute. And this is one of those sneaky HTML attributes where no matter what you put in quotes, you can say selected equals false and it'll still be selected. It's just the presence of it needs to be there. But HTML bars is sophisticated enough now that we can do something like this where I'm going to set the selected attribute equal to some curlies. And you can write a really simple is equal helper here that just compares the two things that you give it. And we'll ask this is equal helper if the current language in the iteration of our loop is equal to the selected language that we're passing in. And that's going to return a Boolean and it's smart enough to know to either render out that selected attribute or not depending on what you're currently evaluates to. Now this is really powerful. Some of you might have remembered that not too long ago, any time we wanted to do a dynamic attribute, we needed to use the bind attribute syntax. This works out okay most of the time. Something like the value is pretty easy to simulate with bind attribute. But what if we were trying to replicate that selected? How would you do that? That turns out to be not as straightforward. So having the power to evaluate stuff in line here is really awesome. So that, my friends, is dynamic attributes. So bind attribute was actually deprecated way back in Emperor 110. Hopefully, I don't think too many of you are back there. But sorry, this is a little backwards on my side. I think bind attribute, something's weird with the version because the new feature can't come before the deprecated one, I don't think. Or maybe it did, yes, because we're good about being nice and leaving things in. So yeah, dynamic attributes are available as a 110 and bind attribute was deprecated in 113. Encourage you to use those because it gives you a lot of power to do some simple logic within your templates and cleans up the kind of readability of your templates quite a bit. So put that all together and we get something like this. Where I'm able to have an initial selection here, but I can pass that initial selection in as data down. And I can make changes with actions up and you'll notice that that original value does not get mutated by my select anymore. So that is really awesome and allows you all sorts of flexibility to manage your data flow as you see fit. So remember my second problem dealing with selects was that pesky disabled option. This turns out again to be pretty straightforward with our new tools. So let's return to the idea of having a model that we're using to generate our select options. A really easy way to do this is to set a computed property on your model that evaluates to a Boolean to use as a flag for something being disabled or not. So I'm gonna switch over to the example of fruits. And let's say we wanted for some reason to disable all the fruits in our list that are yellow. We can go ahead and use a computed property that sets that flag. And then we'll use our dynamic attributes again to say disabled is equal to that fruit.isYellowProperty. And again, this is clever enough to know whether or not to display that attribute based on the Boolean value of what your curly is evaluate to. Oh, it's a little something like that, no yellow fruits, we don't want those. So this is great, we've built something that is way more flexible. We have complete control over the DOM. The only drawback to this is we've lost the reusability of our magic. Sometimes it's actually nice to have a bit of reusable code that you don't have to go through the slog of writing out a lot of template for. So can we have a kind of happy medium between having code that's very flexible for us to use and having code that's reusable? We absolutely can, that's where components come in. This is one of my favorite images ever on the internet, by the way. I put it up as my lock screen background and it made me happy every time I looked at my phone. So yes, we can have it both ways. A great solution here, if you find yourself reusing the select code within your apps. Say there's multiple places around your app that you need to have a selector to choose a fruit. That's something where a component is really powerful to abstract that code a bit away into your own reusable bit of code. So we actually don't have to do too much to change what we've got into its own component. We're going to move it into its own component file. And the only thing we need to do now is make sure that that action actually bubbles up out of our component. So the kind of way that probably most of you are used to doing this is by within the component, so the blue code, we're going to catch that fruit did change action again, and we're going to use this dot send action to send that up out of our component. And then wherever we're rendering the component, we need to pass in the name of the action that we want to be bubbled. So usually you just go with the same thing, because that's straightforward. And then out in that outer scope, you're going to then handle the bubbled up action. So this is a good pattern, but it's actually one of the things that I found really confusing when I got started. Having an action name in just as a string was kind of hard for me to keep track of, because it just looked like another property a lot of the time. And this also starts to bite you when you start nesting components several levels deep because you have to bubble actions up and up and up and up and up. And it's it's yeah, it's a pain in the butt. Components are a great tool for us, but passing actions wasn't really an easy process. Luckily, we have closure actions now. So this landed in 113 available in any version after that. And the way that closure actions work is this allows you to instead of having to bubble up in an internal action handler, you're actually just going to be able to wherever you're rendering the component. So instead of giving it a named action, sorry the name is a little mismatch there. You can actually tell it that I want you to use an action called update fruit. So I love this because not only is it way more explicit in your template, what's happening here, you know that this is going to do an action, run a function. You also do not have to bubble this on your own. It's just going to look for anything in that outer scope called update fruit. And it's going to be able to take the values that you've sent out from your deeply nested component. So you can go ahead and start layering things in as like many layers in between as you need. And that's going to bubble up without having to repeatedly send action. You just need to pass up the name in your templates. So this is really fantastic and again, I think it's a lot more readable. So that's the action up when we've turned this into a component. How about doing data down once we've turned this into a component? So it's going to look actually pretty similar. We're still going to iterate over our fruit and this time we'll just need to wherever the template, the component is called. We're going to pass in that array of fruits. And then we're going to pass in the selected fruit as an initial value. And we haven't really had to change much of our template. We're just making sure we send in good data. But what about something like this? What if we wanted to make that disabled key something dynamic? It's conceivable that in multiple places where you're using this fruit select, that you might want to have a different type of fruit be disabled. So what if I wanted to pass in disabled key is red? I've got this is yellow hard coded in here. So previously, whenever I needed to do a dynamic key look up like that, my solution was usually to render a nested component. So instead of just doing that option straight within the each loop, I would set up something like a fruit select option component. And this is going to allow you to make an attribute binding within that option component. And you can do something like set the value of the disabled attribute with a computed property in that one. And you'll be able to dynamically look up that disabled key with this line up here where we're using ember.get with this.get fruit. And this.get disabled key. So this works, but it's kind of a lot of overhead just to get a dynamic key. And you gotta pass a lot of extra stuff in so that that inner component knows about it. You gotta send everything in there. And your template is a little less readable than what we're used to seeing, which is a simple option. So there's actually a really fantastic solution to that. And that is our friend the get helper. So this landed in ember 2.1 and the way that this works is just gonna allow you to kind of bypass all that extra work to get a dynamic key look up. And you can do it right in your template here. So for the disabled attribute, I use the get helper. I give it an object and then a key. And it's gonna go ahead and do the ember.get under the hood. And just throw that in there nicely without a lot of extra overhead on my part. And now I'm free to pass in a dynamic key to my component. We've built an awesome data down, actions up, select component that's tailored to our app, but still really flexible. What if you wanna do two way binding back? I know that two way binding has kind of got a really bad rap. I think maybe we all got burned by it early on when framework community was super gung-ho about that. But in some cases, like I say, it is appropriate if you're just dealing with a local app state and you actually have state that's tightly coupled. Sometimes two way binding is just the easier, better choice for that. So there's actually a really great way to again have the best of both worlds. And that is the mute helper. So this comes along with closure actions. So it's going to be available anywhere that closure actions are. So that's going to be 113 and up. And the way that that works is instead of passing in a named action, you're gonna be able to just say, hey, I want you to mutate this value instead. So you look at the top here, you'll see I'm using that on a change closure action syntax again. But this time, instead of putting an action name, a function name in there, I'm gonna actually just tell it to mutate a value called selected fruit. Now we just need to do a little extra work here to get this to kind of play nice with what we want. Right now our existing code sends in a fruit object for the data down part, but our actions up is just sending up a value. So this isn't gonna work really awesome as a two way binding, because we have a bit of a mismatch between the data that we're using. So what we really want is to be able to send up a fruit action so that that can be properly mutated with a piece of data of the same format. But that's a pretty easy work around here. What you're gonna be able to do is, this is sort of like the power and flexibility that you have with closure actions is, instead of just letting that bubble straight up, you can go ahead and catch your fruit to change action within the component. And you can do what you need to do. So here, we're going to take the value and we're just gonna do a lookup by ID to find the corresponding object. And then we'll use the closer action kind of inside here. Instead of doing this dot send action because our action is passed in as an attribute, we can just go ahead and use a this dot get lookup for whatever got put into on change. And that function is gonna run and we're able to pass selection as a parameter up to that function. So lots of power, lots of flexibility when you're working with closure actions. And in fact, it feels more natural to how we know functions operate in JavaScript, so this is fantastic. Putting that together, this is a quick example of using the same component to either do a one way or two way binding. So choose your own binding adventure, same code in the component. But as the consumer of the component, you can choose what your data flow needs to be just by passing in either a named function or the mute helper with the value that you wanna mutate. Really awesome. So, what have we done? We've built our own select component that uses custom HTML. We've allowed completely custom data flow as we see fit in our app. And we've also learned about all these really awesome powerful features like dynamic attributes, closer actions, mutes and the get helper. Put that all together and I say you have a select in your app that is flexible, reusable and modern and that is exactly what your Ember apps and the things in your Ember apps should be. So, you can kind of like choose your level of abstraction here. Pick whatever is getting repeated for you in your apps as a select code. Abstract that into a component as you see fit. And do whatever you need to do that works for you. As an example, all of our internal apps are built in Ember. So, we've worked on a little reusable component that suits our needs at TED, called TED Select. So, some of the features that we wanted were allowing the options to be sortable, allowing multi-select versus single-select and this handles that. It doesn't handle everything. There's a lot of things that you can make a select do but I think choosing the right level of abstraction for your needs is a great path that we can follow moving forward in our apps. So, how did I figure out how to do all this? This is your friend. On the EmberJS blog, the release posts every six weeks are really fantastic for keeping up to date with evolving things within the framework. This is where I found out that EmberSelect was going to be deprecated. And I started reading up and getting excited about new ways to do this. And I keep up with this whenever a new post comes out and see all the cool new stuff that this framework is evolving to do. I really think it's fantastic. I've seen in just a year's time, anything that's a pain point is actually getting solved even this morning hearing about the render performance gains in Glimmer2. That's been one of the other things that I've been having trouble with. And just to see that this level of action in the community and the core team to bring us what we need and continue to grow Ember is really fantastic. So I do encourage you all to keep up with this and hopefully you'll get excited about new Ember features. And that can be incentive to upgrade your apps and keep things up to date. So I leave you with that. I hope you can all take away stuff from here to build awesome select elements and hopefully other things within your app. Thank you.