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

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

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


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

앵귤러 튜토리얼(Angular tutorial) - 12 : 데이터 바인딩, 반응형 모듈

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

저번시간에는 앵귤러의 컴포넌트에서 여러 디렉티브와 속성을 사용하는 방법에 대해서 살펴 보았습니다.
이번시간에도 이이서 컴포넌트를 다양한 방법으로 꾸며보겠습니다.

우리는 FormsModule이라는 모듈을 app모듈에 등록한 뒤에 컴포넌트에서 [(ngModel)] 이라는 디렉티브를 통해서 데이터를 받아왔었습니다.
그 예로는 id와 pwd값을 ngModel로 바인딩하여 데이터를 가져왔었습니다.
이번에 바꾸어 볼 대상이 바로 id와 pwd 값을 다른 방법으로 바인딩 해 보는 것 입니다.
ReactiveFormsModule이라는 모듈을 한번 적용하여 보겠습니다.
app모듈 파일에 ReactiveFormsModule을 사용할 수 있도록 추가하여 줍니다.

* 대상 : 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';
import { DashboardComponent } from './dashboard/dashboard.component'; 
import { ReactiveFormsModule } from '@angular/forms';  //반응형 폼?

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

 

다음으로 기존에 사용중이던 login컴포넌트의 id와 pwd 변수값을 일반 문자에서 FormControl이라는 클래스로 바꾸어 줍니다.

* 대상 : login.component.ts

import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { FormControl } from '@angular/forms';  //추가합니다!!!!!

@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 = new FormControl('');  //폼 컨트롤러 클래스로 바꿉니다.
  pwd = new FormControl(''); //폼 컨트롤러 클래스로 바꿉니다.

  private message;

  styleArray = {'wrong_id':false, 'wrong_pwd':false};

  constructor() { 

  }

  ngOnInit(): void {

  }

  tryToLogin() : void{
    if(this.id.value =='admin' && this.pwd.value == '1234'){
      alert('로그인합니다!');
      this.visible1 = true;
      this.sendMyEvent.emit(this.visible1);  //app컴포넌트에 전달
    } else if(this.id.value != 'admin'){
      this.setMessage = 'wrong id';
      this.styleArray.wrong_id = true;
      this.styleArray.wrong_pwd = false;
    } else if(this.pwd.value != '1234'){
      this.setMessage = 'wrong pwd';
      this.styleArray.wrong_id = false;
      this.styleArray.wrong_pwd = true;
    } 
  }

  set setMessage(arg){  //대입합니다.
    this.message = arg;
  } 

  get getMessage() : any{  //가져옵니다.
    return this.message;
  }

}

 

아직은 잘 모르겠지만 id값과 pwd 값이 FormControl이라는 클래스로 변경된 것을 볼 수 있습니다.
tryToLogin 함수에서 값을 가져오는 방식이 value라는 속성으로 교체된 것이 흥미로워 보입니다.
다음으로는 login 컴포넌트html파일을 수정하여 줍니다.

* 대상 : login.component.html

<div>Wellocome</div>
<input type="text" placeholder="id"  [formControl]="id"/>
<input type="text" placeholder="password"  [formControl]="pwd"/>
<button (click)='tryToLogin()'>Login</button>
<div>
    <span  *ngIf="pwd.value && pwd.value.length < 4">비밀 번호 {{pwd.value}}는 4자리 이상이어야 합니다.</span>
</div>
<div *ngIf="getMessage" [ngClass]="styleArray">
   {{getMessage}}
</div>

 

기존의 ngModel 이 있던 자리에 formControl 이라는 속성이 추가 되었습니다.
위 내용으로 코드를 변경 하였다면 이제 프로젝트를 ng serve 명령어를 통해서 실행하여 줍니다.
그리고 테스트를 하여보도록 합니다.

따로 변하건 없어보입니다.

 

