- Imagine you have an Angular application
with a hierarchy of components,
a high level component like app
which maybe gets data from a REST service.
And imagine there's a lot of data and it's too much
for one component to display because it's complicated.
So what you can do instead
of trying to display all the data from one component
you can define lower level components
to take some of the strain.
And from your high level component,
you can pass some of that data into a lower level component
which knows how to deal with it.
It's like functional decomposition in regular programing.
When you've got a lot of work to do,
you don't put everything into the main function,
it would just be too big.
You define lower level functions
and you pass parameters into them to say,
can you deal with this part of my processing?
So that's what you do in an Angular application.
A high level component often gets the data.
It then passes some of that data
into a lower level component to say, please
can you render this for me in an encapsulated kind of way?
So the lower level component is like a subservient function.
It receives an input from its parent and renders it.
It can also pass events back out like an output parameter.
Sometimes a lower level component needs to notify its parent
that something important has happened
so that the whole webpage can be updated.
So a lower level component can receive inputs
and it can also pass events back out to its parent
to say something interesting has happened
that the whole webpage needs to display.
There's an event mechanism for passing output parameters
from a low level component back to your parent.
I've got an example that helps to put this together.
If you go to lesson 12,
it's example two, the demo app in there.
If you run it, it's gonna, it basically looks like this.
I've got three products
each product I can buy each product displays some data
and there's a Buy button here, okay?
What's actually going on here is I've got
a top level component called app that has all the data.
It has three products.
I've got a lower level component called product component.
Each product component displays one product
and each product component also can generate
a sale event to say, this product has been sold.
This product has been sold, and this product has been sold.
When I click one of these buttons
it generates an event, a sale event
and it passes it back to the top level component.
And the top level component says, oh
did this sale event just occur on that product?
It adds them into a big list of sales
and it displays all the lists at the bottom.
So we're gonna see how this works in this section.
And then afterwards, we'll see how to test it.
How can you pass in parameters into a component
and how can you receive outputs
from a component as an event?
So in that application, there were two components,
the high level AppComponent that receives the data
and passes it down
to a lower level component called product component
which decides how to display it, right?
So let's dig into the code and see how it all works.
I thought a good starting point would be
to define just a simple class to represent a product,
nothing to do with Angular, nothing to do with templates.
It's just basic data.
A product has a description and a category and a price.
It's just a regular, plain old class.
In my code folder,
if you're going to source app, you can see it here.
Okay, so a product just has data that can be displayed.
I also thought it would be useful to define
an interface called sale, to represent information about
when the user clicks on the Buy button for a product,
it generates a sale event to say this product
has just been sold.
So the way you represent events
in Angular is using an interface.
It basically represents information about the event.
When a sale occurs, you need to know the description
of the product that's been sold and the quantity
or how many have been sold.
One of these event objects will be emitted back
to the parent whenever the user clicks the Buy button.
So let's see how the components work, right?
Probably the most important component
in this is the product component.
The product component receives inputs
to say this is the data that you need to display.
And it also has to generate an event, a sale event
back out to the parent
whenever the user clicks the Buy button
to notify the parent component
that another sale needs to be displayed.
So let's have a look at the product component, right?
So here is my low level product component, class definition
my top level AppComponent,
this is how it's gonna hand together.
My top level AppComponent
will basically have three product objects, okay?
And for each product object
it'll pass that into a product component.
I'll write PC, okay product component,
it'll pass it as an input.
It'll pass one product object as an input
to that product component
it'll then create another product component.
I'll pass this product object as an input into that.
So each product component receives as an input,
a product object, basically to render.
So here's my product component class.
Let's go through the code then.
So it has an input property called product.
Okay, so let's look at that.
It receives when a product component is rendered,
it'll receive an input parameter.
It's like a function that receives an input parameter,
input is a standard decorator in Angular.
So my product component, my product component.
If I draw it here,
my product component will automatically receive.
It will automatically be initialized like a parameter.
There'll be a product field
in here which will automatically be hooked up
to point to a product object.
Okay, so my application component will basically
pass a product object, a high definition TV,
it'll pass it into this property.
This property will automatically be initialized
to point to a product passed in by the application.
The exclamation mark is a relatively new addition
in type script.
The type script compiler would likes
to see everything being initialized.
So when you have a field that doesn't seem
to have any construction, you'd get a type script error.
The exclamation mark says it is definitely initialized.
It's just not yet.
You can't see it in the constructor
but it will be initialized by some other mechanism.
The application component will basically pass
in a value to initialize this field.
So it stops the compiler
from complaining about an un-initialized field.
So whenever you have a component that needs
to receive an input to say what data to display input, okay?
That's how you receive the input.
Okay, now what else have we got?
I've got an output property here sale.
So effectively, that means my product component.
If this is my product component
my product component is going to emit an event.
And that event would be called sale.
Like a button click from a button.
My product component can emit a sale event.
Now, technically speaking an event, an output parameter
is an instance of event emitter.
Event emitter is a regular Angular class
and you have to specify what kind
of object when you raise an event
or when you emit an event, you have to pass data out.
And that's what this says.
What kind of object will be emitted?
Well, that's the sale object that we looked at just now.
Okay, when I was showing you the sale interface
basically one of these objects will be emitted
whenever a sale occurs.
Okay, so we'll explain how that happens in a minute.
But basically this sale property is an output event
and it will have in here, like the product description
and the quantity that the user has just bought.
So presumably that sale event will be handled
by my application component.
It's a way of notifying for me down here.
I can notify my parent that a sale has occurred.
So we can basically update the list
of sales being displayed on the webpage.
As it happens,
the way it works is each product has a button.
And when the user clicks this button
this is the event handler function that gets invoked, okay?
So basically the user has clicked Buy on one product.
So what we do is we create a sale object.
We create a sale object to say
what's the description of the product.
So I'm creating a sale object here.
Let's say the product description
is an ultra high definition TV, and what's the quantity?
Well, I've just hard coded that as one.
So I've set the quantity to one.
That sale object I then emit, I say
on this sale emitter, emit the data that I've just created.
Here's the data emitted as the sale event.
So effectively from my product component here
it has just emitted a sale event.
And the object here describes the sale
what product and how many.
So my component can receive inputs
from the parent to say, here's the data you need.
And I can raise events and pass them back
as outputs back to my parent, my parent, presumably be
in the application component to say, handle that event.
Something important just happened, right?
So here's the HTML.
This is the HTML for a product.
It's my product component, HTML.
This is what we see being displayed here
each product will receive a product object.
Okay, so remember in my product component class
it has a field called product.
My application component will have created a product object
and basically passed it in to that, okay?
So my product component has a product field
which points to a product object.
And inside that product object, there's a description,
a category and a price.
So get the product object that takes me over here,
in that product object, get the description,
the category and the price,
get the description, the category and the price
of the product that was passed into me as an input.
Oh, and also when the user clicks the Buy button
it calls the click function.
And remember what that does the click function,
if here's my product component, the click function
it created a sale object
and it admitted that sale object as a sale event.
Okay and my application component can handle the sale event
for my product and update the products
the sales that are displayed.
So I think we've finished looking
at the low level component.
We've seen how to receive inputs.
We've seen how to send outputs.
We need to look at it from the other side
of the coin now and see how the application component works.
So here's my application component,
in terms of code, it's quite simple.
I've got an empty array of products, which I then populate.
So those are the products.
My application component basically owns the data.
So my application component has three products
in an array like that.
And ultimately, what it's gonna do is gonna basically
pass each one as an input into a product component,
it'll create a product component
and pass the ultra high definition TV.
It'll create a second product component
and it'll pass in the second product,
that'll be the carving skis.
And then it'll create another product component.
Basically, each component has an input
for which is one product.
Oh, but also of course,
each of these products can generate a sale event.
Maybe that product's been sold
or that product has been sold.
So I need to handle those events and that's what this does.
We'll see how it hooks up in a minute.
But this is my callback function.
This callback function will handle a sale
that comes from one of these components.
So here it is, it'll handle, it'll receive the sale object,
the product description and the quantity.
It just builds up a string,
high definition TV, quantity one.
And then it adds that string into a list.
I've got an array here.
It's just a list of strings.
That's the list of strings
that is displayed at the bottom of the webpage.
So these are the skills that actually get displayed.
It's just a list of innovative strings.
Right, here is the here's where it all comes together.
So my top level application component,
remember my top level application component
had three products, the TV, the skis, and the boots
and what it does for each of those bits of data
it creates a product component
and it passes it in as an input, okay?
And that's what we see happening here,
so I'm gonna explain that in a moment.
I'm just gonna kind of help you to visualize it first.
So it'll basically create three product components
and it'll pass the product data as an input into each one.
So let's have a look at that.
Then you can write a for loop in Angular.
You can have, this is called a structural directive.
It's a for loop, in Angular for loop
where you give it the array products
and well, so P is going to be one product.
And what it does is it renders the product component.
Remember the product component.
If I go into the product component
remember the product component
it had a selector app product, okay?
So whenever you wanna create a product component
you basically use that, but it has an input parameter.
Whenever you render one of those,
you've gotta give it a product property as an input
and you've gotta handle the possibility
of a sale event to be an output, okay?
So when my application component creates
one of these products
it's gotta pass a product property as an input
and it's gonna handle the sale event as an output.
So this is how you do it render a and app product, right?
So that's going to be a product component.
I'll just write PC.
The product component has a product property
and input property.
Here is how you initialize an input property.
When you render a component.
If that component has an input property,
square brackets, okay, it'll initialize.
It's like passing the parameter into the product property.
So the first product was going to be
the ultra high definition, TV, 1800 pounds,
a bargain like that.
That object is basically hooked up like that.
I've passed in as an input,
I've passed my product as an input to this field.
Also my product component can generate a sale event
as an output.
This is how you handle events.
Well, we know this already.
We've seen this before, when we handle button clicks.
When you have some kind
of element that can generate an event
this is how you say, well, it can generate a sale event.
If the sale event occurs, call this function.
Okay, so that would basically call
if that component generates the sale event
it calls this function.
That's the function we just looked at on the previous slide
it'll grab the sale event, ultra high definition TV
that gets passed in a dollar event.
That's the sale event that my product rendered emitted.
So when the user clicked the Buy button on here,
it emitted a sale object sale event
that gets handled by this function.
This is the sale object that was emitted.
Let me remind you how that worked
in my application component.
My application component can say
there's the sale handler function.
It'll receive the sale event and update the list of sales
in its array.
Right, okay then.
So let's just summarize then app product create
and render a product component for one product.
This is going to be three times
that syntax the square bracket product,
that's how you pass an input parameter
into a product component.
That's the name of the field in the component.
And here's the value you're passing into it.
The round bracket sale handles the sale event
from the component,
hooks it up to this event handler function
in my application.
Finally, we display the sales at the bottom.
Okay, so here are the list of sales.
Sales, remember, is just an array of strings.
So it'll always iterate through that list of sales
and for each sale, it'll dissipate as a string.
There we go.
So that concludes the example.
We've seen how a component
like product component can receive an input from its parent
and how it can emit an output back to its parent
from the parent's perspective
when the parent renders the lower level component,
you can set a property as an input
and you can handle an event as an output.
Okay, so that's a nice example.
What we're gonna do in the next session
is see how to test these components using Jasmine.