Angular

Passing data into Angular components with @Input

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...

Written by Luci · 3 min 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.

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.

Introduction

This tutorial will cover passing data into a component, and we’ll be using a Counter component to demonstrate.

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.

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 EventEmitter – let’s explore in the next tutorial.

Written by Luci
I am a multidisciplinary designer and developer with a main focus on Digital Design and Branding, located in Cluj Napoca, Romania. Profile

Angular Basics: The CLI and Components

Luci in Angular
  ·   7 min read
0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x