Angular Container and Nested Components

Angular Container and Nested Components

·

7 min read

Introduction

In Angular, a component is a reusable piece of UI that contains a template, logic, and styles. Components can be nested inside other components, forming a tree-like structure called a component hierarchy.

A component that contains other components is called a container component, while the components it contains are called nested components. Container components and nested components work together to build complex UI elements and layouts.

Creating Container and Nested Components

To create a container component in Angular, you can create a component class and a template that contains other components. For example:

import { Component } from '@angular/core';

@Component({
  selector: 'app-container',
  template: `
    <app-nested1></app-nested1>
    <app-nested2></app-nested2>
  `
})
export class ContainerComponent { }

In this example, the ContainerComponent is a container component that contains two nested components: Nested1Component and Nested2Component. The template uses the <app-nested1> and <app-nested2> elements to include the nested components.

To create a nested component in Angular, you can create a component class and a template. For example:

import { Component } from '@angular/core';

@Component({
  selector: 'app-nested1',
  template: '<p>I am a nested component</p>' })
export class Nested1Component { }

In this example, the Nested1Component is a nested component that contains a simple template with a <p> element.

Communication Between Container and Nested Components

There are several ways to communicate between container and nested components in Angular:

Input/Output Properties

Input/output properties allow you to pass data from a container component to a nested component using input properties, and from a nested component to a container component using output properties. For example, a container component can pass data to a nested component using the [inputProperty] syntax in the template:

import { Component } from '@angular/core';

@Component({
  selector: 'app-container',
  template: `<app-nested1 [data]="nestedData"></app-nested1>`
})
export class ContainerComponent {
  nestedData = 'Some data';
}

In this example, the ContainerComponent has a property called nestedData with the value 'Some data'. The template uses the [data] input property to pass the value of nestedData to the Nested1Component.

The Nested1Component can receive the data using an input decorator in the component class:

import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-nested1',
  template: `
    <p>I am a nested component and I received data: {{ data }}</p>
  `
})
export class Nested1Component {
  @Input() data: string;
}

In this example, the Nested1Component has an input property called data decorated with the @Input decorator. The value of the data input property will be set by the container component. The template uses interpolation to display the value of data.

A nested component can pass data to a container component using an output event and the (outputEvent) syntax in the template:

import { Component } from '@angular/core';

@Component({
  selector: 'app-nested1',
  template: `
    <button (click)="sendData()">Send data</button>
  `
})
export class Nested1Component {
  @Output() dataEvent = new EventEmitter<string>();

  sendData() {
    this.dataEvent.emit('Some data');
  }
}

In this example, the Nested1Component has an output event called dataEvent decorated with the @Output

Examples

Customer Management

Imagine you are building a customer management system for a company. The system has a list of customers and a form to add new customers. The list of customers and the form are two different components that need to be reused in different parts of the application.

You can create a container component called CustomersComponent that contains the list of customers and the form:

import { Component } from '@angular/core';

@Component({
  selector: 'app-customers',
  template: `
    <app-customer-list></app-customer-list>
    <app-customer-form></app-customer-form>
  `
})
export class CustomersComponent { }

The CustomersComponent has a template that includes the <app-customer-list> and <app-customer-form> elements, which are the nested components.

The CustomerListComponent is a nested component that displays a list of customers:

import { Component } from '@angular/core';

@Component({
  selector: 'app-customer-list',
  template: `
    <table>
      <tr *ngFor="let customer of customers">
        <td>{{ customer.name }}</td>
        <td>{{ customer.email }}</td>
      </tr>
    </table>
  `
})
export class CustomerListComponent {
  customers = [
    { name: 'John', email: 'john@example.com' },
    { name: 'Jane', email: 'jane@example.com' }
  ];
}

The CustomerListComponent has a property called customers with a list of customer objects. The template uses the *ngFor directive to iterate over the customers array and display the customer names and emails in a table.

The CustomerFormComponent is a nested component that displays a form to add new customers:

import { Component } from '@angular/core';

