Standalone Component : A new approach to design Angular Application

In the past few version released, the Angular team mainly focus on the removal of the Angular’s Framework legacy code block and rendering pipeline. These activities are mainly done with the main focus on performance improvement. As a part of this activity, In Angular 14, the Angular team introduced a new concept of defining the component i.e. Standalone Component. With the help of this concept, we can easily build any application without using the NgModel. This approach makes the Angular application development much earlier for the developers and most importantly, they do not need to understand or consider the concept of NgModule within the application at all.

So, in this article, we will discuss the concept of a Standalone Component in any angular application. 

Angular 16 Standalone Component

Through this article, we will discuss the following topics – 

  • Concept of Standalone Component in Angular Application
  • Benefits of using a Standalone Component
  • How to create a Standalone component-based application using Angular -CLI.
  • Define a Standalone Component with a Child-Standalone Component.
  • Use Routing to navigate between different standalone components.

An Overview of Standalone Component

From Angular 14 onwards, the angular team introduced the concept of the Standalone component. The standalone component is nothing but a simple component that will not be a part of any Angular module. Before Angular 14, whenever we define any component in the Angular application, we need to first declare that component within the Angular module declaration array objects. If we forgot to do that task, then the Angular compiler throws the error. But, from Angular 14 onwards, these steps are not mandatory. Because, now, we can create any component which can not be a part of any component. And that’s why it is called a Standalone component. Just like standalone components, we can also create pipes and directives as well as Standalone. This type of standalone component can be used anywhere in the application like -

  • Within any module-based component
  • Within any other Standalone component as a child component
  • Within route
  • Can use as a lady-loading component.

In Angular 14, this standalone component concept is released as a part of the developer preview. Now, in the latest version of Angular, i.e. Angular 16, we can use the Standalone Component in full swing with full work support for everything like HttpClient, Router, Angular Element, and many more. 

Benefits of using a Standalone Component

As a developer, when we plan to start development work for any Angular-based application now, then we first need to decide whether we will use the legacy NgModule-based application or we will need to use the Standalone component-based architecture. So, before making this decision, we first need to understand the benefits of using a Standalone component. Some of the key benefits which we can achieve by using standalone components are as follows -

  • One of the major reasons for the Standalone component is Reusability. We can use this type of component throughout the application event in different applications. In this way, we can save development time and can reduce the chances of code duplication.
  • As the Standalone component is independent and does not dependent on any modules, so, we can perform unit testing of this component very easily.
  • In the Standalone component, we can perform encapsulation in the concept of the component’s styles and templates. It reduces interference with different components and helps us to maintain a clean codebase.
  • The concept of the Standalone component encourages us to follow modular development. We can break the large application into smaller and manageable modules and can develop those parts then.
  • Another reason for using a standalone component is the isolated state of the component. It means every standalone component can maintain its state, which is isolated from the other parts of the application. 

Create An Angular Application as a Standalone 

Now, in this section, we will discuss how we can create an Angular application as a Standalone component based on using the Angular CLI command. So, when we want to create any angular application as a Standalone, then we just need to add the --standalone prefix at the end of the Angular CLI command. Same logic we can use also while we create the Standalone component, directives, or pipes. 

ng new angular-standalone-component-demo --standalone

Angular 16 Standalone Component

Once the application is created, then it will create the project structure as below.

Angular 16 Standalone Component

If we notice, we can find that in the create application structure, there is no app.module.ts file. It is because we already created this application as a standalone application. Now, if we open the app.component.ts file, we can find out the below code -

import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterOutlet } from '@angular/router';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule, RouterOutlet],
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'angular-standalone-component-demo';
}

In the above example, we can see that standalone attribute under the @Component metadata, which indicates that this component will act as a standalone component. As it is a standalone component, so, we don’t have any NgModule for bootstrapping the component. Now, in the case of a Standalone application, one Standalone component will be treated as a root component and that component we need to bootstrap within the main.ts file as below -

import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config';
import { AppComponent } from './app/app.component';

bootstrapApplication(AppComponent, appConfig)
  .catch((err) => console. Error(err));

Create and Use a Standalone Component 

Now, we have already created the Angular Standalone component-based application. In this demonstration, we will create one basic employee list which will display the employee list and also, and we can add the employee data to that list. For this purpose, we first create an employee list component that will display the list of employees. In this demo, whatever component we will create, all components will be a standalone components. Once we will create that component, the output will be as below -

Angular 16 Standalone Component

Step 1. we need an Employee interface to define the properties of the employee objects as below. For this, we add one new file called employee.ts and add the below code there – 

export interface EmployeeInfo
{
    emp_id : number;
    emp_code : string;
    emp_name : string;
    emp_mobile : number;
    emp_email : string;
}

