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

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

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


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

앵귤러 튜토리얼(Angular tutorial) - 9 : 컴포넌트, 모듈

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

컴포넌트에 디렉티브를  통하여 앞시간에 우리는 로그인이 성공하면 특정 컴포넌트가 보여지도록 하는 기능을 만들어 보았습니다.
이전시간에 했던 내용이 어렵거나 이해가 되지 않는다면 반드시 다시 확인 해 보아야 합니다!

이번시간에는 새롭게 프로젝트를 한개 더 만들어 보도록 하겠습니다.
아래 명령어를 입력하여줍니다!
디렉토리 위치를 잘 보아야합니다! firstStudy 디렉토리에서 아래 명령어를 실행하는 것이 아닙니다! ^^

 

ng new secondStudy 

routing에서는 N을 입력, 그리고나서 CSS를 선택합니다.

 

프로젝트가 완성되었습니다.
우리는 가장 먼저 생겨난 app컴포넌트를 관리(control) 역할을 하는 컴포넌트로 사용 할 예정입니다.
다시말해, 여러개의 컴포넌트를 만들어서 화면을 꾸밀 예정이지만 app컴포넌트에서는 관리(control)역할만 하도록 바꿀 예정입니다.

앞선 시간에서는 다른 컴포넌트들의 셀렉터를 app컴포넌트에 붙인 뒤에 ngIf 디렉티브를 통해서 조건에 따라 보여주고 가려주었었습니다.
어느정도 app컴포넌트의 역할이 관리(control)역할을 하는 것과 거의 비슷했습니다.

* 예전에 이렇게 사용했었지요! (app.component.html파일 내용입니다.)

<app-hello *ngIf="visible1"></app-hello>
<app-world *ngIf="visible2"></app-world>

 

앞 시간의 내용을 조금 참고하여 컴포넌트를 추가하겠습니다.
로그인 역할을 할 컴포넌트를 추가 합니다.
ng g component login

컴포넌트를 새로 생성합니다. 뭘 보낸다고 하는데 가볍게 NO 해줍니다..^^;

 

app컴포넌트에서 불필요한 title변수를 삭제하고, app컴포넌트의 html 파일의 내용을 전부 제거합니다.
그리고 login컴포넌트의 셀렉터를 붙여 넣어 줍니다. (컴포넌트 내부의 값 입니다. ex -> selector : '값')

app컴포넌트를 아래처럼 깔끔하게 비웁니다.  

* 파일이름 : app.component.ts

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

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

 

app컴포넌트 html파일을 새로 만들어준 login 컴포넌트의 셀렉터만 추가하고 기타 내용은 제거합니다.

* 파일이름 : app.component.html

<app-login></app-login>

 

ng serve 명령어를 입력하여 실행합니다.

그리고 4200번포트로 접속하여봅니다.

쫜~ 로그인 컴포넌트가 동작하였습니다.

 

여기까지는 크게 어렵지 않는 내용입니다.
이전과 다른점은, app컴포넌트와 app컴포넌트html파일에서는 화면구성과 관련된 어떠한 행동도 정의되지 않았다는 점 입니다.
그러면 로그인 기능을 위해 login컴포넌트와 login컴포넌트html파일에 입력창을 달아주도록 하겠습니다.

 

login컴포넌트 파일을 수정합니다.  

* 파일이름 : login.component.ts

import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
  visible1 : boolean = false;
  id :string;
  pwd : string;

  constructor() { }

  ngOnInit(): void {
  }

  tryToLogin() : void{
    if(this.id =='admin' && this.pwd == '1234'){
      this.visible1 = true;
    }   
    console.log(this.id, this.pwd);    
  }
}

 

id와 pwd는 이전 시간처럼 input type text에서 사용될 변수 입니다.

tryToLogin 함수는 해당 값이 지정한 값과 일치하는지 여부를 판단 하여주는 함수 입니다.

이어서 login컴포넌트 html 파일을 수정합니다.  

* 파일이름 : login.component.html

<div>Wellocome</div>
<input type="text" placeholder="id" [(ngModel)]="id"/>
<input type="text" placeholder="password"  [(ngModel)]="pwd"/>
<button (click)='tryToLogin()'>Login</button>

 

이렇게 놓고 보니 뭔가 허전합니다..에러도 발생하고 있습니다.
맞습니다. ngModel 디렉티브 [(ngModel)]는 외부 라이브러리 개념의 디렉티브 입니다. 

기본 디렉티브가 아니므로 설정을 통해 사용할 수 있게 해 주어야 합니다.
해당 설정은 어디서 하는 것 일 까요?   * say : 모듈~!!!
모듈에 FormsModule를 import 해 준 다음에 NgModule 데코레이터의 imports에 추가하여 줍니다.

모듈에 FormsModule를 등록하여 줍니다.  

* 파일이름 : app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { LoginComponent } from './login/login.component';

import {FormsModule} from '@angular/forms';  //폼즈모듈을 가져옵니다!

