Container and Presentation Components Using Angular Component Bindings

Lukas Ruebbelke
InstructorLukas Ruebbelke
Share this video with your friends

Social Share Links

Send Tweet
Published 8 years ago
Updated 5 years ago

Angular 2 introduces the concept of inputs and outputs as a mechanism for components to communicate. The most significant advantage of this is that we can create presentation components that are void of any imperative logic as they rely entirely on their parent container component. We will learn how to create inputs and outputs in Angular 1 using isolated scope and the component binding syntax.

[00:00] In this lesson we are going to learn how to use inputs and outputs to create smart and dumb components. In Angular 2 components communicate via the concept of inputs and outputs which is very similar to isolated scope in Angular 1, property data go in and user events come out.

[00:18] This allows us to create components that are dumb in the sense that they contain no logic whatsoever, and their only function is to display data and relay user events back to its parent component. This reduces our testable surface area significantly, because unless Angular has broken, there is really nothing to test. We can then use smart components to coordinate the layout of our dumb components, and then we pass user events back to the appropriate services.

[00:45] We're going to start by building out a categories item component. I've went ahead and put in the styles and the category item module, and so we're going to get started at the category item component. So the first thing we're going to do is import our template, and the we'll go ahead and import our styles, and then we will define our component configuration object. Before I forget, I'm going to export this, then I'll do the template controller as, now the interesting thing about components is that if you do not explicitly define a controller it will just implicitly create one for you.

[01:45] Now in Angular 1 we would define isolated scope by creating a scope object and then saying that we want to pass in a category and set that to two-way databinding. It then turned into bindTo, and it's now bindings. This would work, but we're going to change it to one-way databinding using this > symbol, so it binds from the parent to the child and change detection is only on the parent, not on the child. Now let's update our template, and then we're going to just bind to categoryzitemController, category, this is what we're passing in, and then the main property on that object.

[02:28] Now let's go ahead and add in the categoryItem module to our categories module so that we have connected the dots, and then we'll go ahead and add this as a dependency. From here, we need to update the categories.html to use our categoryItem component. So we'll delete this class first, then we'll delete this, and then we'll go categoryItem, and then we're going to define a category attribute and pass in our category object.

[03:08] Let's hop into the browser, and you can see that it's working, but just to prove that it is, let's go ahead and update this template and we'll just put two exclamation points in here. We'll hop back into the browser, and so you can see that we're rendering the categoryItem component. Now that we've created an input, let's go ahead and create an output. Let's hop back into our categoryItem component, and we want to create an output of selected, so that when an item is selected, then it emits an event that we can bind to.

[03:44] That's just expression isolated scope. We'll capture the ngClick event, and then from here we're going to call categoryItemControl.selected because that is what we defined on our bindings object. Now this has to be in object map, we send parameters back. This is the one gotcha that gets me. We're sending in a category object and then we're passing a categoryItemController. Then within or categories.html, let's update this to capture the selected event, and then we're going to call an onCategorySelected method on our categories controller.

[04:26] We'll just pass in the category. We'll go ahead and scope this to the categoriesList controller. Then we need to um into our categoriesList controller and then define that. We'll go to categoriesList controller, and we'll define this method on categorySelected, and we'll pass in the category. Then from here we're just going to log this output to the command line. So we'll go categorySelected and then we'll just dump the category object that we're passing in. Let's hop into the browser and see this working.

[05:08] We click a category item, you can see that it has been logged to the console. Let's just do a quick review. We created our category item component that has a category input and a selected output. From there, we are binding to the category input and then onClick we're calling categoryItem controller selected, and passing in the category via an object map, as that is our output.

[05:37] Then in our HTML we're passing in category, and the we're binding to the selected output which then in our categoriesItemController, we're capturing the selected event and then deferring that to onCategorySelected which we are logging to the console. Now one thing I want to point out is that you'll notice in the CategoryItems component there is no controller, it's completely dumb. This is how you create smart and dumb components in Angular 1 and in Angular 2 style.

Przemysław
Przemysław
~ 8 years ago

Actually this clip misses a small information about a default controller which is mentioned in previous posts. For people who did see angular documentation (before watching the lesson) it could not be so obvious from were this controller come from. Especially that w rename it by controllerAs. I could be a small statement that $ctrl is a default controller for all components and in this specific example we will take this default and rename it to .....

Ionut-Valentin Mitrache
Ionut-Valentin Mitrache
~ 7 years ago

Why do you pass in an object in the .selected callback ( categoryItemCtrl.selected({category: categoryItemCtrl.category}) ) when you can pass in the categoryItemCtrl.category? This does not make any sense to me. Please explain.

Lukas Ruebbelke
Lukas Ruebbelkeinstructor
~ 7 years ago

This is one of the idiosyncrasies of expression binding... in order to pass values to the parent component, you have to do so via an object map. This is necessary because of how Angular is parsing what is essentially a string and turning it into a callable function.

From the documentation...

Often it's desirable to pass data from the isolated scope via an expression to the parent scope. This can be done by passing a map of local variable names and values into the expression wrapper fn. For example, if the expression is increment(amount) then we can specify the amount value by calling the localFn as localFn({amount: 22}).
Markdown supported.
Become a member to join the discussionEnroll Today