@Component({
  selector: 'app-customer-form',
  template: `
    <form (submit)="addCustomer()">
      <label>
        Name:
        <input type="text" [(ngModel)]="name" name="name">
      </label>
      <br>
      <label>
        Email:
        <input type="email" [(ngModel)]="email" name="email">
      </label>
      <br>
      <button type="submit">Add Customer</button>
    </form>
  `
})
export class CustomerFormComponent {
  name: string;
  email: string;

  addCustomer() {
    // Add the customer to the list of customers
  }
}

The CustomerFormComponent has two properties: name and email. The template has a form with two input fields for the name and email properties, and a button to submit the form. The addCustomer() method is called when the form is submitted.

The CustomersComponent can be used in any part of the application to display the list of customers and the form to add new customers. The CustomerListComponent and CustomerFormComponent can be reused in other parts of the application as well.

For example, you can use the CustomersComponent in a DashboardComponent that displays the customers in the dashboard:

import { Component } from '@angular/core';

@Component({
  selector: 'app-dashboard',
  template: `
    <app-customers></app-customers>
  `
})
export class DashboardComponent { }

The DashboardComponent has a template that includes the <app-customers> element, which will display the list of customers and the form to add new customers.

Shopping Cart

Here is another real-world example of using container and nested components in an Angular application.

Imagine you are building a shopping cart for an online store. The shopping cart has a list of items and a checkout form. The list of items and the checkout form are two different components that need to be reused in different parts of the application.

You can create a container component called CartComponent that contains the list of items and the checkout form:

import { Component } from '@angular/core';

@Component({
  selector: 'app-cart',
  template: `
    <app-cart-items></app-cart-items>
    <app-checkout-form></app-checkout-form>
  `
})
export class CartComponent { }

The CartComponent has a template that includes the <app-cart-items> and <app-checkout-form> elements, which are the nested components.

The CartItemsComponent is a nested component that displays a list of items in the cart:

import { Component } from '@angular/core';

@Component({
  selector: 'app-cart-items',
  template: `
    <table>
      <tr *ngFor="let item of items">
        <td>{{ item.name }}</td>
        <td>{{ item.price | currency }}</td>
        <td>{{ item.quantity }}</td>
      </tr>
    </table>
  `
})
export class CartItemsComponent {
  items = [
    { name: 'T-Shirt', price: 19.99, quantity: 2 },
    { name: 'Jeans', price: 49.99, quantity: 1 }
  ];
}

The CartItemsComponent has a property called items with a list of item objects. The template uses the *ngFor directive to iterate over the items array and display the item names, prices, and quantities in a table.

The CheckoutFormComponent is a nested component that displays a form to checkout the items in the cart:

import { Component } from '@angular/core';

@Component({
  selector: 'app-checkout-form',
  template: `
    <form (submit)="checkout()">
      <label>
        Name:
        <input type="text" [(ngModel)]="name" name="name">
      </label>
      <br>
      <label>
        Email:
        <input type="email" [(ngModel)]="email" name="email">
      </label>
      <br>
      <label>
        Address:
        <input type="text" [(ngModel)]="address" name="address">
      </label>
      <br>
      <button type="submit">Checkout</button>
    </form>
  `
})
export class CheckoutFormComponent {
  name: string;
  email: string;
  address: string;

  checkout() {
    // Process the checkout
  }
}

The CheckoutFormComponent has three properties: name, email, and address. The template has a form with input fields for the name, email, and address properties, and a button to submit the form. The checkout() method is called when the form is submitted.

The CartComponent can be used in any part of the application to display the list of items in the cart and the checkout form. The CartItemsComponent and CheckoutFormComponent can be reused in other parts of the application as well.

For example, you can use the CartComponent in a CheckoutPageComponent that displays the cart and checkout form in the checkout page:

import { Component } from '@angular/core';

@Component({
  selector: 'app-checkout-page',
  template: `
    <app-cart></app-cart>
  `
})
export class CheckoutPageComponent { }

The CheckoutPageComponent has a template that includes the <app-cart> element, which will display the list of items in the cart and the checkout form.