Angular Standalone Components Example

By Arvind Rai, May 26, 2023
On this page we will learn to create standalone components in Angular application.
1. Standalone components are those components that enable us to build applications without using NgModules. Standalone components specify their dependencies directly and can run without NgModule.
2. To mark a component, directive and pipe as standalone, just use standalone: true within their respective decorators.
3. The standalone APIs are introduced in Angular 14 in developer preview mode. In Angular 15, these are marked as stable API.
4. The advantages of writing standalone components are simplified and reduced coding and need not to use NgModule.
5. The standalone component resolves dependencies using imports attribute. A standalone component can import modules, standalone components, standalone directives and standalone pipes.
6. Standalone component is bootstrapped using bootstrapApplication from src/main.ts file.
7. Find a simple standalone component.
src/main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { Component } from "@angular/core";

@Component({
    selector: 'app-root',
    standalone: true,
    template: ` 
        {{msg}}
    `
})
export class MainAppComponent {
    msg = "Hello World!";
}

bootstrapApplication(MainAppComponent);  
src/index.html
------
<body>
  <app-root></app-root>
</body> 
------ 

1. Project Structure

Now we will create a demo standalone Angular application with parent-child components, directives and router. Find the project structure of our demo application.
Angular Standalone Components Example

2. Creating Standalone Component

Standalone components are created using standalone: true within @Component decorator. They import modules, standalone components, standalone directives and standalone pipes to resolve the dependencies. Now find the components of our example.
src/main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { Component, OnInit } from "@angular/core";
import { Person } from "./services/person";
import { PersonService } from "./services/person.service";
import { PersonComponent } from "./components/person.component";
import { MsgDirective } from './directives/msg.directive';
import { RouterModule, provideRouter } from '@angular/router';
import { ROUTES } from './constants/routs.constant';

@Component({
    selector: 'app-root',
    standalone: true,
    imports: [
        RouterModule,
        PersonComponent,
        MsgDirective
    ],
    templateUrl: './main.component.html'
})
export class MainAppComponent implements OnInit {
    title = "Person List";
    persons?: Person[];
    constructor(private service: PersonService) { }
    ngOnInit() {
        this.service.getAllPersons().subscribe(data => {
            this.persons = data;
        });
    }
}

bootstrapApplication(MainAppComponent, {
    providers: [
        PersonService,
        provideRouter(ROUTES),
    ]
}); 
1. The provideRouter requires RouterModule, so we need to import it using imports within @Component decorator.
2. The imports can import modules, standalone components, standalone directives and standalone pipes. So PersonComponent and MsgDirective must be marked as standalone: true.
3. To bootstrap the application, we need to configure our standalone component using bootstrapApplication in src/main.ts file.
4. We can configure services and routes using bootstrapApplication. The provideRouter is used to configure routes.
5. Include selector app-root of component in index.html as usual.

Now find the HTML code.
src/main.component.html
<ul>
  <li *msgLoop="3">
    Hello World!
  </li>
</ul>
<h3>{{title}}</h3>
<app-person [allPersons]="persons"></app-person>

<router-outlet></router-outlet> 
src/components/person.component.ts
import { Component, Input } from "@angular/core";
import { CommonModule } from "@angular/common";
import { Person } from "../services/person";
import { RouterModule } from "@angular/router";

@Component({
  selector: 'app-person',
  standalone: true,
  imports: [
    CommonModule,
    RouterModule
  ],
  templateUrl: 'person.component.html',
  styleUrls: ['person.component.css']
})
export class PersonComponent {
  @Input('allPersons') persons?: Person[];
} 
The CommonModule enables to use ngIf, ngFor etc. src/components/person.component.html
<div *ngFor="let p of persons">
  <p>{{p.name}} | <a [routerLink]="['/person-detail', p.id]">View Detail</a> </p>
</div> 
src/components/person.component.css
p {
  color: rgb(5, 124, 235);
  text-indent: 25px;
  text-transform: uppercase;
} 
src/components/person-detail.component.ts
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';
import { CommonModule } from '@angular/common';
import { switchMap } from 'rxjs/operators';
import { Person } from '../services/person';
import { PersonService } from '../services/person.service';

@Component({
    standalone: true,
    imports: [CommonModule],
    template: `
    <div *ngIf="person">
      <h3>Details</h3>
      {{person.id}} - {{person.name}} - {{person.age}} - {{person.city}}
    </div>
    `,
    styles: ['div { font-weight: bold}']
})
export class PersonDetailComponent implements OnInit {
    person?: Person;
    constructor(private route: ActivatedRoute,
        private personService: PersonService) { }
    ngOnInit() {
        this.route.params.pipe(
            switchMap((params: Params) => this.personService.getPersonById(+params['id']))
        ).subscribe(person => this.person = person);
    }
} 

3. Creating Standalone Directive

Standalone directives are created using standalone: true within @MsgDirective decorator.
src/directives/msg.directive.ts
import { Directive, TemplateRef, ViewContainerRef, Input } from '@angular/core';

@Directive({
    selector: '[msgLoop]',
    standalone: true
})
export class MsgDirective {
    constructor(private templateRef: TemplateRef<any>,
        private viewContainer: ViewContainerRef) { }
    @Input('msgLoop') set loop(num: number) {
        for (var i = 0; i < num; i++) {
            this.viewContainer.createEmbeddedView(this.templateRef);
        }
    }
} 

4. Configure Routs

In Angular standalone application, provide-prefixed functions can be used to configure different systems. To configure routes, use provideRouter within bootstrapApplication.
src/constants/routs.constant.ts
import { Route } from "@angular/router";
import { PersonDetailComponent } from "src/components/person-detail.component";

export const ROUTES: Route[] = [
	{ path: 'person-detail/:id', component: PersonDetailComponent },
]; 
The PersonDetailComponent must be a standalone component.
src/main.ts
------
bootstrapApplication(MainAppComponent, {
    providers: [
        ------
        provideRouter(ROUTES),
    ]
}); 

5. Configure Services

Find the service used in our example.
src/services/person.service.ts
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { Person } from "./person";

@Injectable()
export class PersonService {
  getAllPersons(): Observable<Person[]> {
    return of(
      [
        { id: 101, name: 'Mohit', age: 25, city: 'Varanasi' },
        { id: 102, name: 'Krishn', age: 30, city: 'Delhi' },
        { id: 103, name: 'Shiv', age: 35, city: 'Patna' }
      ]
    );
  }
  getPersonById(pid: number) {
    return this.getAllPersons().pipe(
      map(allPersons => allPersons.find(p => p.id === pid))
    );
  }
} 
We can configure services using bootstrapApplication.
src/main.ts
------
bootstrapApplication(MainAppComponent, {
    providers: [
        PersonService,
        ------
    ]
}); 
Services can also be configured using providedIn: 'root' within @Injectable decorator.
@Injectable({
    providedIn: 'root'
})
export class PersonService {
} 
Find the output.
Angular Standalone Components Example

6. Reference

7. Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI
LEARN MORE








©2024 concretepage.com | Privacy Policy | Contact Us