Introduction
Today, we’ll learn how to use reusable components in Angular. So here, we’ll see how to pass the data from component to Views and we’ll raise the custom events. We’ll apply the styles to the HTML elements in the template.
- Introduction And Setting Up The Environment - Part One
- Typescript In a Nutshell - Part Two
- Building Blocks of Angular - Part Three
- Binding Variations And Displaying Data - Part Four
In this article, we’ll cover
- Component API
- Input Properties
- Aliasing Input Properties
- Output Properties
- Passing Event Data
- Aliasing Output Properties
- Templates
- Styles
- View Encapsulation
- Shadow DOM
- ngContent
- ngContainer
- What we have learned
- Conclusion
Component API
In the last article, we’ve learned property and event binding.
Property Binding (Square Bracket Syntax):
- <img [src]=”imageUrl” />
It is used to bind the DOM objects to fields or properties in a host component. Here is the component that is using DOM objects; in this case, img object.
Another way of thinking about this statement is that this src property is an input into this DOM object. We use this to supply data to this object, supply some state.
Similarly, we use event binding respond to the events raised from the DOM object.
- <button (click)=”onClick()”></button>
In this case, the click event of the button. But the star component we implemented in the last article doesn’t have any property and event binding.
<star></star>It isn’t reusable. Ideally, I want to set the initial state of this star component using some object that we have in the host component. Here, in the app component, let’s say we get the post object from the server.
- @Component({
- selector: 'app-root',
- templateUrl: './app.component.html',
- styleUrls: ['./app.component.css']
- })
- export class AppComponent {
- post = {
- title: "Title",
- isFavorite: true
- }
- }
Input Properties
So, here in the star component, we want to mark the isFavorite field as an input property. So we can use it in property binding expression. And now, there are 2 ways to mark this field as an input property.
- <star [isFavorite]="post.isFavorite"></star>
Here, unfortunately, we can’t use property binding to bind isFavorite field of star component to the post object. This is not going to work. Now just open your browser and here we’ll see this error.

