본문 바로가기
블로그 이미지

방문해 주셔서 감사합니다! 항상 행복하세요!

  
   - 문의사항은 메일 또는 댓글로 언제든 연락주세요.
   - "해줘","답 내놔" 같은 질문은 답변드리지 않습니다.
   - 메일주소 : lts06069@naver.com


앵귤러, 리엑트, 뷰/Angular Tutorial(old)

앵귤러 튜토리얼 (Angular tutorial) -10

야근없는 행복한 삶을 위해 ~
by 마샤와 곰 2019. 6. 5.

* 제가 다시 작성한 최신 튜토리얼 수정본 입니다. 아래 주소를 통해서 진행하시는 것을 권장 드립니다. ^^

lts0606.tistory.com/328

 

앵귤러 튜토리얼(Angular tutorial) - 1

안녕하세요. 앵귤러에 대해서 알아보기위해 이곳을 찾아주신 분 들께 감사의 말씀 드립니다.^^ 천천히, 초심자도 조금 더 쉽게 접근할 수 있도록 내용을 구성하여 보겠습니다. 어��

lts0606.tistory.com

 

이번시간에는 헤더 부분에 대해서 작업을 해 보겠다.

두개정도의 탭을 추가해서 바디부분의 내용이 변하는 기능을 만들어보도록 하겠다.

먼저 head.component.ts파일을 열어보자.

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

@Component({
  selector: 'app-head',
  templateUrl: './head.component.html',
  styleUrls: ['./head.component.css']
})
export class HeadComponent implements OnInit {  //임플리먼트 OnInit??

  constructor() { }

  ngOnInit() { //ngOnInit??
  }

}

 

앞선시간에 넘어갔던 implements와 OnInit에 대해서 살펴보자.

implements는 상속의 의미로 자바를 다루어본 사람은 금방 이해할 수 있는 내용이다. 해당 기능은 내용이 없고 머리만 존재하는 메소드 및 상수로 이루어진 클래스를 의미하며, 해당클래스를 자기자신에 적용(상속)시켜 기능을 구현하는 것이다. (역시..뭔소린지..)

음..implements에 대해서 어렵다면 이렇게 생각하자.

어떠한 대상을 implements 하면 해당 대상이 가지고 있는 기능을 쓸 수 있게 되는 것으로 이해하면 편할 듯 하다.

여기서는 OnInit이라는 인터페이스를 상속받아 해당 인터페이스가 가지고있는 ngOnInit이라는 메소드를 사용 할 수 있게 되었다.

 

앞선 시간에 constructor는 생성자, 컴포넌트가 실행되기전 어떠한 값이나 기능을 먼저 실행시켜주는 녀석이었다고 알아 보았었다. 요 ngOnInit은 앵귤러의 컴포넌트가 생성자가 실행되고 나서 컴포넌트가 "이제 나 초기화, 준비되었다!" 라는 의미로 실행되는 메소드 이다.

조금더 쉽게 보면, 생성자는 컴포넌트가 뭔가 하기전에 하는 일을 말하며, ngOnInit메소드는 컴포넌트가 동작하는 준비과정이 끝난상태에서의 의미를 뜻한다.

 

즉, ngOnInit은 컴포넌트의 동작준비, *.html파일의 준비, *.css파일의 준비 과정이 끝난 상태를 의미한다.

아아...역시나 어렵다. 이렇게 생각하자.

생성자는 1번째로 실행되고, ngOnInit은 생성자 다음으로 실행되는 함수로 일단 이해하자.

그런데 왜 head.component.ts와 body.component.ts에만 있는 것 일까? app.component.ts에는 없는데 말이다. OnInit을 상속받지 않아도(지워도) 동작 하는데 말이다.

해당내용은 일단 넘어가도록하자. 여기서는 생성자 다음에 바로 실행되는 메소드의 개념으로 알고 넘어가자.

 

헤더에 2개영역을 나누어 보자. 첫번째 영역은 사용자 목록을 보여주는 기능으로, 두번째 영역은 게시판 목록을 보여주는 기능으로 하여 보자.

header.component.html 파일을 수정하자.

<div class='col-md-6'>
  <input type='button' value='User List' class='btn btn-primary'/> <!-- 사용자 목록 보기 -->
</div>

<div class='col-md-6'>
  <input type='button' value='DashBoard' class='btn btn-success'/> <!-- 게시판 보기 -->
</div>

 

이렇게 하고나니깐 에..모양이 이상하다..ㅠ

허접해 보인다..

 