@NgModule({
  declarations: [
    AppComponent,
    LoginComponent
  ],
  imports: [
    BrowserModule, FormsModule  //imports를 통해서 다른 컴포넌트들이 해당 모듈의 기능을 사용할 수 있게 해 줍니다.  
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

 

여기까지는 저번시간과 거의 비슷한 부분입니다.
로그인이 성공하면 보여줄 대쉬보드 컴포넌트를 만들어 보겠습니다.

ng g component dashboard

새로운 컴포넌트를 추가합니다.

 

마찬가지로 dashboard 컴포넌트의의 셀렉터를 app컴포넌트 html 파일에 추가하여 줍니다.

dashboard 컴포넌트 html 파일의 내용은 그냥 그대로 사용하여 보겠습니다.  

* 파일이름 : app.component.html

<app-login></app-login>
<app-dashboard></app-dashboard>

 

밑에 dashboard 컴포넌트가 붙여서 나옵니다!

 

자, 그러면 로그인이 성공했다고 가정해 봅니다.

로그인이 되면 login컴포넌트는 사라져야하고, dashboard컴포넌트는 안보이다가 나타나야 할 것 입니다.
조금 어려울수 있습니다! 
천천히 따라 하여 보도록 합니다!

app컴포넌트에 아래 2개의 변수를 추가하여 줍니다.

* 파일이름 : app.component.ts

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

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

 

loginBool이라는 변수는 login 컴포넌트를 보이기/가리기에 사용 될 변수입니다.

boardBool이라는 변수는 dashboard 컴포넌트를 보이기/가리기에 사용 될 변수입니다.

위 2개의 변수를 app컴포넌트html파일에 적용시켜 줍니다.

컴포넌트를 보이게 할 지 가리게 할 지는 ngIf 디렉티브를 사용 하였었습니다.

* 파일이름 : app.component.html

<app-login *ngIf="loginBool"></app-login>
<app-dashboard *ngIf="boardBool"></app-dashboard>

이제 로그인 성공전 까지 dashboard컴포넌트는 보이지 않습니다.

login컴포넌트의 내용에 @Input이라는 데코레이터를 추가하여줍니다.

* 파일이름 : login.component.ts

import { Component, OnInit, Input } from '@angular/core'; //임포트를 해 주어야 합니다!

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
  @Input() visible1 : boolean;  //새로운 디렉티브가 나타났습니다!
  id :string;
  pwd : string;

  constructor() { 
  }

  ngOnInit(): void {
  }

  tryToLogin() : void{
    if(this.id =='admin' && this.pwd == '1234'){
      this.visible1 = true;
    }
    console.log(this.id, this.pwd);    
  }

}

 

그리고 app컴포넌트 html파일을 아래처럼 수정합니다.

* 파일이름 : app.component.html

<app-login *ngIf="loginBool" [visible1]='loginBool'></app-login>
<app-dashboard *ngIf="boardBool"></app-dashboard>

 

처음보는 기호인 @Input이라는 데코레이터는 "받는" 역할을 의미합니다.
app컴포넌트에 우리는 loginBool, boardBool 2개를 만들어 주었습니다.
그중 loginBool 값을 login컴포넌트에 전달하려고 대괄호에 login컴포넌트의 visible1이라는 변수를 써 주고 app컴포넌트의 변수인 loginBool을 대입하였습니다.

 

다시말해 대괄호 [login컴포넌트의변수] = '보낼값' 으로 표기를 하여 app컴포넌트에 전달을 해 준 것 입니다.

여기까지가 상위 컴포넌트에서 하위 컴포넌트로 보내는 방법입니다.
상위 컴포넌트는, 셀렉터(selector) 태그를 가지고 있는 컴포넌트를 의미합니다.
하위 컴포넌트는 본인의 셀렉터(selector)가 사용되는 컴포넌트를 의미합니다.

 

잠깐 정리를 하면 현재 컴포넌트 구조는 아래처럼 되어 있습니다.

상위 컴포넌트는 당연히 먼저 나온 컴포넌트, 하위 컴포넌트는 상위 다음에 나온 컴포넌트입니다!

현재 컴포넌트의 모습과 관계입니다.

 

그러면 로그인이 성공하게 되면 성공유무 값을 가져와야 되는방법을 살펴보겠습니다.

 

로그인의 성공 유무는 login 컴포넌트의 tryToLogin 함수에서 판별이 되어집니다.

login 컴포넌트만 로그인이 성공 하였는지 실패하였는지 알 수 있습니다.

login컴포넌트에서의 성공유무를 app컴포넌트가 알 수 있게 전달해 주도록 해 보겠습니다.

왜냐하면 로그인이 성공하면 login컴포넌트를 가리고 dashboard 컴포넌트를 보여주게 해야 되는데..

해당 셀렉터들이 전부 app컴포넌트에 있기 때문 입니다.


login컴포넌트를 수정합니다.

* 파일이름 : login.component.ts

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

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
  @Input() visible1 : boolean; //받는 역할
  @Output() sendMyEvent : EventEmitter<any> = new EventEmitter();  //보내는 역할
  id :string;
  pwd : string;

  constructor() { 
  }
  ngOnInit(): void {
  }

  tryToLogin() : void{
    if(this.id =='admin' && this.pwd == '1234'){
      this.visible1 = true;
    } else {
      this.visible1 = false;
    }
    console.log(this.id, this.pwd, this.visible1);    
    this.sendMyEvent.emit(this.visible1);  //보낸다!
  }
}

 

@Output이라는 데코레이터는 컴포넌트 외부로 전달할 때 사용하는 기능 입니다.
컴포넌트의 이벤트를 외부에 EventEmitter의 클래스의 emit이라는 기능을 통해서 원하는 데이터를 보낼 수 있습니다.
일종의 방법이라 생각하면 좋을 것 같습니다.
그러면 해당 이벤트를 받는 부분을 구현하여 보겠습니다.

app컴포넌트 html파일을 수정합니다.

* 파일이름 : app.component.html

<app-login *ngIf="loginBool" [visible1]='loginBool' (sendMyEvent)="getEventThanks($event)"></app-login>
<app-dashboard *ngIf="boardBool"></app-dashboard>

 

app컴포넌트 파일을 수정합니다.

* 파일이름 : app.component.ts

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

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

  getEventThanks(event){
    console.log(event)
  }
}