뭔가 달라지는 것은 안보입니다. 기능도 비슷 한 것 같습니다.
굳이 FormControl 이라는 기능을 붙인 이유가 무엇인지 궁금해집니다.
FormControl에 대해서 어떠한 내용이 있는지 살펴 보겠습니다.
login컴포넌트 파일에서 FormControl 클래스에 Ctrl + 마우스 클릭을 해 보면 해당 클래스의 정의를 볼 수 있습니다.

왓..엄청나게 긴 영문이..

 

앜..엄청난 내용입니다..
타입스크립트와 영어에 익숙하지 않는다면 사실 해당 내용만 보고 FormControl의 기능을 이해하는 것이 쉽지가 않아보입니다.
여기서 중요한 사실은 파라미터는 3개를 받을수 있으며, 각각의 파라미터는 or연산으로 통해서 여러형식을 갖을 수 있다는 점 입니다.

또한 파라미터별로 물음표(?)가 있는 것 으로 보아하니 파라미터 종류가 전부 옵셔널(Optional)이라는 점 입니다.
옵셔널은 파라미터가 있어도 그만, 없어도 그만인 부호입니다. 


자세히는 모르겠지만 formState, validatorOrOpts, asyncValidator 등 총 3가지 형태의 값을 받을 수 있다고 되어있습니다.
formState 값은 최초에 적용할 테그가 가질 수 있는 데이터를 의미하며 나머지 validator의 기호가 붙여진 2개의 변수는 바로 유효성 검사를 사용할 때 쓰여집니다.
여기서는 alidatorOrOpts에 해당하는 내용을 한번 적용하여 보겠습니다.
백문이 불여일견! 
login컴포넌트를 조금 수정하여 보겠습니다.

* 대상 : login.component.ts

import { Validators } from '@angular/forms';  //추가하여줍니다.

//..생략
export class LoginComponent implements OnInit {
    pwd = new FormControl('', [ Validators.required, Validators.minLength(4) ]); //폼 컨트롤러 클래스로 바꿉니다.
}

 

login컴포넌트 html도 수정하여 보겠습니다.

* 대상 : login.component.html

<div>Wellocome</div>
<input type="text" placeholder="id"  [formControl]="id"/>
<input type="text" placeholder="password"  [formControl]="pwd"/>
<button (click)='tryToLogin()'>Login</button>
<div>
    <span  *ngIf="pwd.hasError('minlength') || pwd.hasError('required') ">비밀 번호 {{pwd.value}}는 4자리 이상이어야 합니다.</span>
</div>
<div *ngIf="getMessage" [ngClass]="styleArray">
   {{getMessage}}
</div>

 

이제 한번 실행하여 봅니다.
놀랍게도 전과 동일한 기능이 동작하는 것을 볼 수 있습니다.

오..잘 동작합니다!

 

먼저 login컴포넌트에 대해서 살펴보겠습니다.
FormControl에서의 첫번째 값은 적용할 데이터를 의미합니다.

그리고 두번째 값은 해당 테그에서 유효성 검사에 사용할 대상을 의미하며 여기서는 배열형식으로 값을 부여하였습니다.
배열형식으로 부여한 형태의 값은 ValidatorFn종류의 타입(type)을 의미하며 앵귤러가 스스로 해당 형태를 확인하고 기능을 부여하여 줍니다.

* 타입(type)은 문자(변수 : string), 숫자(변수 : number)형식 등의 데이터의 형태를 의미합니다. 아래처럼 말이죠.

 ex) var num : number = 1234;  var txt : string = 'abcd';
* 명령어 declare와 type을 통해서 사용자만의 타입을 만들 수 있습니다.
* 맨 아래 login컴포넌트에서 test라는 변수에 사용자가 만든 type예문을 붙여놓았습니다. 어렵지 않아요!

 

이렇게 login컴포넌트에 설정을 하고 난 뒤에 login컴포넌트html파일에서는 hasError라는 함수에 앵귤러에서 정의된 값을 대입하여 유효성 검사여부를 확인하게 됩니다.
여기서 Validators.required는 required값이 필요하며, Validators.minLength()는 minlength 값이 필요합니다.

  * html파일에서는 대소문자 구분에 유의하여 주세요.