해당 헤더파일 위쪽 부모의 높이값을 주지 않아서 생긴 현상이다.

부모는 누굴까? 바로 app.component.html파일이다. 해당 파일에서 높이갚을 주자.

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/css/bootstrap.min.css">
<div class="container">

    <div class='panel panel-success'>
      <div class='panel-heading' style='height: 55px'>  <!-- 여기에 높이를 주자!!!! -->
          <app-head></app-head>  <!-- 헤더 컴포넌트 -->
      </div>
      <div class='panel-body'>
          <app-body></app-body>  <!-- 바디 컴포넌트 -->
      </div>
    </div>

</div>

 

일단뭐..기능은 없지만 헤더부분에 버튼 2개가 생겼다. 버튼에 클릭 이벤트를 부여해서 바디 컴포넌트의 내용이 변경 되도록 하여보자.

head.component.ts파일을 수정하자.

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

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

  constructor() { }

  ngOnInit() {

  }

  dataType(type : any) : void{  //타입을 받는 메소드
    console.log(type);
  }
}

 

이어서 head.component.html파일을 수정하자.

<div class='col-md-6'>
  <input type='button' value='User List' class='btn btn-primary' (click)='dataType("A");'/>
</div>

<div class='col-md-6'>
  <input type='button' value='DashBoard' class='btn btn-success' (click)='dataType("B");'/>
</div>

자, 콘솔에 A값과 B값이 나오는 것이면 성공한 것이다!

음..그런데 해당 값을 바디 컴포넌트가 받아서 뭔가 행동을 해야 될 것 같은데..

여기서부터 긴장해야 된다.

 

작업을 하기전 개념을 다시한번 정리해야 된다.

지금 컴포넌트는 총 3개가 동작하고 있다.

1개는 app.component.ts이고 해당 컴포넌트에 포함되어서 동작하는 컴포넌트 2개는 head.component, body.component 컴포넌트이다.

즉, 해더 컴포넌트에서 이벤트(데이터가 바뀌는 행위)가 발생하면 해당 이벤트를 메인컴포넌트(app.component)가 받아서 바디 컴포넌트한테 전달 해 주어야 한다.

 

전달 순서 : 머리 -> 메인 -> 바디

아니..왜이렇게 복잡하고 분리가 되어 있단 말인가..그냥 한곳에서 다 하면 되는데 말이다.

이렇게 분리된 이유는, 사용자의 요구에 따라 화면이 몇개, 몇십개 몇백개로 만들어지게 되면 파일 1곳에서 관리 할 경우 여차하면 코드 분석을 하지도 못하는 경우가 발생되기 때문이다.

 

아무튼, 이벤트를 전달하려면 우리의 앵귤러의 몇가지 기능에 도움을 받아야 한다.

자, 이벤트를 일으키는 dataType 메소드에 기능을 추가하여 보자.

import { Component, OnInit } from '@angular/core';
import { EventEmitter, Output } from '@angular/core';  //임포트


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

  @Output() sendToEvent = new EventEmitter<any>();  //요건 뭡니까??

  constructor() { }

  ngOnInit() {

  }

  dataType(type : any) : void{  //타입
    console.log(type);
    this.sendToEvent.emit(type);  //에밋?
  }
}

 

처음보는 데코레이터가 등장 하였다.

Output 데코레이터는 해당 컴포넌트에서 발생된 이벤트(데이터)를 외부 다른 컴포넌트한테 전달할 때 사용된다.

sendToEvent는 변수명이므로 원하는데로 고쳐쓰면 되는데.. <> 표시가 또 나왔다.

해당 표시는 제네릭으로 그곳에 정의한 데이터 형식만 받을 수 있게한다는 뜻이다.

지금은 any로 되어있으므로 어떠한 데이터를 받을수 있지만 해당 any에 number를 쓰면 number만 전달 할 수 있고, string을 쓰면 string만 전달 할 수 있다.

자, 이렇게 전달할 기능까지 만들었으니 헤더에서 발생한 이벤트를 메인 컴포넌트가 받도록 수정하여 보자.

app.component.ts파일을 수정하여 보자.

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

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

  showType : any;  //body 컴포넌트한테 전달해줄 데이터

  getEventFromHead (event){  //head 컴포넌트로 부터 데이터를 받기위한 메소드
    console.log(event);
    this.showType = event;  //body컴포넌트한테 줄 데이터를 변경하는 부분
  }
}

 

메인 컴포넌트가 뭔가 이제 중앙집권적인(?) 모습을 보이며 하는일이 생겼다. 메인컴포넌트에서 위 내용처럼 데이터를 받는 메소드를 추가하였으니 이제 전달하러 가 보자.

