Check out a free preview of the full Ember Octane Fundamentals course:
The "Decorators & Action Decorator" Lesson is part of the full, Ember Octane Fundamentals course featured in this preview video. Here's what you'd learn in this lesson:

Mike describes how to create decorators and action decorators in Ember, and how this solves the problem of which "this" context a function is using by binding the method to the component instance.

Get Unlimited Access Now

Transcript from the "Decorators & Action Decorator" Lesson

[00:00:00]
>> Mike North: So the next thing I wanna do here is move this stuff out to another function. Just cuz I like my actions to be kinda thinned and I want them, just like with the helper I wanna delegate something vanilla as quickly as I can.
>> Mike North: loginAsUserWithID, something like that.

[00:00:26] And I'm gonna just take in value as an argument. We'll leave that to the console logging down here. We'll do what we have been doing. Let me stretch this out so people can see, and,
>> Mike North: I'll this, so effectively all I've done is I've taken the console log, I've moved it into its own method.

[00:00:50] And down here instead of logging directly I've delegated to this method. So let's try this and see what happens, sign in. Okay, we get an error, this.loginAsUserWithId is not a function. I'll do what I usually do in this situation. Step into this, let's see what's going on. And what we'll find,

[00:01:20]
>> Mike North: Is if we look at our stack, there we go, welcome back, stack. Okay, anyone notice a potential problem here, thinking about the fact that this dot function name was undefined? What's getting in our way?
>> Speaker 2: This is your form now.
>> Mike North: This is my form, this is my form, that's the way dom events work.

[00:01:50] Right, if you have no Ember, hardly any Javascript, you just make an HTML file with a form that says on submit equals and then some function, this is what you're going to get. So what we need to do is make sure when this function's called it's called in the context of our component instance, that's the way it's most useful to us.

[00:02:12] That's the way we can make it so that the components Java Script class is sorta an abstraction behind the HTML and the handlebars that we've written. And the way we do this is with our first decorator. So this is a new, hopefully new, in the future, JavaScript language syntax.

[00:02:36] It's currently still in sorta the proposal phase cuz we're trying to get the performance characteristics right, and make sure everyone's happy, browser, vendors, and framework authors and things. Here's what it looks like. So we're gonna import action from Ember object model and you can see we use this at sign here.

[00:02:59] Now, all decorators are our functions that have a particular kind of signature, and it looks like this. myDecorator,
>> Mike North: obj, propName. So I have basically just made a decorator here. And I can do myDecorator, getting no errors. And so if we were to do that, or find ourself in this debugger right inside myDecorator, the object is the component subclass.

[00:03:40] And the propName is whatever we decorated, that's it, that's all decorators are. That special syntax basically says as we're setting this class up, it happens at class construction time. Gives us an opportunity to do whatever is possible with these two pieces of information. And in this case, what action is doing, part of what it's doing and the only part we care about for this course is binding that method to the component instance, so that no matter how it's invoked, this will always be the component.

[00:04:16] But I'm just trying to show you kinda what a decorator is, just cuz not a lot of people have seen this. Some frameworks like Angular use this very heavily. We have decided that this is a critical part of enabling native class usage with Ember.
>> Speaker 2: Can you stack decorators like that and order of invocation matters?

[00:04:36]
>> Mike North: You can, yes, top to bottom. It's basically just like this.
>> Mike North: Think of it like that, sorta inside out, right? So the lowest decorators and vote, let me be clear. It's not it's not top to bottom, it's bottom to top. Because they are functions and it's basically a transform for this.

[00:05:07] Let me add the action decorator back in, right? So this is the method and it's passed into this, and we get to do whatever we need to do in there and then the result of that is passed into this. We get to do that, so just think about them in terms of functions, even though they have sort of a new syntax, but they align with invocation order of functions.

[00:05:30] And the most likely outcome of the proposed syntax will be if you wanted to export something. It would be the returned value of action, whatever it does. You would export that, sorry, like this. Obviously you can't export a method, but I just wanna come full circle and say it is as if they're functions.

[00:05:51] And they are functions, the only thing that's different is the syntax. Lets you kinda be a little be more declarative. So let me clean up here, and get back to normal,
>> Mike North: Valid syntax here, we don't need this anymore. That's my mini crash course on decorators. If we try this again, select a user and hit sign in, now, well, I'll just let it play through, clear the console, and the logging is successful, right?

[00:06:27] Now that is proof that this is now correct and you could thread this action. Once something is decorated like this, you can pass it into a component, which goes into a child component, which is held until later and then plucked off and reused, and you're guaranteed, there's no way to change it.

[00:06:46] It will always be invoked with this being set up properly. And this is the way we advise setting up actions. Decorate them at the definition site, and then use the function kinda naturally in your templates. You can trust that everything will be right. What's cool about this is there are no more restrictions on where actions can necessarily live.

[00:07:13] Later we'll see we can even put an action on a service because all it is, it's a function that's bound to the object it lives on and we can sorta thread that through and put it where it needs to go and everything's golden.