Tutorials Logic, IN info@tutorialslogic.com
Navigation
Home About Us Contact Us Blogs FAQs
Tutorials
All Tutorials
Services
Academic Projects Resume Writing Website Development
Practice
Quiz Challenge Interview Questions Certification Practice
Compiler Tools

Angular Components — Building Blocks Guide

Components

Components are one of the basic building blocks of any Angular application. In Angular 21, all new components are standalone by default - they do not require an NgModule. A component contains HTML to display a view, CSS to style it, and TypeScript to control it. A component is created using the @Component() decorator, which includes a standalone: true property by default and holds the following properties:-

moduleId: [ ]

If it set, the templateUrl and styleUrl are resolved relative to the angular component.

viewProviders: [ ]

List of dependency injection providers scoped to this or current component's view.

template: [ ]

It contains the inline template of the component's view.

templateUrl: [ ]

It contains the external template URL of the component's view.

styles: [ ]

It contains the list of inline CSS styles for styling the component's view.

styleUrls: [ ]

It contains the external stylesheet URLs for styling the component's view.

Standalone Component (Angular 21)
import { Component, signal } from '@angular/core';

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <div style="text-align:center">
      <h1>Welcome to {{ title() }}!</h1>
      <p>Edit this component to get started.</p>
    </div>
  `,
  styles: [`
    h1 { color: green; }
  `]
})
export class AppComponent {
  title = signal('my-angular-app');
}

Component Lifecycle Hooks

A Angular component/directive has a lifecycle that provide visibility into these key life moments and the ability to act when they occur. Once component/directive is getting created, Angular calls the constructor first, and then it calls the lifecycle hook methods in the following sequence.

HookPurpose and Timing
ngOnChanges()Called before ngOnInit() every time, as soon as a bound input property changes.
ngOnInit()Called after ngOnChanges() once the angular component is initialized.
ngDoCheck()Called immediately after ngOnChanges() and ngOnInit() during every change detection run.
ngAfterContentInit()Called once after the first ngDoCheck() and as soon as an angular performs any content projection into the view.
ngAfterContentChecked()Called every time after the ngAfterContentInit() and every subsequent ngDoCheck() as soon as the projected content has been checked.
ngAfterViewInit()Called once after the first ngAfterContentChecked() and as soon as the component view and its child views has been initialized.
ngAfterViewChecked()Called after the ngAfterViewInit() and every subsequent ngAfterContentChecked() and every time the component view and its child views have been checked.
ngOnDestroy()Called once the component is about to destroyed. It unsubscribe Observables and detach event handlers to avoid memory leaks.
Lifecycle Hooks Example
import {
  Component, OnInit, OnChanges, DoCheck,
  AfterContentInit, AfterContentChecked,
  AfterViewInit, AfterViewChecked, OnDestroy,
  signal, input, SimpleChanges
} from '@angular/core';

@Component({
  selector: 'app-lifecycle',
  standalone: true,
  template: `<p>Check the console for lifecycle hook output.</p>`
})
export class LifecycleComponent implements OnInit, OnChanges, DoCheck,
  AfterContentInit, AfterContentChecked, AfterViewInit, AfterViewChecked, OnDestroy {

  name = input('Angular');

  ngOnChanges(changes: SimpleChanges) { console.log('ngOnChanges', changes); }
  ngOnInit()                          { console.log('ngOnInit'); }
  ngDoCheck()                         { console.log('ngDoCheck'); }
  ngAfterContentInit()                { console.log('ngAfterContentInit'); }
  ngAfterContentChecked()             { console.log('ngAfterContentChecked'); }
  ngAfterViewInit()                   { console.log('ngAfterViewInit'); }
  ngAfterViewChecked()                { console.log('ngAfterViewChecked'); }
  ngOnDestroy()                       { console.log('ngOnDestroy'); }
}

Standalone Components (Angular 21 Default)

In Angular 21, all new components are standalone by default. Standalone components do not require an NgModule - they declare their own dependencies directly in the imports array of the @Component decorator. This simplifies the application structure significantly.

Signal-based Component Inputs (Angular 21)

Angular 21 introduces signal-based component APIs as the modern way to define inputs, outputs, and two-way bindings:

  • input() - Declares a signal-based input property.
  • output() - Declares a signal-based output event.
  • model() - Declares a two-way bindable signal property.
Signal Inputs & Outputs
import { Component, input, output } from '@angular/core';

@Component({
  selector: 'app-greeting',
  standalone: true,
  template: `
    <p>Hello, {{ name() }}!</p>
    <button (click)="greet.emit(name())">Say Hi</button>
  `
})
export class GreetingComponent {
  name = input.required<string>();   // required signal input
  greet = output<string>();          // signal output
}
import { Component } from '@angular/core';
import { GreetingComponent } from './greeting.component';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [GreetingComponent],
  template: `
    <app-greeting
      name="Angular 21"
      (greet)="onGreet($event)"
    />
    <p>{{ message }}</p>
  `
})
export class AppComponent {
  message = '';
  onGreet(name: string) {
    this.message = \`Greeted: \${name}\`;
  }
}

Key Takeaways
  • Angular components are the building blocks of every Angular app - each has a template, class, and styles.
  • Standalone components (default in Angular 17+) do not need NgModule - import dependencies directly.
  • Use @Input() to pass data into a component; @Output() with EventEmitter to emit events up.
  • In Angular 17+, use input() signal and output() function instead of decorators.
  • The @Component selector defines the HTML tag used to render the component.
  • Use OnPush change detection strategy for better performance in large apps.
  • Component lifecycle: constructor -> ngOnChanges -> ngOnInit -> ngDoCheck -> ngAfterViewInit -> ngOnDestroy.
Common Mistakes to Avoid
WRONG @Input() data: any
RIGHT @Input({ required: true }) data!: string
Always type your inputs. Use required:true for mandatory inputs to get compile-time errors instead of runtime bugs.
WRONG Subscribing to observables in ngOnInit without unsubscribing
RIGHT Use takeUntilDestroyed() or async pipe
Memory leaks occur when subscriptions are not cleaned up. The async pipe handles unsubscription automatically.
WRONG Putting business logic in the component class
RIGHT Move business logic to a service
Components should only handle UI logic. Business logic belongs in services - this makes testing and reuse much easier.

Frequently Asked Questions

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.