Enter Your Email Address to Watch This Lesson

Your link to unlock this lesson will be sent to this email address.

Unlock this lesson and all 827 of the free egghead.io lessons, plus get Angular 1.x content delivered directly to your inbox!



Existing egghead members will not see this. Sign in.

Just one more step!

Check your inbox for an email from us and click link to unlock your lesson.



Create a Scope Decorator

4:30 Angular 1.x lesson by

Using Aspect Oriented Programming (AOP) techniques, you can easily decorate AngularJS controller methods to add additional behaviors. This can be useful for handling analytics and other common concerns in a typical application.

Get the Code Now
click to level up

egghead.io comment guidelines

Avatar
egghead.io

Using Aspect Oriented Programming (AOP) techniques, you can easily decorate AngularJS controller methods to add additional behaviors. This can be useful for handling analytics and other common concerns in a typical application.

Avatar
Bharat

This seems like rocket science without an example. Could you provide a real-life example of how to use this concept?

In reply to egghead.io
Avatar
Joel

This is the pre-cursor to the example, so hang tight. It's a chicken and egg problem :>

In reply to Bharat
Avatar
eric

I have to agree with the other comment, this walk through is almost entirely incomprehensible on first view. egghead.io really launched me into angular in the beginning, and i was happy to purchase the pro plan, but lately the videos are visually cluttered on the screen, difficult to follow, and seem to be focused entirely on testing instead of actual application.

I understand how important the testing aspect of this is, but i find it easier to follow and understand and really learn the core principals in one video, and then dive into the testing of that method in a separate section. I felt like the earlier videos did this really well.

This is actually a really interesting topic for me, as AOP in angular is a critical part of a project i just started. same with the 'base model' example in the other video. but both videos haven't actually helped me really understand the concepts or execution because they are so fast and only focused on testing, not actually executing in a real-world situation.

that's just my feedback. (sorry, this is the only feedback mechanism you guys have. maybe this is an inappropriate place.)

In reply to Joel
Avatar
Joel

Thanks for the feedback, and I agree with you. I'll take the blame, as Trevor originally delivered this with an example, and I asked him to re-cut in its current form. It would be more coherent, perhaps, is if this video ended with a simple usage example.

These concepts are a lot harder (and arguably more interesting) than what we've covered in the past. There is a huge difference in showing how to use a framework API and how to build a framework API. This video is the start of the latter.

With this in mind, the TDD is a critical aspect of developing framework APIs. Perhaps more so than code that is simply using an API. Skipping the testing portion implies that skipping the testing portion is how it should be done.

In my training and consulting experience, there is a clear stereotype: nobody really tests anything, and they certainly don't test-drive. "Test later" equates to "test never" in practice, and code like this should absolutely be test-driven.

We're working on getting better and continuing to push the envelope with these more advanced topics. It's sorely under-covered subject matter, probably because it is more difficult to teach ;)

In reply to eric
Avatar
Brian

At first, I was leaning towards agreeing, but on a second walkthrough, I followed very well. It's a higher level of js, and I love that my egghead subscription is going to help make me a better js programmer and not just teach me frameworks and tools. I was actually starting to use it less and less, but this kind of stuff will keep me coming back for a long time.

I came from several non-functional programming languages. It took me a while to really understand function scope and closures, and when I finally got that, felt pretty good. Realizing lately that this is the next step. Prototype and such looked so easy I never gave it much thought about it's true power.

Can't wait to see the next vid. I've already started playing around with this, so will be interested to see if it's used the same way I'm envisioning.

In reply to egghead.io
Avatar
Stephen

I'm not sure how to get the sample code running. I see an nginx.conf file in the zip download. Am I expected to run nginx? I don't see Node or Grunt installed either. How do I get it running?

Avatar
Leonardo

I think the correct would be "fn.apply( this, arguments )" and not "fn.apply( fn, arguments )"

Trevor: We can use an Angular factory that returns a function to decorate a scope. In this case, we're going to try to call this afterMethod after a certain function is on the scope. Take a look at this version here. The decorator is called with the scope and then the two function names. Both are defined up here. One takes arguments, one does not. They both increments values on the scope and return values.

For the purpose of testing, we also have a scopeBefore, as in a scopeBefore it's decorated. We make a quick shallow clone of that to validate behavior. For the afterMethod, we're just going use a spy here to validate that it's getting called when we want it to.

Taking a look at the tests quickly, we validate that before. It never calls the afterMethod. This is important just to know that it's working properly, and then we want to validate just before and after things are working as expected, so that plain works the same as it did before. It increments the same value. The signature, the toString method, is the same, and then also that it called the afterMethod, or afterMethodSpy in this case.

We do the same with the withArgs function and it also gets called with arguments.

We're going to run these tests real quick, and in a second we're just going to focus on the plain ones, just to shorten the scope. We have two failing. This makes sense because the two failing are actually this and this. Neither is calling the afterMethodSpy because all we're doing is just returning the scope without any direction. Let's focus on these and that should get us most of what we're looking at here.

First we want to focus on this concept of decorating a method, and I'm going to create a separate function for this. It's going to be called createWrapper, and createWrapper is going to take in a function that is the function we're decorating. It's also going to return a function wrapped around that, and then it's going to return the value of that fn.apply(fn). That is just a way to wrap it really quickly.

Now, because we want the afterMethod called, and we want this returned, we can set a variable here called the orig, and then we're going to apply the afterMethod, and then we're going to return the orig, so what we're doing is calling the initial function first in the afterMethod and then returning what that one would turn in with. All the tests are still doing the same thing because the decorator isn't using this.

This is a pretty simple way to create a wrapper, and if we apply it to the functions as they're defined here, we do it in a for loop, we'll say fName, let's do a quick if check to say that the scope fName is actually a type of function, and then in here, we want to override this value using the createWrapper method, and we override it passing in itself. OK, cool.

Now we have one failing, but it's actually a different failure. It's this toString case, which is interesting, so one of the things we're going to have to deal with here is the fact that this function is going to have a different signature now that it's a new function, but we actually want it to have the original method's signature.

A way to do this is also just to say newFn, and then we'll say newFn.toString, so we're going to override that method as well, and it's going to equal that guy, so we're going to just return this value. That's just kind of proxying down to it, and then when we return newFn we'll have everything we need. Cool.

All four of the tests in the plain section are passing, so we're iterating over this, overriding this function, giving it a new signature. Let's check out withArgs.

OK, we've got a couple failing withArgs, and this is actually because the arguments are not being accounted for here, so that's why we used the apply method here, because we can actually just take the arguments object, just pass it in JavaScript and apply it to both the function and the afterMethod, giving us our full 10 passes.

That's a really quick way to decorate a function and then call another function right after it while maintaining the same initial behavior of the method.

HEY, QUICK QUESTION!
Joel's Head
Why are we asking?