The {{x-foo}} in You
Florence, Ryan
TDeclarative, evented, data-bound components will change the way you build abstractions in browser applications. The best part is, you're already an expert, you just might not know it yet. We'll discuss how to: Use a component Know when not to use a component Communicate with the world outside the component Refactor large components Test components in isolation Make components accessible.
 Well, I'm really excited to introduce our next speaker. I described him yesterday as the second angriest man in JavaScript. Ryan is simultaneously both the biggest fan and the biggest hater of Ember. I can prove that. I'll show you my IM logs. So I think it's really important, like I said yesterday, to get diverse opinions, people who have been around a lot. So I'm really happy today. Ryan is going to be talking about components from the perspective of a Mood Tools core contributor. Thank you, Ryan. All right. How's the, all right, we can hear me. Thank you very much. Mood Tools, man. It's been a while. Don't extend prototypes, Ember. All right. Let's get this started. The ex-foo in you. Components are a new way for us to create abstractions in the browser. And they're a little bit different than maybe what we're used to. And I've been doing a lot with them lately. And this talk is really just kind of share with you where I'm at with it. If anything is the Wild West in Ember, I think it's probably components where sometimes doing the wrong thing feels about as good as doing the right thing. Because we haven't figured out all those things quite yet. So I hope to kind of show what I think are some of the right things to do with components. Components are just tags that have unique style and behavior. Sort of like some people. I'm counting to 30 in my head. Okay. All right. So, aside from that, it's a custom element with an optional template, an isolated Ember view that controls that template. And then the view is the context. In other words, it is its own controller. Sort of kind of. I had a JS bin that Yehuda didn't like very much where I made an application component. I needed an application view equals application component. An application controller equals application component. And it worked. Then I get a message from Yehuda and I am that's like, hey, I want to talk about your talk. Can you just make sure you keep it within party lines? I was like, I don't know what those are. All right. So, let's think about the most common component that you learn when you first learn HTML. The anchor tag. You might not think of this as a component, but it totally is and it's actually kind of a confusing thing. Think about the behavior of an anchor tag. If we don't have an href, it's just like it does nothing, right? You don't even get an underline. You don't get styles. But as soon as you drop an href on it, now it turns blue, you get an underline. And if you click it and the link is not internal to the document, you actually get a reload new page. It sends you somewhere else. If you have a hash in front of the href, now all of a sudden we're saying, oh, wait, this is inside the document and so now it scrolls down to that element if it can find it. So let's recreate the a tag. Got my doc type. Got a style here. So xa, it's blue, text decoration underline, cursor pointer. And then here I can say xa, href equals amberjs and about. And then I got this h2, throw a bunch of margin on top so that we have to scroll down. And now to implement this guy or girl, depending on the gender of the component, I think that this is a guy. Next one's a girl. Tag name is xa. We've got some attribute bindings, attribute bindings. Whenever you set a property, it's going to keep that up to date on your element. Tab index, I'm doing this because I want to be able to tab to this thing and allow it to be focusable. So I add a tab index to it. And then I did a role because I'm a nice guy to blind users. So the screen reader will actually think of this as a link as it should. And then I just set href to null as a default. Tab index, you actually don't want a tab index at all if there is no href. You don't want this thing to be tabbable. And so I do a computed property and I check, do I have an href, set tab index to zero, which puts it in the tabosphere or null, and then Ember will just, like, remove that attribute completely when I say null. Go to href, on click. One of the great things about Ember, sometimes people measure productivity and how much stuff they can do in a certain amount of time. For me, building a lot of the framework stuff and structure, I think of productivity as how many questions can I not be asked by my team if my component does what it's supposed to do? And if the code makes sense. And I love that with these click handlers, you're forced to name things in Ember. Like I've got to name this go to href rather than just on click and then some random function. I have no idea what you're trying to do. At least now I have a clue about what the developer intended to do by the name of the function. And we all know how often comments that explain things stay up to date. So I get my href, check if I started with a hash, and if so, then I scroll to the href, otherwise I visit the href. If I scroll to it, I go and select that element. If I didn't find one, I just give up. If I did find one, I find the bottom of it on the page, scroll my document down to it, and then update the hash. Otherwise, I just do a window location. So here it is. You see I can tab to these things. If I click about, I scroll down, and the back button doesn't work with this. I didn't know how to make that happen. And then if I click this, it'd send me off to Ember. So that's how the a tag works. It's a component that you're all familiar with. Then I thought, oh, what's in the, oh, no, dang. Oh, well, these were unicorns. And sparkling unicorns. Why did it not open it up? Let me go into Mac and open this guy up. We have a script. I thought, well, I did the anchor tag. This is kind of a weird component also. And so I've got this x script that points to my Bower components, brings in cornify, and then here I actually have a body for a script tag. So a script tag is also a component. If you have a source, it goes and fetches it. If you don't have a source, it yields the body. And so now I've got my x script component. My layout is just a triple mustache to open up or to yield the template without escaping anything. And I don't know what Chris was talking about. Will insert element. I totally have an element here, and I can set a display to none. Chris? Anyway, I don't know how I got this element. I must be magic. But hide the script tag so you don't see the code. And then fetch or yield when it inserts, open an XHR, go get the script, eval the response text, or if I yield, get the text content, and then yield that. And so that last thing is what you just saw, creating a script tag out of that. So this stuff is pretty neat. But aren't we supposed to make stuff that doesn't exist yet? Like I don't know, maybe an X-wing? Uh-oh. Hmm. Easy. All right, where are we going? Heads up. Okay, okay, okay, okay. Let's see if we can get this guy back over to me. Come on, man. So my controls are as they should be. Okay, where are we going? Wrong way. I shouldn't talk, I should just do this, right? All right. It is acting really funny with all the Wi-Fi in here. Whoo! So let's turn this off, and then I'll show you the controls. Nobody know Jameson Dance. He just spoke at Mountain West JS and hooked it up to an Xbox controller, and I was like, oh, dude, that's the greatest component ever. So you can see here when I hit W, I go, and if I keep hitting W, then it turns red, which means I'm at max speed. And if I hit S, then it switches down, and I can go two directions at once. But I've got this concept of opposite directions, right? So if I'm going left and then I hit right, I set the left to zero, and then actually, that just stops everything. And then this side is the point of view, which rotates it or makes it go up and down. And of course, this launches, and I can click all these things to get the same effect. So let's check out this code. Oh, and here's all my actions. All right, so the X-Wing code, to use it, it's just a simple little tag. X-Wing and then a URL to the, I've got an express server that actually controls the thing. It's got a Wi-Fi chip in it, and then I connect to its Wi-Fi, which I was freaking out because I couldn't get connected earlier. Know what my dock type up here? It's kind of how I was flying it. So now I've got my template for the X-Wing. And I've got another abstraction, the X-Wing action. So I just say front. So this action makes it go forward, like tilt forward. And then I bind to the parent components, vals.front. And then I've got these icons, icon arrow, and I can rotate it. And so you see that all these are just the same icon, I just rotate it around. And then left, so it's all the same thing, left, left, left. And then the point of view one, same thing, icon action up, counterclockwise, etc. And these are my icons. Just throw some SVG in, make a template. You don't need any JavaScript, and now you've got icon launch and icon arrow. Now let's look at the JavaScript. Tab index, because when it's not focused, it doesn't fly. So I was trying to have my three-year-old fly it, and he kept clicking outside, and then it wouldn't control it, and it's up on the roof of my in-laws two-story house. And I was walking across it, and it's super steep. I thought I was going to die. So the vals are, I keep track of how fast it's going, so from zero to one. And anyway, that's just for the speed of it. And I've got some opposites here, front, opposite is back, etc. These are all the key things that I respond to in my key map. So then I have one keyboard action on key down, and I throttle it, figure out if I get an action, if I do perform it. And then down here, I can get the action and perform a paired action. That's like left and right, so they cancel each other once it happens. Animation, that was the flip. And then otherwise, I just call some method on here, assuming I've defined it. And then, yeah, just some more stuff. Making an action quest. This is the real magic, is it goes off to an express server, and that express server has the drone library, and that's the thing that actually controls it. Yeah, so that is it. Same controls are for like any first-person shooter you've used before. Greatest component ever. Or is it? What is going on? I hope some of you can appreciate that quote. Doctype public offender. Spacer gift. Yes. Find the height to Y of my controller, and then this is bound to Y. All right, so I can just... Here's a spacer gift component. It's an image, attribute binds to source with height, and then I set its data to... That is a transparent gift. Oops, not anymore. Yeah, there's a transparent gift for you. So use it. This is production ready. So communication. This is often a hard thing for both people and code, especially when you put them together. So how do you get a component to talk to the outside world? And I remember when the core team was sort of screwing around with this idea of components, we were actually making this function called... Actually, I called it component, and then we would get a view, and we'd do an initializer, and then set this.context equals this, and just started messing around with that. And I did a presentation back in Utah at our lunch JS, and I made a slideshow thing, and I had no way to communicate out. And then as components started getting better and better, and then actually shipped, we've got two ways to communicate. It's data binding and actions. And this is fantastic, because now if you build a component, you don't really even have to document it. Like people know, I've got some attributes that I can two-way bind to, or I've got some actions that it might respond to. Instead of in the days of other frameworks or just libraries, you've got to go and read the code or the comments, or go talk to the author at your office who made the thing, and figure out how to actually interact with this, or go read the test that they wrote, et cetera. So let's first talk about data binding. I've got... I'm going to be talking about IC tabs. So at Instructure, our main software is called Canvas. So all of our stuff is prefixed with IC, IC Canvas, IC Dead People. That's coming soon. So IC tabs is something that I just finished a couple of weeks ago, and it's kind of like the state of the art for me on how I build components in number. So I'm going to be talking a lot about it. So one of the use cases that I think is incredibly handy for a tab component is to persist to the query parameters so that you can refresh, and those same tabs are there still, or you can link to a page in that state. So here's my demo. I do IC tabs, and then I say selected index equals country. So that's in my application template. So my application controller down here has query parameters country, and country is set to zero. So the first tab is what will show up. So let's see this in action. So I can click Japan down here in countries, and click Texas in countries. People from Texas are like, that's right. And Canada's like, where are we? Okay. Now if I refresh this, Japan is selected, and then this one was bound to the food on my application controller. So it's pretty awesome. So I actually wanted an API for IC tabs, or I'd say IC tabs, query param equals, and then like a name, and I went into IRC, and the whole core team was like, you're a moron. And Yehud is like, I'm so happy with everyone right now. And I was like, yeah, but what about me? No hard feelings. So that's data binding, which you can see will work all the way with all of the other Ember concepts, where your controller sets the context of your template, or proxies the model anyway, and then query params is just bound to those controller properties, and now your components combine to those controller properties. And so all of the data and the information is flowing the right direction. And when I wanted to do that weird interface of having a query param attribute on my tabs, it was really hard. And I was like poking around, I'm sending Alex messages saying, hey, how do I find the router? And he's like, don't. And so again, productivity for me is making things that I can create and then just forget about. And everyone will use them and they just work. And you get a bug every now and then, for the most part, people will wonder if the thing is active, because GitHub hasn't been updated for several months, but it's because it's done and it works. And Ember provides that for me by making the wrong thing hard and the right thing easy. You saw that query param thing was really easy. So actions. Let's check out how these work. I've got another one called ICMenu. I was talking with another Ryan last night about popovers, and we're saying how it's kind of deceptive. It seems like a really easy problem. And you just click a thing and toggle a property and then have an if in your template and now this thing shows up. But if you start to really think about how a popover works, now you've got this outer click event that you need to deal with, because it's open and then you go click somewhere else. And so you think you're really smart and so you put an event on the body or on the document, and then you plan on some event bubbling up and then checking what was clicked and then closing or not. But you forgot that select tags don't actually propagate the click event all the way up, so that doesn't work. And then you tab and focus them out of their element, and so your thing is still open. So it gets really complicated. And so we have a component for this so that we don't have those kind of weird edge cases happening. And I don't know what people want to do when a menu item is selected. And so I just hand that to their app with my on select event. So when I use IC menu, I make an IC menu item and then I say on select, remove. And that will, that will, I don't know if this is going to open up my code, I don't think it will. That will go, oh never mind, my code's down here. So my application controller's here and I've got actions on that controller removed, so that's going to call remove. Same with save and everything else. So let's check this one out. So I click this menu, pops up, and then I click remove and I get my alert. And like I was saying, this is a pretty tricky thing, so I've got to figure out how to deal with all that stuff. So the thing is, simple tasks, there's no such thing. Except link two and Ember, which is actually a really hard thing, but for us now it's simple. So Ember gives me the primitives to make the things that seem like they should be simple, actually simple for people to use. So no one has to think about that anymore. Another consideration is attribute bindings for accessibility. So when you open up this menu, I'm setting a property called aria expanded true. And that triggers to a screen reader, hey this thing is open. There's also things like aria has pop up and you have aria controls and the aria controls needs to tell the screen reader which element it controls so it knows how to jump the user down there when they do the right keyboard combination. So there's, again, simple things are not actually simple. And with Ember's primitives, I'm able to just bind an attribute to a property. And sometimes it's just a bunch of aliases for me to get something accessible. In my description, I talked about writing and refactoring large components. Components were originally thought of as templates. And in fact, the first version of components in Ember, if you didn't have a template, you didn't get a component. Fortunately, now you don't need templates. So this might be what an X tabs component would look like if this is the first time you're writing a component. You might just think, oh, this will be sweet. I just do X tabs. And I say tabs are your groups. So maybe you're on a group page and you want to make a tab out of each group. And then you're like, now I'm going to do all the hard work down here. And in your template, you create this div and you iterate over the tabs and you make the tabs and you have a label and then you iterate over the tabs again and make your panels. And everyone's happy and it's really easy to use. I won't put my hand there again. There are some problems. Number one is X tabs component does everything. You probably can't read that very well. X tabs component does everything. So it's going to get unwieldy. It's going to be really huge. And everybody's going to start saying things like, oh, no, there's a bug in tabs component. I don't want to go into that code. To be accessible, the tabs need some attributes that get changed. Where are you going to do that when you just have one big component? How are you going to go get those other elements and update their attributes? Now you're getting right back into jQuery spaghetti. Why are we forcing tab.panel and tab.body on people? This is just a tab component. We shouldn't be bound to some sort of data model. And what if we want the tabs on the bottom? My template had them on the top. But does the position of the tabs really have anything to do with the behavior? Or what if I don't even have any data and I just want to make some static tabs? I've just got some static content. I just want to stick it in there. Or even worse, what if I want one static tab and then a bunch of dynamic ones from data? There's just no way to do that when you build these large components with big templates. So instead, what if we did it like this? We make an X tabs and that's a parent thing. Then we have X tab list and that defines the behavior for the list. And then we have an X tab component for the individual tabs. Now each one of the pieces of this component are separated. I call these composite components. So you composite a bunch of smaller components together. So now in this instance, I can have just a static tab called default and then I can have these dynamic tabs for groups. And I'm not bound to some sort of data model. I can just use group.name instead of switching my group stuff into label and stuff like that. The other thing is for these child components can now manage their own state. So if their attributes need to change when they're selected, the tab can just do that itself. It knows it's selected and then it can change its attribute accordingly. You don't have to have some parent big giant thing using jQuery to go and select things and then you're wondering why am I using components? This looks like when I was writing jQuery plugins. Okay, okay, you get it. It wasn't the old thing more convenient. All right, people had to write a whole bunch of stuff now. So instead of doing the huge component, I make what are called convenience templates on top of those components. So I do X tabs top and then tab. So it's right back to that old to the first interface. But now I can compose these tabs however I need to. So on this one I've got tabs on the top. If I want to tabs on the bottom, I just make a new convenience template and move the tab list to the bottom. And everyone else on the team can still just do X tabs top, tabs equals groups and then they're done. So the trick is, oh, and now I have no template because the, well, on the old one. So doing this, you get the composition flexibility with these convenience components without doing crazy hacks. Keep it declarative. Keep it simple. Two things to remember. I have a bias toward no templates. As soon as my component has a template, I start thinking, okay, I'm missing an abstraction in here. And the best way to find where those abstractions are for these subcomponents, just identify them by do they have events? Like if I click a tab, does something happen? Yes? Okay, that should be its own component instead of delegating from some parent and then checking an event.target and determining if it was a tab and then perform some action. And then the second is if you need to manage its class or attribute, depending on the state of the whole component, it should probably be, well, not probably, it should be its own component as well. And the best way that I found to talk about this with people and just myself is to try to think about native elements and the select option combination is just wonderful for this. Think about what it is. You've got two different components, an option tag, which makes no sense outside of a select tag. And you have the select tag and it's got a value. And depending on what you, which option tag you interact with, that's what the value becomes on the parent. And so that's a great reference to when you think about components and how should I abstract this? Try to find a native thing, like a submit button inside of a form. Well, that changes the whole behavior of the form once you have an input type submit down in there. It changes the behavior of hitting enter inside of an input text, right? So just having an input type submit, the whole form reacts to that. Another tip is to test and develop with dynamic data. The great thing about Ember is you get things updated just when you change your data. And everyone who's wrapping Bootstrap or jQuery things, I guarantee you your stuff doesn't work when you go and change your data. Like if you're iterating over and each and creating tabs with Bootstrap, you go change that data, you're going to have to do a lot of tear down and set up management. But if you build these things native to Ember and you consider the dynamic nature of the data that people will give you, you can make them a lot more usable. So to create this tab interface where I can just create these dynamic tabs, and then if I say I delete a tab that is active, and now it's gone, like I've got code in there to say, oh, hey, that thing is gone now. Which one should I select? I should probably select the one previous to it. So again, it doesn't take a whole lot of code for me to build something that used to be really difficult with any other tab kind of component. But when you build it native in Ember, you get this stuff almost for free, but you need to develop with it in mind. And then you also get interesting things like this, where I can bind the data to the selected index. And now anything on the control can be bound to that data, and the template can be bound to that data and control which tab should be active. Distributing your stuff on a container with an application initializer, precompile your templates individually as the layout property of the component. I use a thing called ICStyle that we made for minimum viable amount of CSS for the component to work. It's more than like 10 or 15 lines of CSS is probably too much. And then I use BroccoliDist ES6 module to publish to everything. So this is ICTabs. So you see my main script pulls in everything. I initialize it, register things on the container, and then I export them all. And then I've got my dist that distributes all of these different formats. And so in the case of Browserify, you can MPM install ICTabs, go to your application file, require ICTabs, and then go into your template and just use it, and it'll work and look good. So this is how I distribute it. So if you're looking to distribute things, I don't know if this is the best way yet, but it's the most convenient that I've found for us at Instructure. We are working on a lot of components. You can find them at this address. Only a couple of them have demo pages right now. More are going to be coming and help us out with them. We, Ember, really needs like a few good libraries that we can point to and say, hey, here's some components that you can use and they work with your data. That's it. I'll see you later. Okay?
 Well, I'm really excited to introduce our next speaker.  I described him yesterday as the second angriest man in JavaScript.  Ryan is simultaneously both the biggest fan and the biggest hater of Ember.  I can prove that.  I'll show you my IM logs.  So I think it's really important, like I said yesterday, to get diverse opinions, people  who have been around a lot.  So I'm really happy today.  Ryan is going to be talking about components from the perspective of a Mood Tools core  contributor.  Thank you, Ryan.  All right.  How's the, all right, we can hear me.  Thank you very much.  Mood Tools, man.  It's been a while.  Don't extend prototypes, Ember.  All right.  Let's get this started.  The ex-foo in you.  Components are a new way for us to create abstractions in the browser.  And they're a little bit different than maybe what we're used to.  And I've been doing a lot with them lately.  And this talk is really just kind of share with you where I'm at with it.  If anything is the Wild West in Ember, I think it's probably components where sometimes  doing the wrong thing feels about as good as doing the right thing.  Because we haven't figured out all those things quite yet.  So I hope to kind of show what I think are some of the right things to do with components.  Components are just tags that have unique style and behavior.  Sort of like some people.  I'm counting to 30 in my head.  Okay.  All right.  So, aside from that, it's a custom element with an optional template, an isolated Ember  view that controls that template.  And then the view is the context.  In other words, it is its own controller.  Sort of kind of.  I had a JS bin that Yehuda didn't like very much where I made an application component.  I needed an application view equals application component.  An application controller equals application component.  And it worked.  Then I get a message from Yehuda and I am that's like, hey, I want to talk about your  talk.  Can you just make sure you keep it within party lines?  I was like, I don't know what those are.  All right.  So, let's think about the most common component that you learn when you first learn HTML.  The anchor tag.  You might not think of this as a component, but it totally is and it's actually kind of  a confusing thing.  Think about the behavior of an anchor tag.  If we don't have an href, it's just like it does nothing, right?  You don't even get an underline.  You don't get styles.  But as soon as you drop an href on it, now it turns blue, you get an underline.  And if you click it and the link is not internal to the document, you actually get a reload  new page.  It sends you somewhere else.  If you have a hash in front of the href, now all of a sudden we're saying, oh, wait, this  is inside the document and so now it scrolls down to that element if it can find it.  So let's recreate the a tag.  Got my doc type.  Got a style here.  So xa, it's blue, text decoration underline, cursor pointer.  And then here I can say xa, href equals amberjs and about.  And then I got this h2, throw a bunch of margin on top so that we have to scroll down.  And now to implement this guy or girl, depending on the gender of the component, I think that  this is a guy.  Next one's a girl.  Tag name is xa.  We've got some attribute bindings, attribute bindings.  Whenever you set a property, it's going to keep that up to date on your element.  Tab index, I'm doing this because I want to be able to tab to this thing and allow  it to be focusable.  So I add a tab index to it.  And then I did a role because I'm a nice guy to blind users.  So the screen reader will actually think of this as a link as it should.  And then I just set href to null as a default.  Tab index, you actually don't want a tab index at all if there is no href.  You don't want this thing to be tabbable.  And so I do a computed property and I check, do I have an href, set tab index to zero,  which puts it in the tabosphere or null, and then Ember will just, like, remove that attribute  completely when I say null.  Go to href, on click.  One of the great things about Ember, sometimes people measure productivity and how much stuff  they can do in a certain amount of time.  For me, building a lot of the framework stuff and structure, I think of productivity as  how many questions can I not be asked by my team if my component does what it's supposed  to do?  And if the code makes sense.  And I love that with these click handlers, you're forced to name things in Ember.  Like I've got to name this go to href rather than just on click and then some random function.  I have no idea what you're trying to do.  At least now I have a clue about what the developer intended to do by the name of the  function.  And we all know how often comments that explain things stay up to date.  So I get my href, check if I started with a hash, and if so, then I scroll to the href,  otherwise I visit the href.  If I scroll to it, I go and select that element.  If I didn't find one, I just give up.  If I did find one, I find the bottom of it on the page, scroll my document down to it,  and then update the hash.  Otherwise, I just do a window location.  So here it is.  You see I can tab to these things.  If I click about, I scroll down, and the back button doesn't work with this.  I didn't know how to make that happen.  And then if I click this, it'd send me off to Ember.  So that's how the a tag works.  It's a component that you're all familiar with.  Then I thought, oh, what's in the, oh, no, dang.  Oh, well, these were unicorns.  And sparkling unicorns.  Why did it not open it up?  Let me go into Mac and open this guy up.  We have a script.  I thought, well, I did the anchor tag.  This is kind of a weird component also.  And so I've got this x script that points to my Bower components, brings in cornify,  and then here I actually have a body for a script tag.  So a script tag is also a component.  If you have a source, it goes and fetches it.  If you don't have a source, it yields the body.  And so now I've got my x script component.  My layout is just a triple mustache to open up or to yield the template without escaping  anything.  And I don't know what Chris was talking about.  Will insert element.  I totally have an element here, and I can set a display to none.  Chris?  Anyway, I don't know how I got this element.  I must be magic.  But hide the script tag so you don't see the code.  And then fetch or yield when it inserts, open an XHR, go get the script, eval the response  text, or if I yield, get the text content, and then yield that.  And so that last thing is what you just saw, creating a script tag out of that.  So this stuff is pretty neat.  But aren't we supposed to make stuff that doesn't exist yet?  Like I don't know, maybe an X-wing?  Uh-oh.  Hmm.  Easy.  All right, where are we going?  Heads up.  Okay, okay, okay, okay.  Let's see if we can get this guy back over to me.  Come on, man.  So my controls are as they should be.  Okay, where are we going?  Wrong way.  I shouldn't talk, I should just do this, right?  All right.  It is acting really funny with all the Wi-Fi in here.  Whoo!  So let's turn this off, and then I'll show you the controls.  Nobody know Jameson Dance.  He just spoke at Mountain West JS and hooked it up to an Xbox controller, and I was like,  oh, dude, that's the greatest component ever.  So you can see here when I hit W, I go, and if I keep hitting W, then it turns red, which  means I'm at max speed.  And if I hit S, then it switches down, and I can go two directions at once.  But I've got this concept of opposite directions, right?  So if I'm going left and then I hit right, I set the left to zero, and then actually,  that just stops everything.  And then this side is the point of view, which rotates it or makes it go up and down.  And of course, this launches, and I can click all these things to get the same effect.  So let's check out this code.  Oh, and here's all my actions.  All right, so the X-Wing code, to use it, it's just a simple little tag.  X-Wing and then a URL to the, I've got an express server that actually controls the  thing.  It's got a Wi-Fi chip in it, and then I connect to its Wi-Fi, which I was freaking out because  I couldn't get connected earlier.  Know what my dock type up here?  It's kind of how I was flying it.  So now I've got my template for the X-Wing.  And I've got another abstraction, the X-Wing action.  So I just say front.  So this action makes it go forward, like tilt forward.  And then I bind to the parent components, vals.front.  And then I've got these icons, icon arrow, and I can rotate it.  And so you see that all these are just the same icon, I just rotate it around.  And then left, so it's all the same thing, left, left, left.  And then the point of view one, same thing, icon action up, counterclockwise, etc.  And these are my icons.  Just throw some SVG in, make a template.  You don't need any JavaScript, and now you've got icon launch and icon arrow.  Now let's look at the JavaScript.  Tab index, because when it's not focused, it doesn't fly.  So I was trying to have my three-year-old fly it, and he kept clicking outside, and then  it wouldn't control it, and it's up on the roof of my in-laws two-story house.  And I was walking across it, and it's super steep.  I thought I was going to die.  So the vals are, I keep track of how fast it's going, so from zero to one.  And anyway, that's just for the speed of it.  And I've got some opposites here, front, opposite is back, etc.  These are all the key things that I respond to in my key map.  So then I have one keyboard action on key down, and I throttle it, figure out if I get  an action, if I do perform it.  And then down here, I can get the action and perform a paired action.  That's like left and right, so they cancel each other once it happens.  Animation, that was the flip.  And then otherwise, I just call some method on here, assuming I've defined it.  And then, yeah, just some more stuff.  Making an action quest.  This is the real magic, is it goes off to an express server, and that express server  has the drone library, and that's the thing that actually controls it.  Yeah, so that is it.  Same controls are for like any first-person shooter you've used before.  Greatest component ever.  Or is it?  What is going on?  I hope some of you can appreciate that quote.  Doctype public offender.  Spacer gift.  Yes.  Find the height to Y of my controller, and then this is bound to Y.  All right, so I can just...  Here's a spacer gift component.  It's an image, attribute binds to source with height, and then I set its data to...  That is a transparent gift.  Oops, not anymore.  Yeah, there's a transparent gift for you.  So use it.  This is production ready.  So communication.  This is often a hard thing for both people and code, especially when you put them together.  So how do you get a component to talk to the outside world?  And I remember when the core team was sort of screwing around with this idea of components,  we were actually making this function called...  Actually, I called it component, and then we would get a view, and we'd do an initializer,  and then set this.context equals this, and just started messing around with that.  And I did a presentation back in Utah at our lunch JS, and I made a slideshow thing, and  I had no way to communicate out.  And then as components started getting better and better, and then actually shipped, we've  got two ways to communicate.  It's data binding and actions.  And this is fantastic, because now if you build a component, you don't really even have  to document it.  Like people know, I've got some attributes that I can two-way bind to, or I've got some  actions that it might respond to.  Instead of in the days of other frameworks or just libraries, you've got to go and read  the code or the comments, or go talk to the author at your office who made the thing,  and figure out how to actually interact with this, or go read the test that they wrote,  et cetera.  So let's first talk about data binding.  I've got...  I'm going to be talking about IC tabs.  So at Instructure, our main software is called Canvas.  So all of our stuff is prefixed with IC, IC Canvas, IC Dead People.  That's coming soon.  So IC tabs is something that I just finished a couple of weeks ago, and it's kind of like  the state of the art for me on how I build components in number.  So I'm going to be talking a lot about it.  So one of the use cases that I think is incredibly handy for a tab component is to persist to  the query parameters so that you can refresh, and those same tabs are there still, or you  can link to a page in that state.  So here's my demo.  I do IC tabs, and then I say selected index equals country.  So that's in my application template.  So my application controller down here has query parameters country, and country is set  to zero.  So the first tab is what will show up.  So let's see this in action.  So I can click Japan down here in countries, and click Texas in countries.  People from Texas are like, that's right.  And Canada's like, where are we?  Okay.  Now if I refresh this, Japan is selected, and then this one was bound to the food on  my application controller.  So it's pretty awesome.  So I actually wanted an API for IC tabs, or I'd say IC tabs, query param equals, and then  like a name, and I went into IRC, and the whole core team was like, you're a moron.  And Yehud is like, I'm so happy with everyone right now.  And I was like, yeah, but what about me?  No hard feelings.  So that's data binding, which you can see will work all the way with all of the other  Ember concepts, where your controller sets the context of your template, or proxies the  model anyway, and then query params is just bound to those controller properties, and  now your components combine to those controller properties.  And so all of the data and the information is flowing the right direction.  And when I wanted to do that weird interface of having a query param attribute on my tabs,  it was really hard.  And I was like poking around, I'm sending Alex messages saying, hey, how do I find the  router?  And he's like, don't.  And so again, productivity for me is making things that I can create and then just forget  about.  And everyone will use them and they just work.  And you get a bug every now and then, for the most part, people will wonder if the thing  is active, because GitHub hasn't been updated for several months, but it's because it's  done and it works.  And Ember provides that for me by making the wrong thing hard and the right thing easy.  You saw that query param thing was really easy.  So actions.  Let's check out how these work.  I've got another one called ICMenu.  I was talking with another Ryan last night about popovers, and we're saying how it's  kind of deceptive.  It seems like a really easy problem.  And you just click a thing and toggle a property and then have an if in your template and now  this thing shows up.  But if you start to really think about how a popover works, now you've got this outer  click event that you need to deal with, because it's open and then you go click somewhere  else.  And so you think you're really smart and so you put an event on the body or on the document,  and then you plan on some event bubbling up and then checking what was clicked and then  closing or not.  But you forgot that select tags don't actually propagate the click event all the way up,  so that doesn't work.  And then you tab and focus them out of their element, and so your thing is still open.  So it gets really complicated.  And so we have a component for this so that we don't have those kind of weird edge cases  happening.  And I don't know what people want to do when a menu item is selected.  And so I just hand that to their app with my on select event.  So when I use IC menu, I make an IC menu item and then I say on select, remove.  And that will, that will, I don't know if this is going to open up my code, I don't  think it will.  That will go, oh never mind, my code's down here.  So my application controller's here and I've got actions on that controller removed, so  that's going to call remove.  Same with save and everything else.  So let's check this one out.  So I click this menu, pops up, and then I click remove and I get my alert.  And like I was saying, this is a pretty tricky thing, so I've got to figure out how to deal  with all that stuff.  So the thing is, simple tasks, there's no such thing.  Except link two and Ember, which is actually a really hard thing, but for us now it's simple.  So Ember gives me the primitives to make the things that seem like they should be simple,  actually simple for people to use.  So no one has to think about that anymore.  Another consideration is attribute bindings for accessibility.  So when you open up this menu, I'm setting a property called aria expanded true.  And that triggers to a screen reader, hey this thing is open.  There's also things like aria has pop up and you have aria controls and the aria controls  needs to tell the screen reader which element it controls so it knows how to jump the user  down there when they do the right keyboard combination.  So there's, again, simple things are not actually simple.  And with Ember's primitives, I'm able to just bind an attribute to a property.  And sometimes it's just a bunch of aliases for me to get something accessible.  In my description, I talked about writing and refactoring large components.  Components were originally thought of as templates.  And in fact, the first version of components in Ember, if you didn't have a template, you  didn't get a component.  Fortunately, now you don't need templates.  So this might be what an X tabs component would look like if this is the first time  you're writing a component.  You might just think, oh, this will be sweet.  I just do X tabs.  And I say tabs are your groups.  So maybe you're on a group page and you want to make a tab out of each group.  And then you're like, now I'm going to do all the hard work down here.  And in your template, you create this div and you iterate over the tabs and you make the  tabs and you have a label and then you iterate over the tabs again and make your panels.  And everyone's happy and it's really easy to use.  I won't put my hand there again.  There are some problems.  Number one is X tabs component does everything.  You probably can't read that very well.  X tabs component does everything.  So it's going to get unwieldy.  It's going to be really huge.  And everybody's going to start saying things like, oh, no, there's a bug in tabs component.  I don't want to go into that code.  To be accessible, the tabs need some attributes that get changed.  Where are you going to do that when you just have one big component?  How are you going to go get those other elements and update their attributes?  Now you're getting right back into jQuery spaghetti.  Why are we forcing tab.panel and tab.body on people?  This is just a tab component.  We shouldn't be bound to some sort of data model.  And what if we want the tabs on the bottom?  My template had them on the top.  But does the position of the tabs really have anything to do with the behavior?  Or what if I don't even have any data and I just want to make some static tabs?  I've just got some static content.  I just want to stick it in there.  Or even worse, what if I want one static tab and then a bunch of dynamic ones from data?  There's just no way to do that when you build these large components with big templates.  So instead, what if we did it like this?  We make an X tabs and that's a parent thing.  Then we have X tab list and that defines the behavior for the list.  And then we have an X tab component for the individual tabs.  Now each one of the pieces of this component are separated.  I call these composite components.  So you composite a bunch of smaller components together.  So now in this instance, I can have just a static tab called default and then I can have  these dynamic tabs for groups.  And I'm not bound to some sort of data model.  I can just use group.name instead of switching my group stuff into label and stuff like that.  The other thing is for these child components can now manage their own state.  So if their attributes need to change when they're selected, the tab can just do that  itself.  It knows it's selected and then it can change its attribute accordingly.  You don't have to have some parent big giant thing using jQuery to go and select things  and then you're wondering why am I using components?  This looks like when I was writing jQuery plugins.  Okay, okay, you get it.  It wasn't the old thing more convenient.  All right, people had to write a whole bunch of stuff now.  So instead of doing the huge component, I make what are called convenience templates on top  of those components.  So I do X tabs top and then tab.  So it's right back to that old to the first interface.  But now I can compose these tabs however I need to.  So on this one I've got tabs on the top.  If I want to tabs on the bottom, I just make a new convenience template and move the tab  list to the bottom.  And everyone else on the team can still just do X tabs top, tabs equals groups and then  they're done.  So the trick is, oh, and now I have no template because the, well, on the old one.  So doing this, you get the composition flexibility with these convenience components without  doing crazy hacks.  Keep it declarative.  Keep it simple.  Two things to remember.  I have a bias toward no templates.  As soon as my component has a template, I start thinking, okay, I'm missing an abstraction  in here.  And the best way to find where those abstractions are for these subcomponents, just identify  them by do they have events?  Like if I click a tab, does something happen?  Yes?  Okay, that should be its own component instead of delegating from some parent and then checking  an event.target and determining if it was a tab and then perform some action.  And then the second is if you need to manage its class or attribute, depending on the state  of the whole component, it should probably be, well, not probably, it should be its own  component as well.  And the best way that I found to talk about this with people and just myself is to try  to think about native elements and the select option combination is just wonderful for this.  Think about what it is.  You've got two different components, an option tag, which makes no sense outside of a select  tag.  And you have the select tag and it's got a value.  And depending on what you, which option tag you interact with, that's what the value becomes  on the parent.  And so that's a great reference to when you think about components and how should I abstract  this?  Try to find a native thing, like a submit button inside of a form.  Well, that changes the whole behavior of the form once you have an input type submit down  in there.  It changes the behavior of hitting enter inside of an input text, right?  So just having an input type submit, the whole form reacts to that.  Another tip is to test and develop with dynamic data.  The great thing about Ember is you get things updated just when you change your data.  And everyone who's wrapping Bootstrap or jQuery things, I guarantee you your stuff doesn't  work when you go and change your data.  Like if you're iterating over and each and creating tabs with Bootstrap, you go change  that data, you're going to have to do a lot of tear down and set up management.  But if you build these things native to Ember and you consider the dynamic nature of the  data that people will give you, you can make them a lot more usable.  So to create this tab interface where I can just create these dynamic tabs, and then if  I say I delete a tab that is active, and now it's gone, like I've got code in there to  say, oh, hey, that thing is gone now.  Which one should I select?  I should probably select the one previous to it.  So again, it doesn't take a whole lot of code for me to build something that used to be  really difficult with any other tab kind of component.  But when you build it native in Ember, you get this stuff almost for free, but you need  to develop with it in mind.  And then you also get interesting things like this, where I can bind the data to the selected  index.  And now anything on the control can be bound to that data, and the template can be bound  to that data and control which tab should be active.  Distributing your stuff on a container with an application initializer, precompile your  templates individually as the layout property of the component.  I use a thing called ICStyle that we made for minimum viable amount of CSS for the component  to work.  It's more than like 10 or 15 lines of CSS is probably too much.  And then I use BroccoliDist ES6 module to publish to everything.  So this is ICTabs.  So you see my main script pulls in everything.  I initialize it, register things on the container, and then I export them all.  And then I've got my dist that distributes all of these different formats.  And so in the case of Browserify, you can MPM install ICTabs, go to your application  file, require ICTabs, and then go into your template and just use it, and it'll work and  look good.  So this is how I distribute it.  So if you're looking to distribute things, I don't know if this is the best way yet,  but it's the most convenient that I've found for us at Instructure.  We are working on a lot of components.  You can find them at this address.  Only a couple of them have demo pages right now.  More are going to be coming and help us out with them.  We, Ember, really needs like a few good libraries that we can point to and say, hey, here's  some components that you can use and they work with your data.  That's it.  I'll see you later.  Okay?
