Write Angular like a pro. Angular Icon

Follow the ultimate Angular roadmap.

Passing data into Angular components with @Input

Angular components are the building blocks of applications, and component communication via one-way data flow is the key to writing clean Angular applications.

In this tutorial you’ll learn how to pass data into an Angular component using the @Input decorator and custom property binding. Angular is built upon property binding, so learning this is essential.

No components are created equal, there are parent and child components…

A parent component is likely responsible for retrieving data and passing it to the correct components for rendering and user interaction.

✨ This introduces the concept of a smart, or “container” component. A container component is smart because it has awareness outside of the Angular component tree - for example it retrieves data from a Service.

Once that data is available it’s time to delegate the rendering, and behavior, down to a dumb component (or presentational component).

Smart components are aware of things outside of the Angular component tree, whereas dumb components are not.

Let’s begin with a simple smart container component that receives a list of menu items and renders them:

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

@Component({
  selector: 'menu',
  template: `
    <div *ngIf="items$ | async as items">
      <div *ngFor="let item of items">
        {{ item.name }}
        {{ item.price }}
      </div>
    </div>
  `
})
export class MenuComponent implements OnInit {
  items$: Observable<Item[]>;

  constructor(private menuService: MenuService) {}

  ngOnInit() {
    this.items$ = this.menuService.getAll();
  }
}

Assume that menuService.getAll() returns a list of menu items to render as an Observable, hence the async pipe.

But, our template is not using any components, which is fine to begin with but we need to break down our logic to keep our application clean and separated. One component should perform a specific role in your application - so let’s turn our component into this:

@Component({
  selector: 'menu',
  template: `
    <div *ngIf="items$ | async as items">
      <menu-item 
        *ngFor="let item of items"
        [item]="item">
      </menu-item>
    </div>
  `
})
export class MenuComponent {...}

Which means we need a <menu-item> component and pass each item down. For this, you can see [item] which is a property binding. A property binding creates a communication path on our custom element for Angular to understand. Without it we’d see an error like “cannot bind to property item”.

So, let’s create it and set it up to receive each item via an @Input - our first presentational component.

For this, we import the Input decorator from @angular/core and declare it inside the component against a property name we wish to bind to:

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

@Component({
  selector: 'menu-item',
  template: `
    <div>
      {{ item.name }}
      {{ item.price }}
    </div>
  `
})
export class MenuItemComponent {
  @Input() item: Item;

  constructor() {}
}

The @Input decorator then tells Angular to create a property binding to the item property that we bound to using square brackets [], which lets us reference item in the component and any properties such as name and price.

As our parent container component is in charge of rendering our child presentational component, the data is already available to us - so we don’t need any Observable references or constructor logic - we can simply use it to render out based on the @Input data passed into the component.

Here’s a StackBlitz example of what we’ve done so far:

Before you leave there’s one more thing to show you - custom property names. This helps us keep our child component the same, but bind to a different named property.

This is not that common to use, but well worth understanding. If you want to keep your internal class property name, but bind to a different property on the component you can use this syntax by passing a string with a value into the @Input decorator, for example @Input('product'):

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

@Component({
  selector: 'menu-item',
  template: `
    <div>
      {{ item.name }}
      {{ item.price }}
    </div>
  `
})
export class MenuItemComponent {
  @Input('product') item: Item;

  constructor() {}
}

This then allows us to keep the item: Item naming inside our component but bind to [product] instead:

@Component({
  selector: 'menu',
  template: `
    <div *ngIf="items$ | async as items">
      <menu-item 
        *ngFor="let item of items"
        [product]="item">
      </menu-item>
    </div>
  `
})
export class MenuComponent {...}

Notice how we use [product] above instead of [item]. There may be various reasons why you wish to adopt this approach, but at least you know ‘how’.

This gives you some flexibility with creating component property names that may conflict with “built-in” HTML or JavaScript property names, or use it for composing your very own component library and namespacing the property name when it’s used publicly.

Next steps

Next you’ll want to dive into the Output Decorator and EventEmitter to complete the circle of one-way data flow and component communication.

I’d also highly recommend checking out my new Angular courses that will guide you through every step of the Angular ecosystem (and more).

Learn Angular the right way.

The most complete guide to learning Angular ever built.
Trusted by 82,951 students.

Todd Motto

with Todd Motto

Google Developer Expert icon Google Developer Expert

Related blogs 🚀

Free eBooks:

Angular Directives In-Depth eBook Cover

JavaScript Array Methods eBook Cover

NestJS Build a RESTful CRUD API eBook Cover