자식(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()은 반대로 자식 컴포넌트에서 부모 컴포넌트로 데이터를 전달할 때 사용합니다."
아들(데이터 전달) → 부모(아들과 딸을 연결) → 딸(데이터 수신)
타이머 앱을 앵귤러로 만들어 보았다. 리모컨과 텔레비전이라는 자식 컴포넌트가 있고 위성이라는 부모 컴포넌트가있다. 리모컨을 조작했을때 텔레비전 화면에 무엇을 표시하는 것이 목적이다.
위 그림을 보았을 때 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.
'Angular.js' 카테고리의 다른 글
[Angular] 디렉티브 - Directive(지시/명령) (0) | 2023.01.05 |
---|---|
[Angular] 디렉티브와 템플릿 문법, 그리고 바인딩 문법 (0) | 2023.01.05 |
[Angular] 자바스크립트 데코레이터 (JavaScript Decorator) (0) | 2023.01.04 |
[Angular] Angular 개요와 프로젝트 구조 (0) | 2023.01.03 |
[Angular] 터미널에서 ng 명령어 실행 실패 - 원인: 보안 오류(PSSecurityException) (0) | 2023.01.03 |
댓글