Become a member
to unlock all features

Level Up!

Access all courses & lessons on egghead today and lock-in your price for life.


    CodeSchool Refactor - Reusable Directives Part 1/2


    In collaboration with CodeSchool, John refactors pieces of the CodeSchool Angular app into a more reusable directives.



    Become a Member to view code

    You must be a Pro Member to view code

    Access all courses and lessons, track your progress, gain confidence and expertise.

    Become a Member
    and unlock code for this lesson
    orLog In




    Man 1: The Code School Shaping Up course ended by extracting HTML into a bunch of different directives. One of the examples is this product description directive, which you can see here, which is an element that loads this product description template.

    Where they left it this product description directive is not very flexible or reusable, because this product object right here is bound all the way back to the product from this repeater in the index file. It's declared here, it goes down into the product tabs which is here, and then back down into the product description where it's shown here. This product is this product from the repeater.

    You can see that this directive is tightly coupled to this container because it relies on this being named product, or else this will break. The way we can fix this is by using the scope. We'll declare a scope, and inside that scope we'll say that an item is the two-way binding, so whatever object we pass in is bound on both sides. If you've seen other things on directives you know there's other options, but this is the main use case so we're just going to focus on this for now.

    This means that if I take item, and wherever I declare this product description I can say item, and then I can pass in the product. That means that I can say this isn't the product, it's whatever gets passed in. You can see if I refresh here, this still works just fine. What this allows us to do is to use this product description directive in other places. Say for example I want to use it outside of that repeater, I can use a product description and then give it an item. We'll just pass in an object with a description, because that's the only requirement. We'll say the description is wow.

    If I refresh here, you can see I have used my description directive outside of this repeater, so it doesn't rely on this product to be defined. I can use this product description directive wherever I want to.

    Let's do a similar refactoring to the other directives inside of product tabs. Let's look at product specs. We'll navigate straight to that. We'll give it a scope, just like we did before, and our scope will have an item. Then where we declare our product specs, we can say item is equal to product. And then in our product specs HTML we can just rename all of the products to item, replace all of them, and then the specs should work just the same as well. Now our product specs directive is reusable outside of that ngRepeat too.

    Lastly in our product tabs we have the product reviews, which we'll hop into and give it a scope again. This time instead of naming it item I'll name it reviewed product and give it two-way binding. I'll hop into the product tabs, I'll say reviewed product. I'll pass in the product, and then inside of the product reviews template, instead of naming this product I'll name it reviewed product to match what we named it in the JavaScript. Refresh here, scroll down to reviews, and you see that this still works.

    Again, the idea being that this reviewed product is set in our product tabs where reviewed product is assigned to product. This product comes from the repeater here and through our directive is where we defined the scope, which says use reviewed product as the name of the product that's going to be passed in, and use that object as an object to bind both ways to.

    To take this to the last step, we'll use the product tabs where this product is being passed in but you don't know where it's coming from because it's coming from the container. Again, this ngRepeat. We'll name this tabbed product. We'll pass in the product in our JavaScript. We'll go down to the product tabs, we'll say the scope is tabbed product with the two-way binding, and then anywhere in our product tabs where we used product, so I'll do a search for this, and replace it with tabbed product. Replace all of them, and you can see that everything still works just fine in our tabs.

    Now you know you can look for tabbed product inside of your JavaScript so that you know where this is coming from. You know that this is being set somewhere on that element so that you know wherever your product tabs are being defined something is being passed into tabbed product, which just happens to be this product. This allows us to completely separate ourselves from this product in the repeater and make everything in this product tabs reusable outside of the ngRepeat.

    To demonstrate this, let's blow up our entire application and only show the tabs for the bloodstone, which means that we can delete everything except for the store controller. We'll need that for our product tabs. We'll pass in a tab product and assign that to store product and bloodstone is number one. We will refresh, and you can see that we get tabs for bloodstone. Specs and Reviews are all there, without any dependencies from our application other than some sort of product item being passed into our tabbed product.