- <star [isFavorite]="post.isFavorite" (click)="onClick()"></star>
And inside that method, we can call the server or do something else. Once again, we need to add support for event binding as well. We need to define the special property in star component that can be referred to as output property.
In other words, in order to make a component more reusable, we need to add a bunch of input and output properties. We use input properties to pass input or state to a component and we use output property to raise events from this custom component. A combination of input and output properties for a component make up what we call Component API (public API of that component).
So now, we don’t have component API in star component because it doesn’t have any input and output properties.
Input Properties
So here in star component, we want to mark the isFavorite field as an input property. So we can use it in property binding expression. There are 2 ways to mark this field as an input property.
- import { Component, OnInit, Input } from '@angular/core';
- @Component({
- selector: 'star',
- templateUrl: './star.component.html',
- styleUrls: ['./star.component.css']
- })
- export class StarComponent implements OnInit {
- @Input() isFavorite: boolean;
- constructor() { }
- ngOnInit() {
- }
- onClick(){
- this.isFavorite = !this.isFavorite;
- }
- }
By default, it is filled because we have to bind our property with the app component post's isFavorite property and we set it to true there. So it is filled. Now our property binding works perfectly.
Now the 2nd approach is to make input property. We use Inputs property in Component declaratory.
- import { Component, OnInit } from '@angular/core';
- @Component({
- selector: 'star',
- templateUrl: './star.component.html',
- styleUrls: ['./star.component.css'],
- inputs: ['isFavorite']
- })
- export class StarComponent implements OnInit {
- isFavorite: boolean;
- constructor() { }
- ngOnInit() {
- }
- onClick(){
- this.isFavorite = !this.isFavorite;
- }
- }
- @Component({
- selector: 'star',
- templateUrl: './star.component.html',
- styleUrls: ['./star.component.css'],
- inputs: ['isFavorite']
- })
- export class StarComponent implements OnInit {
- isSelected: boolean;
- constructor() { }
- ngOnInit() {
- }
- onClick(){
- this.isSelected = !this.isSelected;
- }
- }
- <star [isFavorite]="post.isFavorite" (click)="onClick()"></star>
And the value of isFavorite in app component is true. That’s it; just in fill state, click event is not applying on it because click event is changing the state of isSelected, not isFavorite.
So that’s why it is a bad approach although it is quite clean instead of the first approach but it is not recommended. Most of the time when the language contains multiple ways to do anything then it confuses the beginners in learning. So the best approach to make the input property is by using Input declarator. So this is how we define Input properties.
Aliasing Input Properties
We’ve learned how to define the input properties, now let’s explore how to define the aliasing of input properties.
- export class StarComponent implements OnInit {
- @Input() isFavorite: boolean;
- }
- <star [is-favorite]="post.isFavorite" (click)="onClick()"></star>
Look now we’ve changed the property as is-favorite. Now in Javascript and in Typescript we don’t have this kind of acceptable identifier because we can just make the variable without dash in JS.
So the solution to this kind of problem is to use the alias or a nickname for an input property. So back in star component here we’re using Input declaratory and here we’ll supply the string for the alias of this property.- @Input('is-favorite') isFavorite: boolean;
And now if you run the application, you’ll see it is working without any issue.
This aliasing actually gives the contract of this API stable. Let’s go back to app component and revert back.
- export class StarComponent implements OnInit {
- @Input() isFavorite: boolean;
- constructor() { }
- ngOnInit() {
- }
- onClick(){
- this.isFavorite = !this.isFavorite;
- }
- }
- export class StarComponent implements OnInit {
- @Input() isSelected: boolean;
- onClick(){
- this.isSelected = !this.isSelected;
- }
- }
- @Input('isFavorite') isSelected: boolean;
- <span class="glyphicon"
- [class.glyphicon-star]="isFavorite"
- [class.glyphicon-star-empty]="!isFavorite"
- (click)="onClick()"
- ></span>
- <span class="glyphicon"
- [class.glyphicon-star]="isSelected"
- [class.glyphicon-star-empty]="!isSelected"
- (click)="onClick()"
- ></span>
Output Properties
So now we want to be notified when the user clicks on star. So here we want to raise the custom event ‘change’ and define them in the star component.- <star [isFavorite]="post.isFavorite" (change)="onStarChange()"></star>
- export class AppComponent {
- post = {
- title: "Title",
- isFavorite: true
- }
- onStarChange(){
- console.log('Star Changed');
- }
- }
Now it is the time to make the change event output property. As we use Input declarator, similar here we use @Output declaratory and we’ll initialize @Output declarator variable with EventEmitter() it actually helps us to raise and publish the events.
- import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
- @Component({
- selector: 'star',
- templateUrl: './star.component.html',
- styleUrls: ['./star.component.css']
- })
- export class StarComponent implements OnInit {
- @Input('isFavorite') isSelected: boolean;
- @Output() change = new EventEmitter();
- constructor() { }
- ngOnInit() {
- }
- onClick(){
- this.isSelected = !this.isSelected;
- this.change.emit();
- }
- }
And here is the star component code. We need to call the emit() function with click output property. Now if we run the application
Look it is working fine on star click as we’re printing the console message on Star click.
Passing Event Data
So here we’ll see how to pass event data when raising an event. Here in app component currently we’re just displaying a single message on console.- onStarChange(){
- console.log('Star Changed');
- }
Here we don’t know anything about this event. We’re just raising an event which is displaying the message on console. We even don’t know if the user has marked the object as favorite or not. So we need to change our implementation and pass some data when raising an event. So back in our star component, when we’re emitting the event we can optionally pass some value and this value will be available to all the subscribers of this event. And here in our case, change event subscriber is app component onStarChange() function.
- export class StarComponent implements OnInit {
- @Input('isFavorite') isSelected: boolean;
- @Output() change = new EventEmitter();
- constructor() { }
- ngOnInit() {
- }
- onClick(){
- this.isSelected = !this.isSelected;
- this.change.emit(this.isSelected);
- }
- }
Look here we’re passing isSelected property to change event. Now we’re consuming this star component into app component. So open app.component.ts and make some changes.
- export class AppComponent {
- post = {
- title: "Title",
- isFavorite: true
- }
- onStarChange(isFavorite){
- console.log('Star Changed ', isFavorite);
- }
- }
So we’re just catching the parameter and displaying it into console. And now open app.component.html
- <star [isFavorite]="post.isFavorite" (change)="onStarChange($event)"></star>
- onClick(){
- this.isSelected = !this.isSelected;
- this.change.emit({ newValue: this.isSelected });
- }
And now here $event object is representing a Javascript object that has the property called newValue.
- <star [isFavorite]="post.isFavorite" (change)="onStarChange($event)"></star>
- onStarChange(eventArgs){
- console.log('Star Changed ', eventArgs);
- }
You might be working in some kind of complex project and you want to show the intellisense while you’re working or you want compile time checking. So you need to apply the data annotations for the parameters.
- onStarChange(eventArgs: { newValue: boolean }){
- console.log('Star Changed ', eventArgs);
- }
Look here with the inline annotation we’ve applied the type of the parameter. But it is little bit messy. Now if you remember typescript, we’ve already discussed interfaces. With the help of interface, we can make our implementation more robust and we can make our code clean.
- import { Component } from '@angular/core';
- import { debug } from 'util';
- interface StarChangedEventArgs {
- newValue: boolean;
- }
- @Component({
- selector: 'app-root',
- templateUrl: './app.component.html',
- styleUrls: ['./app.component.css']
- })
- export class AppComponent {
- post = {
- title: "Title",
- isFavorite: true
- }
- onStarChange(eventArgs: StarChangedEventArgs){
- console.log('Star Changed ', eventArgs);
- }
- }
- import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
- @Component({
- selector: 'star',
- templateUrl: './star.component.html',
- styleUrls: ['./star.component.css']
- })
- export class StarComponent implements OnInit {
- @Input('isFavorite') isSelected: boolean;
- @Output() change = new EventEmitter();
- constructor() { }
- ngOnInit() {
- }
- onClick(){
- this.isSelected = !this.isSelected;
- this.change.emit({ newValue: this.isSelected });
- }
- }
- export interface StarChangedEventArgs {
- newValue: boolean;
- }
- import { StarChangedEventArgs } from './star/star.component';
- import { Component } from '@angular/core';
- import { debug } from 'util';
- @Component({
- selector: 'app-root',
- templateUrl: './app.component.html',
- styleUrls: ['./app.component.css']
- })
- export class AppComponent {
- post = {
- title: "Title",
- isFavorite: true
- }
- onStarChange(eventArgs: StarChangedEventArgs){
- console.log('Star Changed ', eventArgs);
- }
- }
To resolve the reference file issue, auto import extension helps us a lot really. And on the opposite side our application is working fine.
Aliasing Output Properties
So earlier we’ve learned how we can use an alias to keep the contract of the component stable. Previously we’ve used an alias for an input property but we can also use an alias on an output property.
- export class StarComponent implements OnInit {
- @Input('isFavorite') isSelected: boolean;
- @Output() change = new EventEmitter();
- constructor() { }
- ngOnInit() {
- }
- onClick(){
- this.isSelected = !this.isSelected;
- this.change.emit({ newValue: this.isSelected });
- }
- }
So here, tomorrow if we decide to change the name of this event from change to something else our application will certainly break or might not work properly. Let’s take an experiment.
- export class StarComponent implements OnInit {
- @Input('isFavorite') isSelected: boolean;
- @Output() click = new EventEmitter();
- constructor() { }
- ngOnInit() {
- }
- onClick(){
- this.isSelected = !this.isSelected;
- this.click.emit({ newValue: this.isSelected });
- }
- }
Now look, the subscriber of Star component is still expecting a change event.
- <star [isFavorite]="post.isFavorite" (change)="onStarChange($event)"></star>
And if you run the application, our component is working properly but doesn’t show the log messages in the console which we’re displaying through onStarChange() event of Star component.
Now you might be thinking that app.component.html contains change event which doesn’t exist then why isn't our application broken. It is because our app component is expecting that it may exist sometimes in the future that’s why it doesn’t give us any error in the browser. But the code actually is broken because event handler onStarChange() is not called. So always it is the better choice to use alias to make sure if in the future we rename this field, the subscriber of the component is not going to break. So,
- export class StarComponent implements OnInit {
- @Input('isFavorite') isSelected: boolean;
- @Output('change') click = new EventEmitter();
- constructor() { }
- ngOnInit() {
- }
- onClick(){
- this.isSelected = !this.isSelected;
- this.click.emit({ newValue: this.isSelected });
- }
- }
And now if we run the application, we’ll see it is working fine. And our onStarChange() method is logging the message in console.
Templates
We’ve seen 2 forms of using template. One way is to use the template externally and then we use the templateUrl property of component metadata to specify the path to the template file and another approach is to use template property. So we can add the template inline here. Now please don’t mix these approaches, you can follow only 1 approach.
- @Component({
- selector: 'star',
- templateUrl: './star.component.html',
- template: '',
- styleUrls: ['./star.component.css']
- })
Now you might ask which approach is better.
It really depends, if you’re building a small component with a very simple template we can add the template here in the component declarator which would be easy to work with and to import it into multiple applications. Yes you can use your component into multiple applications. Just copy your component folder and paste it into any application where you want and just use it like we do here in app component. If your template is more than 5 lines of code, you can think your own that this code is quite busy and too noisy. So in that case the best approach is to store it in the external file.
Now you might think that as it is a separate file so there will be a new request for template files. Actually that’s not the case here. Remove the redundant template.
- @Component({
- selector: 'star',
- templateUrl: './star.component.html',
- styleUrls: ['./star.component.css']
- })
Open your app.component.html and place a heading here with any name.
- <h2>Usama Shahid</h2>
- <star [isFavorite]="post.isFavorite" (change)="onStarChange($event)"></star>

Look all of our external templates are actually bundled along with our javascript code. So there is no separate request to the server to download the template files.
Styles
As we build components, sometimes we need to apply styles on the components. In Angular there are 3 ways to apply styles to a component but first of all let’s remove the unnecessary code.- export class StarComponent {
- @Input('isFavorite') isSelected: boolean;
- @Output('change') click = new EventEmitter();
- onClick(){
- this.isSelected = !this.isSelected;
- this.click.emit({ newValue: this.isSelected });
- }
- }
We’ll see OnInt interfaces later, at the moment we don’t need it. So there are 3 ways to apply styles.
- @Component({
- selector: 'star',
- templateUrl: './star.component.html',
- styleUrls: ['./star.component.css']
- })
- @Component({
- selector: 'star',
- templateUrl: './star.component.html',
- styleUrls: ['./star.component.css'],
- styles: [
- `
- `
- ]
- })











test testPosted Mar 15, 2019, 3:27 PM
Perfect. i understand angular with you series post. thanks very much
Mahesh ChandPosted Sep 5, 2018, 7:59 PM
Wow! Very detailed. Nicely done. I'm not an Angular developer but looks like you've done a great job and spend ton of time on this article. I've updated the title with "In Angular" so if someone searches in Google will probably search that. Cheers!