/ ANGULAR

Angular 강좌(10) - 데이터공유(@Output)

Angular 강좌는 여러 절로 구성되어 있습니다.


@Output Decorator

이번 포스트는 자식 Component에서 부모 Component로 데이터를 전달하기 위한 @Output decorator에 대해서 알아보겠습니다.

자식 Component에서 부모 Component로 데이터를 전달하기 위해서는 EventEmitter를 이용한 이벤트 처리를 하셔야 합니다. 즉, 자식 Component에서 발생한 event를 부모 Component가 event bidning을 이용해 데이터를 받는 방식입니다.

코드레벨에서 알아보죠. 이전에 @Input decorator를 설명하면서 사용했던 예제를 좀 수정해서 사용하겠습니다.

아래는 search-box.component.ts 내용입니다.

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

@Component({
  selector: 'app-search-box',
  templateUrl: './search-box.component.html',
  styleUrls: ['./search-box.component.css']
})
export class SearchBoxComponent implements OnInit {

  _bookCategory: string;
  //@Input() bookCategory:string;
  //@Input('bookCategory') mySelected:string;

  @Input()
  set bookCategory(value: string) {
    if( value != null ) {
      // 추가적인 작업이 들어올 수 있습니다.
      this._bookCategory = 'category: ' +value;
    } else {
      this._bookCategory = value;
    }

  }

  @Output() searchEvent = new EventEmitter();

  keyword = null;

  constructor() { }

  ngOnInit() {
  }

  setKeyword(keyword: string): void {
    this.keyword = keyword;
    this.searchEvent.emit({
      keyword : `${this.keyword}`,
      category: `${this._bookCategory.replace('category: ','')}`
    });
  }

  inputChange(): void {

  }
}

부모 Component에게 이벤트를 전달하기 위해 다음의 코드로 EventEmitter 객체를 생성하고 @Output decorator를 이용했습니다. 부모 Component는 searchEvent 이름으로 event binding 해야합니다.

@Output() searchEvent = new EventEmitter();

자식 Component에서 Search! 버튼을 눌렀을 때 setKeyword() method가 호출되는데 이 안에서 searchEvent에 대한 이벤트를 발생시킵니다. 그러면서 부모 Component에게 전달할 데이터를 인자로 넣어줍니다.

this.searchEvent.emit({
    keyword : `${this.keyword}`,
    category: `${this._bookCategory.replace('category: ','')}`
});

이제 부모 Component에서 어떻게 event binding을 이용해서 데이터를 받는지만 살펴보면 됩니다.

아래는 book-search-main.component.html 입니다.


<div class="bookSearch-outer">
  <div class="d-flex align-items-center p-3 my-3 text-white-50 bg-purple rounded box-shadow">
    <img class="mr-3" src="assets/images/search-icon.png" alt="" width="48" height="48">
    <div class="lh-100">
      <h5 class="mb-0 text-white lh-100">Search Result : {{searchTitle}}</h5>
    </div>
  </div>

  <div class="example-container">
    <mat-form-field>
      <mat-select placeholder="도서종류"
                  #bookCategorySelect
                  [(ngModel)]="selectedValue"
                  (ngModelChange)="changeValue(bookCategorySelect.value)">
        <mat-option *ngFor="let category of bookCaterory"
                    [value]="category.value">
          {{ category.viewValue }}
        </mat-option>
      </mat-select>
    </mat-form-field>
  </div>

  <div>
    <app-search-box [bookCategory]="displayCategoryName"
                    (searchEvent)="changeTitleBar($event)">
    </app-search-box>
  </div>
  <div>
    <app-detail-box></app-detail-box>
  </div>
  <div>
    <app-list-box></app-list-box>
  </div>
</div>

주의해서 보셔야 할 부분은

<app-search-box [bookCategory]="displayCategoryName"
                (searchEvent)="changeTitleBar($event)">
</app-search-box>

입니다. event binding을 이용해서 searchEvent 이벤트가 발생하면 changeTitleBar() method를 호출하고 인자를 받아서 처리하고 있네요. 인자 받는 방식도 유의해서 보셔야 합니다.


<h5 class="mb-0 text-white lh-100">Search Result : {{searchTitle}}</h5>

interpolation을 이용해 searchTitle 속성의 값을 View에 출력하고 있네요. 아마 changeTitleBar() method안에서 내용이 결정될 듯 합니다.

마지막으로 book-search-main.component.ts 파일입니다.

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

@Component({
  selector: 'app-book-search-main',
  templateUrl: './book-search-main.component.html',
  styleUrls: ['./book-search-main.component.css',
  './offcanvas.css']
})
export class BookSearchMainComponent implements OnInit {

  selectedValue = null;
  displayCategoryName = null;
  bookCaterory = [
    {value: 'all', viewValue: '국내외도서'},
    {value: 'country', viewValue: '국내도서'},
    {value: 'foreign', viewValue: '국외도서'}
  ];

  searchTitle = null;

  constructor() { }

  ngOnInit() {
  }

  changeValue(category: string): void {
      for(let element of this.bookCaterory ) {
        if(element.value == category) {
          this.displayCategoryName = element.viewValue;
        }
      }
  }

  changeTitleBar(searchInfo) : void {
    this.searchTitle = `${searchInfo.keyword} ( ${searchInfo.category} )`;
  }
}

기본적인 개념은 이미 설명했으니 코드레벨에서 한번 천천히 살펴보시면 충분히 이해할 수 있을 듯 보입니다.

여기까지 작업한 내용을 실행해 정상적으로 동작하는지 확인하시면 될 듯 합니다.

자식 Component에서 부모 Component로 Event를 이용해서 데이터를 어떻게 전달하는지에 대해서 간단하게 살펴보았습니다.

다음 포스트는 부모 Component에서 자식 요소에 접근할 때 또 다른 방법으로 어떤 방법이 있는지 알아보도록 하겠습니다.

End.


Angular 강좌는 아래의 책과 사이트를 참조했습니다. 조금 더 자세한 사항을 알고 싶으시면 해당 사이트를 방문하세요!!