Angular 8/9 @Input, @Output and EventEmitter Tutorial by Quick Example

In a real-world Angular application, a number of components may exist with their own specific task to accomplish. This hierarchy of components may have parent-child or relation as siblings.

To communicate from parent to child component we use @Input decorator to pass data from parent to child component and to send back data from child to parent we use @Output decorator. The @Output emits the data using the EventEmitter method to the parent component.

Let’s create a demo on How we can use @Input, @Output and EventEmitter to data communication.

Here we will add two components Create Post and List Posts which will be in App Component.

 

Create Components

Run following NG generate commands in the terminal window to quickly create components in the posts folder:

$ ng generate component posts/post-create
$ ng generate component posts/post-list

PostCreateComponent

The app-post-create is having (postCreated) Output property to fetch created post data using the emit() method.

// post-create.component.ts
import { Component, Output, EventEmitter } from '@angular/core';

export interface Post {
  title:string;
  content:string;
}

@Component({
  selector: 'app-post-create',
  templateUrl: './post-create.component.html',
  styleUrls: ['./post-create.component.css']
})
export class PostCreateComponent {

  post:Post; 

  @Output() postCreated = new EventEmitter<Post>();

  constructor() {
    this.post = {} as Post;
  }

  onAddPost(){
    const post = {
      title: this.post.title,
      content: this.post.content
    }
    this.postCreated.emit(post);
  }

}
<!-- post-create.component.html -->
<h3>Create Post</h3>

<form>
    <div class="form-group">
      <label>Title</label>
      <input type="text" class="form-control" name="title" required [(ngModel)]="post.title">
    </div>
    <div class="form-group">
      <label>Content</label>
      <textarea name="content" class="form-control" cols="10" rows="2" required [(ngModel)]="post.content"></textarea>
    </div>
    <button type="submit" class="btn btn-primary" (click)="onAddPost()">Create</button>
  </form>

AppComponent

In the AppComponent we will just get newly created post emitted from PostCreateComponent then push it into a storedPosts object.

Then the storedPosts is passed to PostListComponent via [posts] input property.

<!-- app.component.html -->

<app-post-create (postCreated)="onPostAdded($event)"></app-post-create>

<div class="dropdown-divider"></div>

<app-post-list [posts]="storedPosts"></app-post-list>
// app.component.ts
import { Component } from '@angular/core';

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

  storedPosts = []

  onPostAdded(event) {
    this.storedPosts.push(event);
  }

}

PostListComponent

The app-post-list component directive is having [posts] input property to take in the emitted via AppComponent.

// post-list.component
import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-post-list',
  templateUrl: './post-list.component.html',
  styleUrls: ['./post-list.component.css']
})
export class PostListComponent {

  @Input() posts = [];

  constructor() { }
}
<!-- post-list.component.html -->
<h3>List</h3>

<ng-container *ngIf="posts.length; else elseTemplate">

    <ul class="list-group">
        <li class="list-group-item" *ngFor="let post of posts; let i = index">
            <h5>{{i+1}}) {{post.title}}</h5>
            <p>
                {{post.content}}
            </p>
        </li>
    </ul>

</ng-container>
<ng-template #elseTemplate>

    <div class="alert alert-danger" role="alert">
        No Post Found!
    </div>

</ng-template>

 

Leave a Comment

Your email address will not be published. Required fields are marked *