Passing data into Angular components with @Input blog post

Passing data into Angular components with @Input

Todd Motto

3 Sep, 2019

Angular

5 minutes read

In a component-driven application architecture we typically use stateful and stateless components. The key concept is having some form of “stateful” component that delegates data and perhaps tasks (in the form of events) into a “stateless” child, or children, component. In this article, we’re going to explore how to pass data into an Angular component and understand the basis of component architecture.

To pass data into an Angular component, we need to be aware of a concept called property binding, which we learned about in the previous article when we bound to an <input> element to display a count.

The first step to passing data into an Angular component is to create a custom property to bind to. This is done via “input” binding to pass data from one component to another (typically parent to child). This custom input binding is created via the @Input() decorator! Let’s explore.

Follow along with the series:

  1. Bootstrapping your first Angular app
  2. Creating your first Angular component
  3. Passing data into Angular components with @Input
  4. Component events with EventEmitter and @Output in Angular

Introduction

This tutorial will cover passing data into a component, and we’ll be using a Counter component to demonstrate. If you’ve not dived in and learned how to create a component in Angular, check that out here, as we’ll be using the same source code to continue building.

Stateful (parent) component binding

With a stateful component, we would typically render out stateless, or perhaps stateful, components. Taking a stateless counter component, we need to tell Angular that we’d like to pass data into that component, where we can set some initial data to be delegated down into our CounterComponent.

In the previous article, we registered our CounterComponent in our @NgModule which allows us to use it inside our module’s registered components.

Jumping to our AppComponent, this means we can declare it as a custom element inside the template:

// app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <div class="app">
      <counter></counter>
    </div>
  `
})
export class AppComponent {
  initialCount: number = 10;
}

So what about initialCount that we’ve decided to add in this example “stateful” component? We need to bind it to our component!

We learned about property binding in the previous article, and the same applies with our own custom components when we want to create and bind to a property. The difference in creating our own properties to bind to (as opposed to a built-in property) is we have to tell Angular the name of the property binding, essentially exposing it for us to bind to. This will make more sense momentarily, but let’s create a binding called count on our component and pass through our initialCount value:

@Component({
  selector: 'app-root',
  template: `
    <div class="app">
      <counter [count]="initialCount"></counter>
    </div>
  `
})
export class AppComponent {
  initialCount: number = 10;
}

To recap quickly, we’re creating a custom property called count, and supplying the value of initialCount, which can be any number.

@Input decorator, stateless component

Now we’re creating a stateless, or “dumb” component, to pass our data into, which we can mutate locally and get data back out. We’ll be getting new data back out of the component in the next article.

Let’s jump into our CounterComponent (some @Component metadata has been removed for brevity):

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

@Component({...})
export class CounterComponent {

  count: number = 0;

  increment() {
    this.count++;
  }

  decrement() {
    this.count--;
  }

}

There is one key thing we need to do here. At the moment we have a fully isolated component in terms of data, but we need to be able to pass data into this component.

To do this, we can import the Input decorator from the Angular core, and simply decorate the count property:

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

@Component({...})
export class CounterComponent {

  @Input()
  count: number = 0;

  increment() {
    this.count++;
  }

  decrement() {
    this.count--;
  }

}

This decorator tells Angular to treat count as an input binding, and if a piece of data is supplied, the count is then used – otherwise it will default to the value of 0 we added inside the child component above.

And that’s all you need to do! You can create as many inputs as you like, and even change their internal/external property names (see below!).

Bonus: custom property names

It may be that you’d want your “public” property names to differ from the internal input names. Here’s what we might want to do:

@Component({
  selector: 'app-root',
  template: `
   <div class="app">
      <counter [init]="initialCount"></counter>
    </div>
  `
})
export class AppComponent {
  initialCount: number = 10;
}

You can see I’ve changed [count] to [init], so how does this now affect our internal input binding inside the CounterComponent? Currently, this will break and throw us some kind of binding-not-found error:

@Component({...})
export class CounterComponent {

  @Input()
  count: number = 0;

  // ...

}

Why? Because count is no longer being bound to, we’re trying to bind to an init property instead. To keep the internal property name(s) different to the public names, we can do this:

@Component({...})
export class CounterComponent {

  @Input('init')
  count: number = 0;

  // ...

}

We simply pass a string into the @Input() decorator with the name of the property we want to bind to. That’s it, and we can use this.count as usual inside CounterComponent. This gives you some nice flexibility with creating components or composing your very own component library.

Next steps

Wouldn’t it be great to be notified of changes when the internal counterValue (inside CounterComponent) has changed? Well, instead of @Input, we can use @Output and EventEmitterlet’s explore in the next tutorial.

To learn more techniques, best practices and real-world expert knowledge I’d highly recommend checking out my Angular courses – they will guide you through your journey to mastering Angular to the fullest!

About the author

Todd Motto profile picture

Todd Motto

GDE Google Developer Expert

Todd is the Founder of Ultimate Courses. With a passion for Angular, TypeScript and JavaScript, Todd leads the online courses creation and has written hundreds of articles on front-end web development and beyond. He specialises in breaking down complex topics and understands the critical mission of learning new technology fast, comprehensively and the right way.

Love the post? Share it!

Lots of time and effort go into all our blogs, resources and demos,
we'd love it if you'd spare a moment to share them!

Explore our Angular courses

Get started today and join over 60,000 developers.