Getting started with Angular 2 - Part 3 (Understanding directives' inputs and outputs)

We developed together a to-do list application in Getting Started with Angular 2 - Part 2 (Using Built-in Directives) and learnt about some enhanced semantics of Angular 2 along with it built-in directives. In this post, we are going to restructure our to-do list application by taking advantage of the directives' inputs and outputs.

Finding out inputs and outputs

As you can remember, we have only three components (formed with multiple directives) used in our todo list application, which are InputBox and TodoList.

Main app

This is where all individuals components of our app combined into one place, which is responsible for maintaining the list of to-do items.

InputBox

Let's take a look at our InputBox component where we can type our new todo items in our app. It has two inputs and one output as following list.

InputBox[Input]
     1. A placeholder for the textbox
     2. A label for the submit button

InputBox[Output]
    1. Should emit the content of the input once the submit button is clicked.

TodoList

Now, the TodoList component renders every individual to-do items whether they already existed in the lists or newly added from the InputBox. Inputs and outputs of TodoList could be considered as below.

TodoList[Input]
     1. The list of to-do items.

TodoList[Output]
     1. Should emit the change once the completion status of any of the to-do items changes.

Inputs could be considered as properties or arguments that parameterise the directive's behaviour and/or view.

Outputs refers to events that the directives fires when something special happens.

Defining the InputBox's inputs and outputs

After finding out each directive's inputs and outputs, we will now define our own Angular 2 components by using them starting from InputBox in this tutorial.

Before that, you need to have a complete todo list app from Getting Started with Angular 2 - Part 2 (Using Built-in Directives) or simple clone one from github.

Firstly in app.component.ts, we need to import a couple of modules from angular2/core package like following.

// angular2-todo-list-app/app/app.component.ts

import {  
  Component, 
  Input,
  Output,
  EventEmitter,
  ViewEncapsulation 
} from 'angular2/core';

We imported here are three decorators and 2 classes. @Component is required to create a new component class and add metadata for our app components. @Input and @Output decorators are required to declare the directive's inputs and outputs. EventEmitter class will be used to emit outputs together with @Output decorator.

After importing modules what we need, let's create a ImputBox component of our own by refactoring directive's inputs and outputs in app.component.ts file.

@Component({
  selector: 'input-box',
  template: `
    <input #todoInput [placeholder]="inputPlaceholder" >
    <button (click)="emitText(todoInput.value);
                      todoInput.value = '';">
                      {{buttonLabel}}
    </button>
  `
})

Remember what we found out inputs and outputs of InputBox component previously and we just created a InputBox component template that contains all of these inputs and outputs needed:

InputBox[Input]
     1. A placeholder for the textbox => inputPlaceholder
     2. A label for the submit button => buttonLabel

InputBox[Output]
    1. Should emit the content of the input once the submit button is clicked => Binded emitText method to emit todoInput value once it is triggered.

Now, we will define those inputs and outputs in the component's controller as following:

export class InputBox {  
  @Input() inputPlaceholder: string;
  @Input() buttonLabel: string;
  @Output() inputText = new EventEmitter<string>();
  emitText(text: string) {
    this.inputText.emit(text);
  }
}

In the controller, first we declared all inputs components and inputText output by creating a new instance of the type EventEmitter<string>. Then, we defined emitText method that should emit the value of the text input.

Defining the TodoList's inputs and outputs

We can also define the inputs and outputs of TodoList component as same as we did in InputBox like following:

@Component({
  selector: 'todo-list',
  template: `
    <ul>
        <li *ngFor="#todo of todos; var index = index" [class.completed]="todo.completed">
          <input type="checkbox" [checked]="todo.completed" (change)="toggleCompletion(index)">
            {{todo.label}}
        </li>
    </ul>
  `,
  styles: [
    `ul li {
      list-style: none;
    }
    .completed {
      text-decoration: line-through;
    }`
  ],
})

export class TodoList {  
  @Input() todos:  Todo[];
  @Output() toggle = new EventEmitter<Todo>();
  toggleCompletion(idx: number) {
    let todo = this.todos[idx];
    this.toggle.emit(todo);
  }
}

The template definition for todo-list is exactly as same as we did in previous tutorial and the controller class for TodoList is also similar as we defined in InputBox component.

Combining altogether with Main App component

Now, it is time to implement our complete app by combining the components that we defined previously altogether in the todo-app main component. The completed main app component would be look like following content.

@Component({
  selector: 'todo-app',
  directives: [TodoList, InputBox],
  templateUrl: 'app/app.html'
})

export class TodoApp {  
  todos: Todo[] = [{
      label: 'Learn Angular 2',
      completed: false
  }, {
      label: 'Go to market',
      completed: false
  }];
  name: string = 'Nay';
  addTodo(label: string) {
    this.todos.push({
      label,
      completed: false
    })
  }
  toggleCompletion(todo: Todo) {
    todo.completed = !todo.completed;
  }
}

Finally, we just need to replace the existing InputBox and TodoList in app.html with our own ones like following:

<!-- angular2-todo-list-app/app/app.html -->

<h1>Hello {{name}}!</h1>

<p>  
    Add a new todo:
    <input-box inputPlaceholder="New todo..."
      buttonLabel="Add"
      (inputText)="addTodo($event)">
    </input-box>
</p>  
<p>  
  Here's a list of the things I need to do:
</p>  
<todo-list [todos]="todos" (toggle)="toggleCompletion($event)">

</todo-list>  

In this tutorial, we understood how inputs and outputs of directives and defined new components along with their controllers class. I am still learning Angular 2 web development like many others do and these posts are like my self-study notes to myself. I am here to just share what I learnt with you guys.

Thank you for reading this post and your sharing makes my day if you enjoy this post.

Cheers.

Nay Win Myint

A JavaScript full-stack web developer, also interested in Android application development and Graphic design.

United Kingdom