본문 바로가기
Angular.js

[Angular] 부모와 자식 사이 데이터 전달/수신 (feat. 데이터 바인딩)

by 찬찬2 2023. 1. 4.

자식(buttons.component) → 부모(section.component)

위 그림은 자식이 부모에게 데이터를 전달하는 구조이다. 여기서 각 태그 혹은 컴포넌트에 들어간 이벤트 핸들러의 형태를 살펴보자. 

HTML 요소에 이벤트 핸들러를 추가 시 소괄호"( )"에 click, drag, keypress, keyup 등 이벤트 객체를 선택할 수 있도록 셀렉트박스가 나온다. 하지만 컴포넌트 템플릿의 경우는 다르다. 소괄호를 쓰면 태그처럼 이벤트 객체를 선택할 수 있는 셀렉트 박스가 나오지 않는다.

즉, 컴포넌트에는 일반적인 이벤트 객체를 넣을 수 업는 듯 하다. 그렇다면 위 그림에 있는 "clickEvent"는 어떻게 사용되어 지는가? ButtonComponent 컴포넌트 안을 살펴보면 "@Output"라는 데코레이터가 있다. 그리고 @Output에 "clickEvent" 변수를 추가했고, new EventEmitter라는 생성자 함수를 "clickEvent" 변수에 할당했다. 그리고 button을 눌렀을때 실행될 함수인 start 함수에 EventEmitter 객체가 가지고 있는 메서드 중 하나인 "emit" 함수를 호출하도록 만들었다.

이 구조가 바로 자식이 부모에게 데이터를 전달하는 방법 중 기본적인 방법이다. 아직 기초단계를 공부중이기 때문에 앵귤러에서 어떻게 이벤트 핸들러를 다루고 데이터를 바인딩하는지 더 볼것이다.

 


 

"@Input(), @Output() 데코레이터를 활용하면 자식 컴포넌트가 부모 컴포넌트와 통신할 수 있습니다. 이 때 @Input()은 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달할 때 사용합니다. 그리고 @Output()은 반대로 자식 컴포넌트에서 부모 컴포넌트로 데이터를 전달할 때 사용합니다."

 

https://angular.kr/guide/inputs-outputs

 

 

 

아들(데이터 전달) → 부모(아들과 딸을 연결) → 딸(데이터 수신)

 

타이머 앱을 앵귤러로 만들어 보았다. 리모컨과 텔레비전이라는 자식 컴포넌트가 있고 위성이라는 부모 컴포넌트가있다. 리모컨을 조작했을때 텔레비전 화면에 무엇을 표시하는 것이 목적이다.

위 그림을 보았을 때 MVC 패턴과 비슷하게 보인다. 리모컨은 Controller, 위성은 Model, 텔레비전은 View로 볼 수 있을 것 같다.

앵귤러에서 데이터를 바인딩할때 맵핑관계가 매우 중요하다. 위 그림과 같이 맵핑관계를 파악해 보았을때 크게 복잡해 보이지는 않다. 아직 기초단계라 더 공부해보면 알겠지...

 

앵귤러의 조금 특이한 점은, 위에 경우, 자식 → 부모 → 자식으로 데이터를 흘려보냈을때 리모컨 컴포넌트와 위성 컴포넌트에 똑같이 이벤트를 발생시켜야하는 점이다.(맵핑관계 설정) 부모 컴포넌트의 경우 그 형태가 조금 다른데 저것을 이벤트 핸들러라고 봐야하는지 잘 모르겠다. 조금 더 공부하고 내용을 수정하도록 하자.

 

키워드

#Output(), #Input, #EventEmitter(), #emit(), #ngOnChanges()

 

Child(@Output) → Parent

 

 

Parent → Child(@Input)

 

 

Child-A(@Output) → Parent → Child-B(@Input)

 

 


 

component-interaction#parent-and-children-communicate-via-a-service

(공식문서)

 

목자

1. Pass data from parent to child with input binding

2. Intercept input property changes with a setter

3. Intercept input property changes with ngOnChanges()

4. Parent interacts with child using local variable

5. Parent and children communicate using a service

 

위에서 기본적인 @Output, @Input의 사용벅을 적었다. 

공식문서를 보던 중 부모-자식 간 data-binding에 대한 다른 예시가 있어서 한번 보았다.

 

Pass data from parent to child with input binding (parent → child)

@Input('fromParent') variableName : ''

 

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

import { HEROES } from './hero';

@Component({
  selector: 'app-hero-parent',
  template: `
    <h2>{{master}} controls {{heroes.length}} heroes</h2>

    <app-hero-child
      *ngFor="let hero of heroes"
      [hero]="hero"
      [master]="master">
    </app-hero-child>
  `
})
export class HeroParentComponent {
  heroes = HEROES;
  master = 'Master';
}

 

부모가 자식에게 데이터를 전달하는 방법이다.

 

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

import { Hero } from './hero';

@Component({
  selector: 'app-hero-child',
  template: `
    <h3>{{hero.name}} says:</h3>
    <p>I, {{hero.name}}, am at your service, {{masterName}}.</p>
  `
})
export class HeroChildComponent {
  @Input() hero!: Hero;
  @Input('master') masterName = '';
}

 

 

자식 컴포넌트에 있는 @Input 데코레이터를 보면 두 번째 @Input의 인자에 부모로 부터 전달받은 데이터가 있고, 그것을 다른 변수에 담는 모습이다.

 

Intercept input property changes with a setter

- Intercept input property changes with a setter

- 흠.. class 문법 중 get, set을 사용해서 데이터를 가로챈다는데... 굳이 가로채야 하는 상황은 어떤 상황일지 경험이 없어 잘 이해는 못하겠다.

 

/* name-parent.component */
import { Component } from '@angular/core';

@Component({
  selector: 'app-name-parent',
  template: `
    <h2>Master controls {{names.length}} names</h2>

    <app-name-child *ngFor="let name of names" [name]="name"></app-name-child>
  `
})
export class NameParentComponent {
  // Displays 'Dr. IQ', '<no name set>', 'Bombasto'
  names = ['Dr. IQ', '   ', '  Bombasto  '];
}

/* name-child.component */
import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-name-child',
  template: '<h3>"{{name}}"</h3>'
})
export class NameChildComponent {
  @Input()
  get name(): string { return this._name; }
  set name(name: string) {
    this._name = (name && name.trim()) || '<no name set>';
  }
  private _name = '';
}

 

The setter of the name input property in the child NameChildComponent trims the whitespace from a name and replaces an empty value with default text.

 

댓글