와..내용이 어렵습니다.
sendMyEvent는 login컴포넌트에서 만든 @Output 데코레이터가 붙여진 변수 명칭 입니다.
그리고 getEventThanks 함수는 app컴포넌트에서 만든 함수 입니다.
위 내용을 실행하여 틀린 정보, 올바른 정보로 클릭하여보면 app컴포넌트에게 데이터가 전달되는 모습을 볼 수 있습니다.

짜잔! 값이 전달됩니다!

 

거의 다 왔습니다.
app컴포넌트에서 getEventThanks함수는 login컴포넌트가 로그인 성공유뮤값을 boolean 형태로 전달해 주었습니다.
그러므로, 값이 true이면 login컴포넌트는 가리고 dashboard컴포넌트를 보여주어야 할 것 입니다.

app컴포넌트의 getEventThanks 함수를 아래처럼 수정하여줍니다.

* 파일이름 : app.component.ts

  getEventThanks(event){
    console.log(event)
    if(event == true){
      this.loginBool = false;
      this.boardBool = true;
    }
  }

 

로그인 여부에 따라 login컴포넌트와 dashboard컴포넌트가 보이기/가리기 기능이 완벽하게 동작하는 앱을 만들게 되었습니다!
이름이 익숙하지 않아서 햇갈릴 수 있습니다. 
천천히 내용을 다시 살펴보도록 합니다.

만들어진 내용을 살펴보면,
app컴포넌트는 컴포넌트간의 데이터를 전달해주고 받으면서 보이기 가리기 기능을 관리(control)하는 역할을 하게 되었습니다.
화면구성에 필요한 div, input type, table테그 등 그러한 내용은 존재하지 않고 오직 관리(control)역할만 하도록 기능이 분리 되었습니다.

우리는, Input과 Output이라는 데코레이터를 사용하였습니다.
Input과 Output이라는 데코레이터는 컴포넌트간의 데이터 주고받기를 위해 존재 합니다.
Input데코레이터는 app컴포넌트에서 login컴포넌트로 데이터를 전달 해 줄 때 사용되었습니다.
Output데코레이터는 이와 반대로 login컴포넌트에서 app컴포넌트로 데이터를 전달 해 줄 때 사용되었습니다.
상위 컴포넌트에서 하위 컴포넌트로 갈 때는 Input, 하위 컴포넌트에서 상위 컴포넌트로 갈 때는 Output입니다!

정리하여 보겠습니다.
1. 가장 먼저 실행되는 모듈, 컴포넌트는 관리(control)의 목적으로 주로 사용됩니다.
2. 관리(control)의 목적으로 사용되는 컴포넌트에는 통상적으로 다른 컴포넌트들의 셀렉터(selector) 테그를 넣어줍니다.
3. 수많은 컴포넌트들은 셀렉터(selector)를 통해서 가져오게되면 전부 보이게 되므로 ngIf 디렉티브를 통해서 보여질화면, 가려질화면을 정해 주도록 합니다.
4. Input데코레이터, Output 데코레이터를 통해서 컴포넌트간의 데이터를 주고받로독 합니다.
5. 관리(control)의 목적으로 사용되는 컴포넌트는 이러한 주고받는 데이터를 통해서 화면 구성의 역할을 실시 합니다.

이번시간에는 컴포넌트의 역할을 통해서 화면을 구성하는 기초 방법에 대해서 살펴보았습니다.
다음시간에는 이번시간의 내용을 조금 더 자세히 살펴보도록 하겠습니다.

 

src.zip
0.01MB

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

댓글