Generic component with Angular 6 CLI

Generic component with Angular 6 CLI

The @Input() decorator in Angular 6

We will use the @Input() decorator to create a component which is kind of "dumb" it has only one purpose, display data! With dumb i mean, there should be no logic at all inside this component. The logic and the data should be mutated only from one source, called the single source of truth (SSOT)!

This is the explanation from the angular docs.

"Decorator that marks a class field as an input property and supplies configuration metadata. Declares a data-bound input property, which Angular automatically updates during change detection."

You can think of it as a kind of constructor of the component but it is not the constructor! The @Input defines which properties can be injected from outside. The injected data is bounded and angular handles the change detection automatically. Let me try to demonstrate it with a example

Let's refactor our code to this approach. We have created a list of post titles in the last section and recognized a disadvantage of it. There is no way of reusability. We have to code it in a more generic manner.

First of all, import the Input decorator from @angular/core. In your example we want to inject a list of posts. To achieve this, add following line inside the class. (we will change the any type later, for now just ignore it).

@Input() posts: any

There is still a blank page, you are right we need to inject the posts inside the component. Open app.component.html and add the property posts inside the component tag. Don't forget to add the brackets around the property to be bindable. We will talk about binding later.

<app-post-list [posts]="posts"></app-post-list>

Move the posts property from post-list.compontent.ts to app.component.ts.

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';

  posts = [
    { title: 'Great jobs at arconsis IT-Solutions' },
    { title: 'Join our team at arconsis IT-Solutions' },
    { title: 'At arconsis we work with newest technologies' },
  ];
}

The @Output() decorator in Angular 6

We will use the @Output decorator to create a callback function. While the @Input() decorator notifies the children component that something changed, The @Output() decorator notifies the parent component that something happened. There currently is no explanation in angular docs for this decorator. But after this example everything should be clear.

First of all, import Output and EventEmitter from @angular/core. We will add a button which only have one purpose, to notify it's parent component that it has been clicked! The logic should be implemented by the wrapping component, in our example, the app.component.ts. We have to add a property with the @Output() decorator to our post-list.component.ts file. We will call it clicked and initialize it as a EventEmitter() we recently added. Create a onClick() function, which calls the the emit() function as soon as the button is clicked.

  @Output() clicked = new EventEmitter();

  onClick() {
    this.clicked.emit();
  }

In our post-list.component.ts file we have to bind the onClick() function to the buttons click event.

<button (click)="onClick()">Click me</button>

The parent component implements a function deleteLastPost(). It pops the last element from the posts array.

deleteLastPost() {
    this.posts.pop();
  }

Last step is to inject the deleteLastPost() function to the @Output() decorated property clicked via event binding.

<app-post-list [posts]="posts" (clicked)="deleteLastPost()"></app-post-list>

That's it! You have a working component which is able to display a list of posts and update itself as soon as the source of truth updates. This component have only one purpose, to display a list of posts. You can reuse this component and inject the posts you want to display from outside! No need to create a new component or to handle what posts to display inside the component.

Visit the next chapter on how to create a attribute directive or feel free to leave your feedback or suggestions here. You can find me at Twitter or simply send me an email to tomislav.eric@arconsis.com.