Step 2. Now, add a new file called app.employee.service.ts and add the below code –

import { EmployeeInfo } from './employee';
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class EmloyeeService {
  public employeeList: EmployeeInfo[] = [];

  ngOnInit(){
    this.employeeList = [
      { "emp_id": 1, "emp_name": "Roger Smith", "emp_code" : "ET0002334", "emp_mobile" : 9830098300, "emp_email": "[email protected]"},
      { "emp_id": 2, "emp_name": "Alex Bob", "emp_code" : "ET0002992", "emp_mobile" : 9830198301, "emp_email" : "[email protected]"},
      { "emp_id": 3, "emp_name": "Stephen Ken", "emp_code" : "ET0001675", "emp_mobile" : 88830098312, "emp_email" : "[email protected]"},
      ];
  }

  getEmployeeList()  {
    if (this.employeeList.length == 0 )
        this.ngOnInit();
    return this.employeeList;
  }

  initializeData(){
    this.getEmployeeList();
  }

  getEmployee(id : number){
    return this.employeeList.find(e=>e.emp_id == id);
  }

  addEmployeeInfo(emloyee : EmployeeInfo){
    this.employeeList.push(emloyee);
  }
}

Step 3. Now, add a new standalone component called app.employee.index.ts and add the below code – 

import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Router } from '@angular/router';

import { EmployeeInfo } from './employee';
import { EmloyeeService } from './app.employee.service';

@Component({
  selector: 'app-employee-index',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './app.employee.index.html'
})
export class EmployeeIndexComponent implements OnInit {
  public employeeList : EmployeeInfo[] = [] ;

  constructor(
    private _employeeService : EmloyeeService, 
    private _route: Router) {

  }

  ngOnInit(){
    this.employeeList = this._employeeService.getEmployeeList();
  }

  navigateUrl(path:string, id:number){
    this._route.navigate([path, id]);
  }
}

Step 4. Now, open the HTML file called app.employee.index.html and add the below code –

<div class="container-fluid">
    <div class="row">

        <h2>Employee Records</h2>
        <div style="position: relative; width: fit-content; float: right;" class="text-right">
            <a class="btn btn-primary" href="/employee-add" role="button">Add Employee</a>
        </div>
        <div class="table-responsive">
            <table class="table table-striped table-sm">
                <thead>
                    <tr>
                        <th scope="col">S.No</th>
                        <th scope="col">Employee Code</th>
                        <th scope="col">Employee Name</th>
                        <th scope="col">Mobile No</th>
                        <th scope="col">Email Id</th>
                        <th></th>
                    </tr>
                </thead>
                <tbody>
                    <tr *ngFor='let emp_data of employeeList'>
                        <td>{{emp_data.emp_id}}</td>
                        <td>{{emp_data.emp_code}}</td>
                        <td>{{emp_data.emp_name}}</td>
                        <td>{{emp_data.emp_mobile}}</td>
                        <td>{{emp_data.emp_email}}</td>
                        <td>
                            <button type="button" class="btn btn-info" (click)="navigateUrl('/employee-view', emp_data.emp_id)">Info</button>
                        </td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>
</div>

Step 5. Now, open the app.component.ts file and import the EmployeeIndexComponent within that component imports array objects.

import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { provideRouter, RouterOutlet } from '@angular/router';
import { EmployeeIndexComponent } from './employees/app.employee.index';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule, RouterOutlet, EmployeeIndexComponent],
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'Angular 16 Application - Standalone App Demo';
  
}

Routing with Standalone Component 

Now, in the above employee index component, we create two buttons – Add Employee and another button for View Employee details. By using these two buttons, we will navigate to the related component with the help of the routes. Now, we will define how we can define routes in the application.

Step 1. Now, add another standalone component called app.employee.view.ts file and add the following code – 

import { Component, OnInit } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { Router } from '@angular/router';

import { EmployeeInfo } from './employee';
import { EmloyeeService } from './app.employee.service';
import { last } from 'rxjs';

@Component({
  selector: 'app-employee-add',
  standalone: true,
  imports: [CommonModule, FormsModule],
  templateUrl: './app.employee.add.html'
})
export class EmployeeAddComponent implements OnInit {
  public employeeList : EmployeeInfo[] = [] ;
  public employee : any = {};

    constructor(
    private _employeeService : EmloyeeService, 
    private _route: Router) {
  }

  ngOnInit(){
    this.employeeList = this._employeeService.getEmployeeList();
  }

  addRecord(){
    var lastNo = this.employeeList[this.employeeList.length-1].emp_id;
    if (lastNo == null)
      lastNo = 0;
    this.employee.emp_id = lastNo +1;
    this._employeeService.addEmployeeInfo(this.employee);
    this.navigateUrl();
  }

