This post is for young web developers who have just started their careers in web development or are still looking to learn Angular for frontend development. In this post, we will look at Angular Components and will deep dive to understand the what, the how, and the why, along with a component’s lifecycle, communication between components, etc.
What is an Angular Component?
Angular components are the key feature of an angular application. You can build your whole application by composing it from a bunch of angular components which you can create on your own. Angular components use special Decorators (Decorators are a typescript feature that allows you to separate classes without manipulating the original source code. They always start with @
) like @Component
, @NgModule
, etc.
There is a root component (app-component
) that contains our entire application. It is the component in which we nest or other components. We can call other components in the template of the root component HTML (app-component.html
).
Why do we use Angular Components?
As mentioned above, the angular component provides the structure of a block in an application which can be used multiple times and makes the code reusable. It helps us to split a huge code into various small-small blocks which are easy to understand, use, maintain and debug(if needed).
Advantages of using angular components are:
- Uses Typescript.
- Supported by Google.
- Uses POJO (Plain Old Java Object which is just a java object, not bound by any special restriction).
- Declarative UI.
- Easy Testing.
- Easy to maintain.
- Improve readability.
- Reusability.
- Code consistency.
- Compact size.
How do we use Angular Components?
A component in angular is typically a typescript class that angular could instantiate to make objects based on the architecture we write up in the typescript file (demo-component.component.ts
) mentioned below as DemoComponent
. In this example, the @Component
decorator marks a class as an angular component and provides data that specifies how the component should be processed, observed, and used at runtime. You can see that the DemoComponent has a namespace used in its selector. Namespaces are used to basically maintain and organize our code in a proper manner.
An example of a small Angular component typescript file is given below:
import {component} from '@angular/core'; @Component({ selector : 'app-demo-component', templateUrl: './demo-component.html', styleUrls: ['./demp-component.scss'] }) export class DemoComponent { title : String = "Demo Component example"; }
In the above example,
- Selector – Selector is used for including the template anywhere in the application. Like
<app-demo-component></app-demo-component>
. - Template – The template in the component defines the basic UI of the component which is in HTML format.
- TemplateUrl – TemplateUrl consists of the path of the HTML file which contains the UI of that component.
- StyleUrls – StyleUrls is an array that consists of the Styling files used in the component.
Note: We can use either Template or TemplateUrl in an Angular Component
How do Angular components communicate with each other?
Angular components have a relationship amongst them which helps in communicating between those components. The component can either be a parent component (root component) or a child component (other than the root component). We can call as many child components which are required in a root component.
The sharing of data between these components is done in the following ways:
- Parent to child communication
- Data sharing between the parent and child component is done via the
@Input
decorator. This decorator binds the data to be shared through the templates.
Syntax:@Input() dataFromParent: String;
Here
@Input
is the decorator used for binding the Input,dataFromParent
is the input variable andString
is the datatype of the input variable. - Data sharing between the parent and child component can also be done via the
@ViewChild
decorator. It basically allows the developer to access the instance (class, methods, etc) which are described in the child component through the Parent component. It basically allows access to the whole child component in the parent component. Syntax:@ViewChild(ChildComponent) child : ChildComponent;
Here
@ViewChild
is the decorator used for binding the component, thechild
is the input variable andChildComponent
is the component which is being called here.
- Data sharing between the parent and child component is done via the
- Child-to-parent communication – Data sharing between the child and parent component is done via
@output
decorator. This decorator emits data (event) from a child component to the parent component. Syntax:@Output() dataFromChild = new EventEmitter();
sendDataToParent(){ this.dataFromChild.emit("Data is retrieved from child component"); }
Here
@Output()
is the decorator used for binding the output,dataFromChild
is the output variable which is the instance of theEventEmitter
(the class used to emit data based on events and have the emit function) - Siblings communication – Sibling communication is the type of communication in which components are connected not via direct relationships. Like a component is a child of root component and another component is a child of the root component. For this, we create Services in Angular applications. Service is basically a class with a well-defined purpose. It only does a specific job. It may consist of values, functions, features, etc as per the requirement of the parent component.
For example:// data.service.ts export class DataService{} // Component import { DataService } from './data.service'; export class Component { constructor(private dataService : DataService){} get data(): string{ return this.dataService.serviceData(); } set data(message: string){ this.dataService.setMessage = message; } }
Here the DataService is the service used for binding the data between two components that are not directly related to each other,
dataService
is the instance of the service DataService and it is accessed in the component through it.
Angular components Life Cycle hooks?
Angular components can control their runtime behavior by implementing various life-cycle hooks. The instance of angular components has a lifecycle that creates, updates, and destroys the angular components. Developers can use the exact and specific moments in the lifecycle by implementing the lifecycle hooks(one or more) interface from the Angular Core Library.
The lifecycle of an angular component is defined below:
ngOnChanges()
- It is called before
ngOnInit()
. - It is called when the component detects any change in the data-bind input properties.
- If the component does not have any change in the data-bind input properties then this function is not called.
For example:
ngOnChanges (change: SimpleChange){
console.log(change, “changes”);
}
ngOnInit()
- Called after the first
ngOnChanges()
. - It is initialized when the component is first loaded with data-bound input properties.
For example:
ngOnInit(){ console.log(“NgOnInit”); }
ngDoCheck()
- Called after every
ngOnChanges()
when the change is detected and immediately after the firstngOnInit()
. - It acts upon the changes which angular won’t be able to detect on its own.
For example:
ngDoCheck(){ console.log(“ngDoCheck”) }
ngAfterContentInit()
- Called only once after the first
ngDoCheck()
. - Responds after the angular initializes the component with the component’s content.
For example:
template: 'Click here'
ngDoCheck(){ console.log("ngDoCheck"); } ngAfterContentInit(){ console.log("ngAfterContentInit"); } onClick(){ console.log("Link Clicked"); }
Output:
ngDoCheck ngAfterContentInit Link Clicked ngDoCheck
ngAfterContentChecked()
- Called immediately after the
ngAfterContentInit()
and everyngDoCheck()
. - Responds after angular checks the content that is projected in the component.
For example:
template: 'Click here'
ngDoCheck(){ console.log(“ngDoCheck”); } ngAfterContentInit(){ console.log("ngAfterContentInit"); } ngAfterContentChecked(){ console.log("ngAfterContentChecked"); } onClick(){ console.log("Link Clicked"); }
Output:
ngDoCheck ngAfterContentInit ngAfterContentChecked Link Clicked ngDoCheck ngAfterContentChecked
ngAfterViewInit()
- Called once after the first
ngAfterContentChecked()
. - Responds after the angular initializes the component with the component’s view and child views.
For example:
template: 'Click here'
ngDoCheck(){ console.log("ngDoCheck"); } ngAfterViewInit(){ console.log("ngAfterViewInit"); } onClick(){ console.log("Link Clicked"); }
Output:
ngDoCheck ngAfterViewInit Link Clicked ngDoCheck
ngAfterViewChecked()
- Called immediately after the
ngAfterViewInit()
and after everyngAfterContentChecked()
. - Responds after angular checks the component’s view and child views.
For example:
template: 'Click here'
ngDoCheck(){ console.log("ngDoCheck"); } ngAfterViewInit(){ console.log("ngAfterViewInit"); } ngAfterViewChecked(){ console.log("ngAfterViewChecked"); } onClick(){ console.log("Link Clicked"); }
Output:
ngDoCheck ngAfterViewInit ngAfterViewChecked Link Clicked ngDoCheck ngAfterViewChecked
ngOnDestroy()
- Calls just before the angular component are being destroyed.
- It is used to clean up the angular components. Unsubscribing the observables or detachment of event handlers is done here.
For example:
ngAfterContentInit() { console.log("ngAfterContentInit"); } ngOnDestroy() { console.log("ngOnDestroy"); }
Output:
ngAfterContentInit ngOnDestroy
Here ngOnDestroy()
is called just after ngAfterContentInit()
.
Angular Constructors
Constructor was never a part of the Angular component lifecycle. It is a predefined default method of the typescript class. The constructor is always called before any other instance of the lifecycle hook.
The best practice is not to do anything in the constructor and use it for classes that are going to be injected.
For example:
//data.service.ts export class DataService {} //Component import { DataService } from './data.service'; export class Component { constructor(private dataService: DataService) {} get data(): string{ return this.dataService.serviceData(); } set data(message: string){ this.dataService.setMessage = message; } }
Source code
You can access the source code explaining all the concepts described in the blog post here.
About the author
Aditya is the AVP of Engineering at Goals101. He started his coding with javaScript and now moving towards Angular projects at Goals101. Aditya spends most of his time learning and executing Angular codes. When not coding, you can find Aditya solving sudoku and learning about new gadgets & cars.