x-foo_0_1271.png x-foo_1272_1487.png x-foo_1488_1667.png x-foo_1668_3515.png x-foo_3516_3791.png x-foo_3792_4187.png x-foo_4188_4367.png x-foo_4368_5435.png x-foo_5436_7451.png x-foo_7452_8315.png x-foo_8316_8783.png x-foo_8784_9659.png x-foo_9660_10415.png x-foo_10416_12263.png x-foo_12264_16067.png x-foo_16068_17327.png x-foo_17328_18095.png x-foo_18096_18671.png x-foo_18672_20399.png x-foo_20400_27323.png x-foo_27324_27395.png x-foo_27396_27695.png x-foo_27696_27791.png x-foo_27792_27995.png x-foo_27996_28223.png x-foo_28224_28643.png x-foo_28644_28715.png x-foo_28716_31499.png x-foo_31500_33515.png x-foo_33516_33563.png x-foo_33564_33623.png x-foo_33624_36587.png x-foo_36588_38183.png x-foo_38184_38231.png x-foo_38232_38939.png x-foo_38940_39407.png x-foo_39408_39515.png x-foo_39516_41891.png x-foo_41892_42119.png x-foo_42120_42287.png x-foo_42288_42335.png x-foo_42336_42491.png x-foo_42492_42647.png x-foo_42648_43247.png x-foo_43248_44135.png x-foo_44136_45011.png x-foo_45012_46187.png x-foo_46188_47114.png
Well, I'm really excited to introduce our next speaker. I described him yesterday as the second angriest man in JavaScript. Ryan is simultaneously both the biggest fan and the biggest hater of Ember. I can prove that. I'll show you my IM logs. So I think it's really important, like I said yesterday, to get diverse opinions, people who have been around a lot. So I'm really happy today. Ryan is going to be talking about components from the perspective of a Mood Tools core contributor. Thank you, Ryan. All right. How's the, all right, we can hear me. Thank you very much. Mood Tools, man. It's been a while. Don't extend prototypes, Ember. All right. Let's get this started. The ex-foo in you. Components are a new way for us to create abstractions in the browser. And they're a little bit different than maybe what we're used to. And I've been doing a lot with them lately. And this talk is really just kind of share with you where I'm at with it. If anything is the Wild West in Ember, I think it's probably components where sometimes doing the wrong thing feels about as good as doing the right thing. Because we haven't figured out all those things quite yet. So I hope to kind of show what I think are some of the right things to do with components. Components are just tags that have unique style and behavior. Sort of like some people. I'm counting to 30 in my head. Okay. All right. So, aside from that, it's a custom element with an optional template, an isolated Ember view that controls that template. And then the view is the context. In other words, it is its own controller. Sort of kind of. I had a JS bin that Yehuda didn't like very much where I made an application component. I needed an application view equals application component. An application controller equals application component. And it worked. Then I get a message from Yehuda and I am that's like, hey, I want to talk about your talk. Can you just make sure you keep it within party lines? I was like, I don't know what those are. All right. So, let's think about the most common component that you learn when you first learn HTML. The anchor tag. You might not think of this as a component, but it totally is and it's actually kind of a confusing thing. Think about the behavior of an anchor tag. If we don't have an href, it's just like it does nothing, right? You don't even get an underline. You don't get styles. But as soon as you drop an href on it, now it turns blue, you get an underline. And if you click it and the link is not internal to the document, you actually get a reload new page. It sends you somewhere else. If you have a hash in front of the href, now all of a sudden we're saying, oh, wait, this is inside the document and so now it scrolls down to that element if it can find it. So let's recreate the a tag. Got my doc type. Got a style here. So xa, it's blue, text decoration underline, cursor pointer. And then here I can say xa, href equals amberjs and about. And then I got this h2, throw a bunch of margin on top so that we have to scroll down. And now to implement this guy or girl, depending on the gender of the component, I think that this is a guy. Next one's a girl. Tag name is xa. We've got some attribute bindings, attribute bindings. Whenever you set a property, it's going to keep that up to date on your element. Tab index, I'm doing this because I want to be able to tab to this thing and allow it to be focusable. So I add a tab index to it. And then I did a role because I'm a nice guy to blind users. So the screen reader will actually think of this as a link as it should. And then I just set href to null as a default. Tab index, you actually don't want a tab index at all if there is no href. You don't want this thing to be tabbable. And so I do a computed property and I check, do I have an href, set tab index to zero, which puts it in the tabosphere or null, and then Ember will just, like, remove that attribute completely when I say null. Go to href, on click. One of the great things about Ember, sometimes people measure productivity and how much stuff they can do in a certain amount of time. For me, building a lot of the framework stuff and structure, I think of productivity as how many questions can I not be asked by my team if my component does what it's supposed to do? And if the code makes sense. And I love that with these click handlers, you're forced to name things in Ember. Like I've got to name this go to href rather than just on click and then some random function. I have no idea what you're trying to do. At least now I have a clue about what the developer intended to do by the name of the function. And we all know how often comments that explain things stay up to date. So I get my href, check if I started with a hash, and if so, then I scroll to the href, otherwise I visit the href. If I scroll to it, I go and select that element. If I didn't find one, I just give up. If I did find one, I find the bottom of it on the page, scroll my document down to it, and then update the hash. Otherwise, I just do a window location. So here it is. You see I can tab to these things. If I click about, I scroll down, and the back button doesn't work with this. I didn't know how to make that happen. And then if I click this, it'd send me off to Ember. So that's how the a tag works. It's a component that you're all familiar with. Then I thought, oh, what's in the, oh, no, dang. Oh, well, these were unicorns. And sparkling unicorns. Why did it not open it up? Let me go into Mac and open this guy up. We have a script. I thought, well, I did the anchor tag. This is kind of a weird component also. And so I've got this x script that points to my Bower components, brings in cornify, and then here I actually have a body for a script tag. So a script tag is also a component. If you have a source, it goes and fetches it. If you don't have a source, it yields the body. And so now I've got my x script component. My layout is just a triple mustache to open up or to yield the template without escaping anything. And I don't know what Chris was talking about. Will insert element. I totally have an element here, and I can set a display to none. Chris? Anyway, I don't know how I got this element. I must be magic. But hide the script tag so you don't see the code. And then fetch or yield when it inserts, open an XHR, go get the script, eval the response text, or if I yield, get the text content, and then yield that. And so that last thing is what you just saw, creating a script tag out of that. So this stuff is pretty neat. But aren't we supposed to make stuff that doesn't exist yet? Like I don't know, maybe an X-wing? Uh-oh. Hmm. Easy. All right, where are we going? Heads up. Okay, okay, okay, okay. Let's see if we can get this guy back over to me. Come on, man. So my controls are as they should be. Okay, where are we going? Wrong way. I shouldn't talk, I should just do this, right? All right. It is acting really funny with all the Wi-Fi in here. Whoo! So let's turn this off, and then I'll show you the controls. Nobody know Jameson Dance. He just spoke at Mountain West JS and hooked it up to an Xbox controller, and I was like, oh, dude, that's the greatest component ever. So you can see here when I hit W, I go, and if I keep hitting W, then it turns red, which means I'm at max speed. And if I hit S, then it switches down, and I can go two directions at once. But I've got this concept of opposite directions, right? So if I'm going left and then I hit right, I set the left to zero, and then actually, that just stops everything. And then this side is the point of view, which rotates it or makes it go up and down. And of course, this launches, and I can click all these things to get the same effect. So let's check out this code. Oh, and here's all my actions. All right, so the X-Wing code, to use it, it's just a simple little tag. X-Wing and then a URL to the, I've got an express server that actually controls the thing. It's got a Wi-Fi chip in it, and then I connect to its Wi-Fi, which I was freaking out because I couldn't get connected earlier. Know what my dock type up here? It's kind of how I was flying it. So now I've got my template for the X-Wing. And I've got another abstraction, the X-Wing action. So I just say front. So this action makes it go forward, like tilt forward. And then I bind to the parent components, vals.front. And then I've got these icons, icon arrow, and I can rotate it. And so you see that all these are just the same icon, I just rotate it around. And then left, so it's all the same thing, left, left, left. And then the point of view one, same thing, icon action up, counterclockwise, etc. And these are my icons. Just throw some SVG in, make a template. You don't need any JavaScript, and now you've got icon launch and icon arrow. Now let's look at the JavaScript. Tab index, because when it's not focused, it doesn't fly. So I was trying to have my three-year-old fly it, and he kept clicking outside, and then it wouldn't control it, and it's up on the roof of my in-laws two-story house. And I was walking across it, and it's super steep. I thought I was going to die. So the vals are, I keep track of how fast it's going, so from zero to one. And anyway, that's just for the speed of it. And I've got some opposites here, front, opposite is back, etc. These are all the key things that I respond to in my key map. So then I have one keyboard action on key down, and I throttle it, figure out if I get an action, if I do perform it. And then down here, I can get the action and perform a paired action. That's like left and right, so they cancel each other once it happens. Animation, that was the flip. And then otherwise, I just call some method on here, assuming I've defined it. And then, yeah, just some more stuff. Making an action quest. This is the real magic, is it goes off to an express server, and that express server has the drone library, and that's the thing that actually controls it. Yeah, so that is it. Same controls are for like any first-person shooter you've used before. Greatest component ever. Or is it? What is going on? I hope some of you can appreciate that quote. Doctype public offender. Spacer gift. Yes. Find the height to Y of my controller, and then this is bound to Y. All right, so I can just... Here's a spacer gift component. It's an image, attribute binds to source with height, and then I set its data to... That is a transparent gift. Oops, not anymore. Yeah, there's a transparent gift for you. So use it. This is production ready. So communication. This is often a hard thing for both people and code, especially when you put them together. So how do you get a component to talk to the outside world? And I remember when the core team was sort of screwing around with this idea of components, we were actually making this function called... Actually, I called it component, and then we would get a view, and we'd do an initializer, and then set this.context equals this, and just started messing around with that. And I did a presentation back in Utah at our lunch JS, and I made a slideshow thing, and I had no way to communicate out. And then as components started getting better and better, and then actually shipped, we've got two ways to communicate. It's data binding and actions. And this is fantastic, because now if you build a component, you don't really even have to document it. Like people know, I've got some attributes that I can two-way bind to, or I've got some actions that it might respond to. Instead of in the days of other frameworks or just libraries, you've got to go and read the code or the comments, or go talk to the author at your office who made the thing, and figure out how to actually interact with this, or go read the test that they wrote, et cetera. So let's first talk about data binding. I've got... I'm going to be talking about IC tabs. So at Instructure, our main software is called Canvas. So all of our stuff is prefixed with IC, IC Canvas, IC Dead People. That's coming soon. So IC tabs is something that I just finished a couple of weeks ago, and it's kind of like the state of the art for me on how I build components in number. So I'm going to be talking a lot about it. So one of the use cases that I think is incredibly handy for a tab component is to persist to the query parameters so that you can refresh, and those same tabs are there still, or you can link to a page in that state. So here's my demo. I do IC tabs, and then I say selected index equals country. So that's in my application template. So my application controller down here has query parameters country, and country is set to zero. So the first tab is what will show up. So let's see this in action. So I can click Japan down here in countries, and click Texas in countries. People from Texas are like, that's right. And Canada's like, where are we? Okay. Now if I refresh this, Japan is selected, and then this one was bound to the food on my application controller. So it's pretty awesome. So I actually wanted an API for IC tabs, or I'd say IC tabs, query param equals, and then like a name, and I went into IRC, and the whole core team was like, you're a moron. And Yehud is like, I'm so happy with everyone right now. And I was like, yeah, but what about me? No hard feelings. So that's data binding, which you can see will work all the way with all of the other Ember concepts, where your controller sets the context of your template, or proxies the model anyway, and then query params is just bound to those controller properties, and now your components combine to those controller properties. And so all of the data and the information is flowing the right direction. And when I wanted to do that weird interface of having a query param attribute on my tabs, it was really hard. And I was like poking around, I'm sending Alex messages saying, hey, how do I find the router? And he's like, don't. And so again, productivity for me is making things that I can create and then just forget about. And everyone will use them and they just work. And you get a bug every now and then, for the most part, people will wonder if the thing is active, because GitHub hasn't been updated for several months, but it's because it's done and it works. And Ember provides that for me by making the wrong thing hard and the right thing easy. You saw that query param thing was really easy. So actions. Let's check out how these work. I've got another one called ICMenu. I was talking with another Ryan last night about popovers, and we're saying how it's kind of deceptive. It seems like a really easy problem. And you just click a thing and toggle a property and then have an if in your template and now this thing shows up. But if you start to really think about how a popover works, now you've got this outer click event that you need to deal with, because it's open and then you go click somewhere else. And so you think you're really smart and so you put an event on the body or on the document, and then you plan on some event bubbling up and then checking what was clicked and then closing or not. But you forgot that select tags don't actually propagate the click event all the way up, so that doesn't work. And then you tab and focus them out of their element, and so your thing is still open. So it gets really complicated. And so we have a component for this so that we don't have those kind of weird edge cases happening. And I don't know what people want to do when a menu item is selected. And so I just hand that to their app with my on select event. So when I use IC menu, I make an IC menu item and then I say on select, remove. And that will, that will, I don't know if this is going to open up my code, I don't think it will. That will go, oh never mind, my code's down here. So my application controller's here and I've got actions on that controller removed, so that's going to call remove. Same with save and everything else. So let's check this one out. So I click this menu, pops up, and then I click remove and I get my alert. And like I was saying, this is a pretty tricky thing, so I've got to figure out how to deal with all that stuff. So the thing is, simple tasks, there's no such thing. Except link two and Ember, which is actually a really hard thing, but for us now it's simple. So Ember gives me the primitives to make the things that seem like they should be simple, actually simple for people to use. So no one has to think about that anymore. Another consideration is attribute bindings for accessibility. So when you open up this menu, I'm setting a property called aria expanded true. And that triggers to a screen reader, hey this thing is open. There's also things like aria has pop up and you have aria controls and the aria controls needs to tell the screen reader which element it controls so it knows how to jump the user down there when they do the right keyboard combination. So there's, again, simple things are not actually simple. And with Ember's primitives, I'm able to just bind an attribute to a property. And sometimes it's just a bunch of aliases for me to get something accessible. In my description, I talked about writing and refactoring large components. Components were originally thought of as templates. And in fact, the first version of components in Ember, if you didn't have a template, you didn't get a component. Fortunately, now you don't need templates. So this might be what an X tabs component would look like if this is the first time you're writing a component. You might just think, oh, this will be sweet. I just do X tabs. And I say tabs are your groups. So maybe you're on a group page and you want to make a tab out of each group. And then you're like, now I'm going to do all the hard work down here. And in your template, you create this div and you iterate over the tabs and you make the tabs and you have a label and then you iterate over the tabs again and make your panels. And everyone's happy and it's really easy to use. I won't put my hand there again. There are some problems. Number one is X tabs component does everything. You probably can't read that very well. X tabs component does everything. So it's going to get unwieldy. It's going to be really huge. And everybody's going to start saying things like, oh, no, there's a bug in tabs component. I don't want to go into that code. To be accessible, the tabs need some attributes that get changed. Where are you going to do that when you just have one big component? How are you going to go get those other elements and update their attributes? Now you're getting right back into jQuery spaghetti. Why are we forcing tab.panel and tab.body on people? This is just a tab component. We shouldn't be bound to some sort of data model. And what if we want the tabs on the bottom? My template had them on the top. But does the position of the tabs really have anything to do with the behavior? Or what if I don't even have any data and I just want to make some static tabs? I've just got some static content. I just want to stick it in there. Or even worse, what if I want one static tab and then a bunch of dynamic ones from data? There's just no way to do that when you build these large components with big templates. So instead, what if we did it like this? We make an X tabs and that's a parent thing. Then we have X tab list and that defines the behavior for the list. And then we have an X tab component for the individual tabs. Now each one of the pieces of this component are separated. I call these composite components. So you composite a bunch of smaller components together. So now in this instance, I can have just a static tab called default and then I can have these dynamic tabs for groups. And I'm not bound to some sort of data model. I can just use group.name instead of switching my group stuff into label and stuff like that. The other thing is for these child components can now manage their own state. So if their attributes need to change when they're selected, the tab can just do that itself. It knows it's selected and then it can change its attribute accordingly. You don't have to have some parent big giant thing using jQuery to go and select things and then you're wondering why am I using components? This looks like when I was writing jQuery plugins. Okay, okay, you get it. It wasn't the old thing more convenient. All right, people had to write a whole bunch of stuff now. So instead of doing the huge component, I make what are called convenience templates on top of those components. So I do X tabs top and then tab. So it's right back to that old to the first interface. But now I can compose these tabs however I need to. So on this one I've got tabs on the top. If I want to tabs on the bottom, I just make a new convenience template and move the tab list to the bottom. And everyone else on the team can still just do X tabs top, tabs equals groups and then they're done. So the trick is, oh, and now I have no template because the, well, on the old one. So doing this, you get the composition flexibility with these convenience components without doing crazy hacks. Keep it declarative. Keep it simple. Two things to remember. I have a bias toward no templates. As soon as my component has a template, I start thinking, okay, I'm missing an abstraction in here. And the best way to find where those abstractions are for these subcomponents, just identify them by do they have events? Like if I click a tab, does something happen? Yes? Okay, that should be its own component instead of delegating from some parent and then checking an event.target and determining if it was a tab and then perform some action. And then the second is if you need to manage its class or attribute, depending on the state of the whole component, it should probably be, well, not probably, it should be its own component as well. And the best way that I found to talk about this with people and just myself is to try to think about native elements and the select option combination is just wonderful for this. Think about what it is. You've got two different components, an option tag, which makes no sense outside of a select tag. And you have the select tag and it's got a value. And depending on what you, which option tag you interact with, that's what the value becomes on the parent. And so that's a great reference to when you think about components and how should I abstract this? Try to find a native thing, like a submit button inside of a form. Well, that changes the whole behavior of the form once you have an input type submit down in there. It changes the behavior of hitting enter inside of an input text, right? So just having an input type submit, the whole form reacts to that. Another tip is to test and develop with dynamic data. The great thing about Ember is you get things updated just when you change your data. And everyone who's wrapping Bootstrap or jQuery things, I guarantee you your stuff doesn't work when you go and change your data. Like if you're iterating over and each and creating tabs with Bootstrap, you go change that data, you're going to have to do a lot of tear down and set up management. But if you build these things native to Ember and you consider the dynamic nature of the data that people will give you, you can make them a lot more usable. So to create this tab interface where I can just create these dynamic tabs, and then if I say I delete a tab that is active, and now it's gone, like I've got code in there to say, oh, hey, that thing is gone now. Which one should I select? I should probably select the one previous to it. So again, it doesn't take a whole lot of code for me to build something that used to be really difficult with any other tab kind of component. But when you build it native in Ember, you get this stuff almost for free, but you need to develop with it in mind. And then you also get interesting things like this, where I can bind the data to the selected index. And now anything on the control can be bound to that data, and the template can be bound to that data and control which tab should be active. Distributing your stuff on a container with an application initializer, precompile your templates individually as the layout property of the component. I use a thing called ICStyle that we made for minimum viable amount of CSS for the component to work. It's more than like 10 or 15 lines of CSS is probably too much. And then I use BroccoliDist ES6 module to publish to everything. So this is ICTabs. So you see my main script pulls in everything. I initialize it, register things on the container, and then I export them all. And then I've got my dist that distributes all of these different formats. And so in the case of Browserify, you can MPM install ICTabs, go to your application file, require ICTabs, and then go into your template and just use it, and it'll work and look good. So this is how I distribute it. So if you're looking to distribute things, I don't know if this is the best way yet, but it's the most convenient that I've found for us at Instructure. We are working on a lot of components. You can find them at this address. Only a couple of them have demo pages right now. More are going to be coming and help us out with them. We, Ember, really needs like a few good libraries that we can point to and say, hey, here's some components that you can use and they work with your data. That's it. I'll see you later. Okay?
abstractions in the browser. And they're a little You might not think of this as a component, but button doesn't work with this. I didn't know how X-Wing code, to use it, it's just a simple little the most part, people will wonder if the thing is components in Ember, if you didn't have a just no way to do that when you build these large layout property of the component. I use a thing if this is the best way yet, but it's the most