  navigateUrl(){
    this._route.navigate(['home']);
  }
}

Step 2. Now, open the app.employee.view.html file and add the following code – 

<h2>Add Employee</h2>

<form>
    <div class="row mb-3">
        <div class="col-sm-4">
            <label>Employee Code</label>
        </div>
        <div class="col-sm-8">
            <input type="text" name="emp_code" [(ngModel)] ="employee.emp_code"/>
        </div>
    </div>
    <div class="row mb-3">
        <div class="col-sm-4">
            <label>Employee Name</label>
        </div>
        <div class="col-sm-8">
            <input type="text" name="emp_name" [(ngModel)] ="employee.emp_name"/>
        </div>
    </div>
    <div class="row mb-3">
        <div class="col-sm-4">
            <label>Email Id</label>
        </div>
        <div class="col-sm-8">
            <input type="email" name="emp_email" [(ngModel)] ="employee.emp_email"/>
        </div>
    </div>
    <div class="row mb-3">
        <div class="col-sm-4">
            <label>Mobile No</label>
        </div>
        <div class="col-sm-8">
            <input type="number" name="emp_mobile" [(ngModel)] ="employee.emp_mobile"/>
        </div>
    </div>
    <div class="row mb-3">
        <div class="col-sm-4">
           
        </div>
        <div class="col-sm-8">
            <input type="submit" value="Submit" class="btn-primary" (click)="addRecord()"/>
        </div>
    </div>
</form>

<a href="#">Back to Home</a>

Step 3. Now, add another standalone component called app.employee.add.ts file and add the following code – 

import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ActivatedRoute, Params, Router } from '@angular/router';

import { EmployeeInfo } from './employee';
import { EmloyeeService } from './app.employee.service';

@Component({
  selector: 'app-employee-view',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './app.employee.View.html'
})
export class EmployeeViewComponent implements OnInit {
  public employee : any = {};
  public employeeId : number = 0;

  constructor(private _employeeService : EmloyeeService,
    private router: Router, 
    private route: ActivatedRoute) {
  }

  ngOnInit() {
    this.route.params.subscribe((params: Params)=> this.employeeId = params['id']);
    this.employee = this._employeeService.getEmployee(this.employeeId);
  }
}

Step 4. Now, open the app.employee.add.html and add the following code – 

<h2>Employee Details</h2>

<div>
    <div class="row mb-3">
        <div class="col-sm-4">
            <label>Employee Id</label>
        </div>
        <div class="col-sm-8">
            <span>{{ employee.emp_id }}</span>
        </div>
    </div>
    <div class="row mb-3">
        <div class="col-sm-4">
            <label>Employee Code</label>
        </div>
        <div class="col-sm-8">
            <span>{{ employee.emp_code }}</span>
        </div>
    </div>
    <div class="row mb-3">
        <div class="col-sm-4">
            <label>Employee Name</label>
        </div>
        <div class="col-sm-8">
            <span>{{ employee.emp_name }}</span>
        </div>
    </div>
    <div class="row mb-3">
        <div class="col-sm-4">
            <label>Email Id</label>
        </div>
        <div class="col-sm-8">
            <span>{{ employee.emp_email }}</span>
        </div>
    </div>
    <div class="row mb-3">
        <div class="col-sm-4">
            <label>Mobile No</label>
        </div>
        <div class="col-sm-8">
            <span>{{ employee.emp_mobile }}</span>
        </div>
    </div>
</div>

<a href="/home">Back to Home</a>

Step 5. So, open the app.routes.ts file and add the below component –

import { Routes } from '@angular/router';

import { AppComponent } from './app.component';
import { EmployeeIndexComponent } from './employees/app.employee.index';
import { EmployeeAddComponent } from './employees/app.employee.add';
import { EmployeeViewComponent } from './employees/app.employee.view';

export const APP_ROUTES: Routes = [
    {
        path: '',
        pathMatch: 'full',
        redirectTo: 'home'
    },
    {
        path: 'home',
        component: EmployeeIndexComponent
    },
    {
        path:'employee-index',
        component:EmployeeIndexComponent
    },
    {
        path:'employee-add',
        component:EmployeeAddComponent
    },
    {
        path:'employee-view/:id',
        component:EmployeeViewComponent
    }
];

Now, we can run the application and test the route functionality.

Routing with Angular Standalone Component 

To access the complete code samples used in this article, please check the below git repository – debasis-saha/angular-standalone-component-demo (github.com)

Conclusion

This article discusses the basic concept of Standalone components in Angular applications. Also, we discussed the steps related to implementing a Standalone component-based application using Angular Framework. Any suggestions, feedback, or queries related to this article are welcome.


Similar Articles