앵귤러에서 정의된 유효성 검사에 사용가능한 항목은 'maxlength','required', 'minlength', 'pattern' 등등 다양하게 존재합니다.

 

그러면, 로그인 버튼을 누르는 경우 짧은 비밀번호를 입력할 때와 4자리 이상의 비밀번호를 입력한 뒤에 pwd 변수의 상태를 확인하여 보겠습니다.
tryToLogin 함수에 console.log를 통하여 값을 출력하여 보겠습니다.

유효성 타입에 따라서 결과가 VALID와 INVALID가 나옵니다.

 

첫번째 콘솔 값은 비밀번호 aa를 입력하였습니다. pwd의 변수값에서 status라는 속성이 "INVALID"가 나온 것을 볼 수 있습니다.
두번째 콘솔 값은 비밀번호 aa12를 입력하였습니다. status라는 속성이 "VALID"가 나온 것을 볼 수 있습니다.
login컴포넌트html파일 뿐만 아니라 login컴포넌트에서도 값에 대해서 다양한 제약조건과 검사를 쉽게 할 수 있게된 것 입니다!
물론 당연하게도 사용자가 만든 기능을 붙일 수도 있습니다.
바로 3번째 파라미터에 사용자가 만든 유효성 검사기능을 가진 내용을 채워주면 되는 것 입니다.
그러나..해당 내용은 조금 복잡하므로 나중에 다시 살펴보겠습니다. ^^

 

이러한 FormControl은 기존에 사용되었던 ngModel 디렉티브와 마찬가지로 input type 형식의 엘리먼트(테그)에만 사용이 가능합니다.
그리고, FormControl의 상위 그룹핑 개념인 FormGroup, FormBuilder 라는 기능도 존재합니다.
해당 기능들은 다음장에서 언급하여 보겠습니다.

 

앵귤러에서의 ReactiveFormsModule 모듈은 이러한 Form과 관련한 테그의 기능을 좀 더 다양하고 쉽게 사용할 수 있게 하여줍니다.
이번시간에는 ReactiveFormsModule 모듈에서의 기초적인 사용법에 대해서 살펴 보았습니다.
다음시간에는 dashboard 컴포넌트를 활용하여 데이터를 바인딩 하는 기초부분에 대해서 좀더 살펴 보겠습니다.

 

* 사용자 지정 타입을 만든 모습의 예제 입니다.

* 대상 : login.component.ts

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

declare type MyCustomType = {  //사용자가 만든 타입입니다.
  text : any;
  number : any;
};

@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 = new FormControl('');  //폼 컨트롤러 클래스로 바꿉니다.
  pwd = new FormControl('', [ Validators.required, Validators.minLength(4) ]); //폼 컨트롤러 클래스로 바꿉니다.
  private message;
  styleArray = {'wrong_id':false, 'wrong_pwd':false};

  private test : MyCustomType = {  //타입관련 예제 입니다.
    text :'',
    number : 1234
  };
  constructor() { 
    
  }
  ngOnInit(): void {
    
  }
  tryToLogin() : void{
    console.log(this.pwd)
    if(this.id.value =='admin' && this.pwd.value == '1234'){
      alert('로그인합니다!');
      this.visible1 = true;
      this.sendMyEvent.emit(this.visible1);  //app컴포넌트에 전달
    } else if(this.id.value != 'admin'){
      this.setMessage = 'wrong id';
      this.styleArray.wrong_id = true;
      this.styleArray.wrong_pwd = false;
    } else if(this.pwd.value != '1234'){
      this.setMessage = 'wrong pwd';
      this.styleArray.wrong_id = false;
      this.styleArray.wrong_pwd = true;
    } 
  }
  set setMessage(arg){  //대입합니다.
    this.message = arg;
  } 
  get getMessage() : any{  //가져옵니다.
    return this.message;
  }

}

 

src.zip
0.01MB

 

 

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

댓글