app.component.html 파일을 수정하여 보자.

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/css/bootstrap.min.css">
<div class="container">

    <div class='panel panel-success'>
      <div class='panel-heading' style='height: 55px'>  <!-- 여기에 높이를 주자!! -->
          <app-head (sendToEvent)='getEventFromHead($event)'></app-head>  <!-- 헤더 컴포넌트 -->
      </div>
      <div class='panel-body'>
          <app-body [getShowType]='showType' ></app-body>  <!-- 바디 컴포넌트 -->
      </div>
    </div>

</div>

 

에...app-head 부분에 (sendToEvent) 라는게 생겼다. 자세히 살펴보면, sendToEvent는 헤더 컴포넌트에서 선언한 Output 데코레이터 변수의 명칭과 같으며, = 'getEventFromHead($event)' 부분에서의 getEventFromHead 는 메인 컴포넌트의 메소드 명칭과 똑같다.

이렇게만 보더라도 컴포넌트와 컴포넌트를 연결하는 데 html 파일이 필요함을 알 수 있으며, 이벤트를 전달하는 녀석은 소괄호에 이름을 명시하고, 받는 녀석은 ='받는메소드($event)' 로 표현하는 것을 알 수 있다.

 

바디 컴포넌트에는 대괄호[] 표시에 showType이 선언되어 있다. 컴포넌트 파일에 데이터를 전달하는 방법 중 1가지로써 대괄호에 변수명을 써주고 ='전달할 값' 표시에 전달할 값을 써 주면 된다.

다시말해 [전달할 변수명] = '전달할 값' 의 개념이다.

 

메인 컴포넌트에서 전달까지 했으니 바디컴포넌트에서 받아보도록 하자.

바디 컴포넌트를 수정한다.

import { Component, OnInit,  } from '@angular/core';
import { Input } from '@angular/core';  //임포트
@Component({
  selector: 'app-body',
  templateUrl: './body.component.html',
  styleUrls: ['./body.component.css']
})
export class BodyComponent implements OnInit {

  @Input() private getShowType : any;  //아까 @Output의 반대로 보인다??

  constructor() { }

  ngOnInit() {

  }


}

 

컴포넌트에서 이벤트를 전달하는 것은 Output 데코레이터를 사용했었다. 받는 것은 직관적인 의미인 Input 데코레이터 이다. 해당 데코레이터를 쓰면 데이터가 이제 받아질 준비가 된 것이다.

자세히 살펴보면 이름이 getShowType으로 되어있는데, 메인 컴포넌트에서 전달한 변수명과 같음을 알 수 있다.

그러면 값이 실제로 바뀌는지 body.component.html 파일을 수정하여 보자.

<p>
  body works!  {{getShowType}}
</p>

 

자! 이제 저장을 하고 헤더의 버튼을 클릭하여 보자!

아무것도 클릭 안한 모습
첫번째 버튼 클릭!
두번째 버튼 클릭!

오....바디 컴포넌트한테 데이터가 잘 전달이 된다.

그러면 이제 해당 값을 토대로 뭔가 바디에 원하는 데이터를 변경하면 되는 일만 남았다.

 

여기까지 해서 게시판의 기본기능에 대해 알아보았다.

정리하여보자.

1. 컴포넌트간에 데이터를 주고받으려면 @Input @Output 데코레이터가 필요하다.

  1) 보내는 방법(헤더컴포넌트) : @Output() 보내는변수명 = new EventEmitter<any>();

  2) 받는 방법(바디컴포넌트) : @Input 받는변수명;

2. 주고받는 데이터는 메인 컴포넌트.html파일에서 수정을 해야 한다.

  1) 받는 방법 : (보내는변수) ='받는 메소드'

  2) 데이터를 받는 받법 : [받는변수명]='보내는 변수명'

 

다음시간에는 이제 바디컴포넌트에서 받은 이벤트를 토대로 게시판 내용을 보여주는 방법에 대해서 알아보도록 하자.

오늘까지의 내용을 압축한 파일을 첨부한다.

app.zip
0.01MB

 

* 좋은 말씀주신 "지나가는사람" 님 감사드립니다. ^^

 

반응형
* 위 에니메이션은 Html의 캔버스(canvas)기반으로 동작하는 기능 입니다. Html 캔버스 튜토리얼 도 한번 살펴보세요~ :)
* 직접 만든 Html 캔버스 애니메이션 도 한번 살펴보세요~ :)

댓글