Deep Dive into Components in Angular

Introduction

Components are the fundamental building blocks of an Angular application. They define views, which are sets of screen elements that Angular can choose among and modify according to program logic and data. This deep dive will explore the structure, functionality, lifecycle, and features of Angular components, as well as how they compare to components in React.

Understanding Angular Components

  1. Component Anatomy:

    • An Angular component consists of three main parts: the template, the class, and the metadata.
    import { Component } from '@angular/core';
     
    @Component({
      selector: 'app-example',
      templateUrl: './example.component.html',
      styleUrls: ['./example.component.css']
    })
    export class ExampleComponent {
      title = 'Hello, Angular!';
    }
    • Template: Defines the HTML view for the component.
    • Class: Contains the data and logic for the component.
    • Metadata: Provides Angular with information about the component, including its selector, template, and styles.
  2. Templates:

    • Angular templates use HTML to define the view. They can include Angular-specific syntax such as interpolation, binding, and directives.
    • Interpolation: Binding component data to the view.
      <h1>{{ title }}</h1>
  3. Data Binding:

    • Interpolation: Used for binding data from the component class to the template.
    • Property Binding: Sets properties of HTML elements or directives.
      <input [value]="title">
    • Event Binding: Responds to user actions.
      <button (click)="handleClick()">Click me</button>
    • Two-way Binding: Combines property and event binding using the ngModel directive.
      <input [(ngModel)]="title">

Question

What is the ngModel?

ngModel enables two-way data binding by combining property binding and event binding. This means that any change in the input field updates the component property, and any change in the component property updates the input field.

  1. Property Binding:

    • Binds the value of the component property to the form input.
    • Syntax: [value]="property"
  2. Event Binding:

    • Updates the component property when the user changes the form input.
    • Syntax: (input)="property = $event.target.value"

ngModel simplifies these bindings into a single syntax:

<input [(ngModel)]="property">

  1. Directives:

    • Angular directives are special markers in the template that tell Angular to do something with DOM elements. There are three types of directives:
      • Components: Directives with a template.
      • Structural Directives: Change the DOM layout by adding and removing elements (e.g., *ngIf, *ngFor).
      • Attribute Directives: Change the appearance or behavior of an element (e.g., ngClass, ngStyle).
  2. Component Lifecycle:

    • Angular components have a well-defined lifecycle managed by Angular. Lifecycle hooks allow developers to tap into key events in the component lifecycle:
      • ngOnChanges: Called when an input property changes.
      • ngOnInit: Called once after the first ngOnChanges.
      • ngDoCheck: Called during every change detection run.
      • ngAfterContentInit: Called after content is projected into the component.
      • ngAfterContentChecked: Called after every check of projected content.
      • ngAfterViewInit: Called after the component’s view has been initialized.
      • ngAfterViewChecked: Called after every check of the component’s view.
      • ngOnDestroy: Called before the component is destroyed.
    import { Component, OnInit, OnDestroy } from '@angular/core';
     
    @Component({
      selector: 'app-example',
      templateUrl: './example.component.html',
      styleUrls: ['./example.component.css']
    })
    export class ExampleComponent implements OnInit, OnDestroy {
      ngOnInit() {
        console.log('Component initialized');
      }
     
      ngOnDestroy() {
        console.log('Component destroyed');
      }
    }

Comparison with React Components

  1. Structure:

    • Angular: Uses separate files for the component class (.ts), template (.html), and styles (.css). This promotes separation of concerns.
    • React: Typically uses JSX to combine HTML and JavaScript in the same file, promoting a single-file component approach.
  2. Templates:

    • Angular: Uses HTML templates with Angular-specific syntax for binding and directives.
    • React: Uses JSX, a syntax extension that allows HTML-like code within JavaScript.
  3. Data Binding:

    • Angular: Supports two-way data binding out of the box with ngModel.
    • React: Primarily uses one-way data binding, with state and props to manage data flow.
  4. Lifecycle Hooks:

    • Angular: Provides a comprehensive set of lifecycle hooks.
    • React: Provides lifecycle methods in class components (e.g., componentDidMount, componentDidUpdate) and hooks (e.g., useEffect) in functional components.
  5. Dependency Injection:

    • Angular: Built-in dependency injection system, allowing services to be injected into components.
    • React: No built-in dependency injection. Typically uses context and hooks for dependency management.

Practical Examples

  1. Simple Angular Component:

    import { Component } from '@angular/core';
     
    @Component({
      selector: 'app-greeting',
      template: `<h1>{{ greeting }}</h1>`,
      styles: [`h1 { color: blue; }`]
    })
    export class GreetingComponent {
      greeting = 'Hello, Angular!';
    }
  2. Simple React Component:

    import React, { useState } from 'react';
     
    function Greeting() {
      const [greeting, setGreeting] = useState('Hello, React!');
     
      return <h1>{greeting}</h1>;
    }
     
    export default Greeting;

Advanced Features

  1. Component Communication:

    • @Input() and @Output(): Angular uses @Input for parent-to-child communication and @Output for child-to-parent communication.
      import { Component, Input, Output, EventEmitter } from '@angular/core';
       
      @Component({
        selector: 'app-child',
        template: `<button (click)="notify.emit()">Notify Parent</button>`
      })
      export class ChildComponent {
        @Input() data: string;
        @Output() notify = new EventEmitter<void>();
      }
  2. Content Projection:

    • ng-content: Angular allows content to be projected into components using the ng-content directive.
      <ng-content></ng-content>
  3. Dynamic Components:

    • Angular can dynamically create components using the ComponentFactoryResolver and ViewContainerRef.
    import { Component, ComponentFactoryResolver, ViewChild, ViewContainerRef } from '@angular/core';
     
    @Component({
      selector: 'app-dynamic',
      template: `<ng-container #container></ng-container>`
    })
    export class DynamicComponent {
      @ViewChild('container', { read: ViewContainerRef }) container: ViewContainerRef;
     
      constructor(private resolver: ComponentFactoryResolver) {}
     
      addComponent(component: any) {
        const factory = this.resolver.resolveComponentFactory(component);
        this.container.createComponent(factory);
      }
    }

Summary

Angular components are the core building blocks of an Angular application, encapsulating the view, data, and behaviour in a modular and reusable way. They are defined using a combination of TypeScript classes, HTML templates, and CSS styles. Angular’s robust component system, with features like data binding, dependency injection, and lifecycle hooks, provides a powerful framework for building complex and scalable applications. Compared to React, Angular offers a more structured and opinionated approach, while React provides greater flexibility and simplicity in its component model. Both frameworks, however, enable developers to create dynamic and responsive user interfaces efficiently.