로그인 앱 설계

 

지난번까지 로그인 앱에 대한 폴더 구조를 알아봤다. 지금까지 했던 작업들과 다르게 로그인 앱 설계 부분에서는 node.js를 통한 서버 환경을 구현했다. server 폴더 하위에 index.js 파일에 서버를 구현하는 로직이 있다.

 

const path = require('path');
const express = require('express');
const morgan = require('morgan');
const { urlencoded, json } = require('body-parser');
const { v4 } = require('uuid');
const axios = require('axios');
const app = express();

app.use(express.static('dist'));
app.use(morgan('dev'));
app.use(urlencoded({ extended: false }))
app.use(json())

app.get('/api/user/:id', (req, res) => {
  ...
});

app.get('/api/user/:id/posts', (req, res) => {
  ...
});

app.post('/api/authentication', (req, res) => {
  if (Math.floor(Math.random() * 10) % 2 === 0) {
    res.status(200).send({
      status: 'OK',
      result: {
        id: Math.floor(Math.random()*10),
        token: v4(),
      }
    });
  } else {
    res.status(400).send({
      status: 'Error'
    });
  }
});

app.listen(8080, () => {
  console.log('ready to dumy signup server');
});

 

코드를 보면 상단엔 import 하는 부분이 모여있다. require를 통해서 여러가지 라이브러리를 사용할 수 있다. npm을 통해서 라이브러리를 다운 받은 파일도 마찬가지로 사용한다. 여기선 웹 서버를 사용할 것이기 때문에 node.js의 웹 프레임워크인 express.js를 사용한다. 서버처리가 필요한 작업들은 해당하는 파일에서 작업할 것이다. 클라이언트 사이드에서 / 를 통한 경로는 화면을 변경하는 라우팅 경로가 되는것이지만 서버에서는 데이터를 전달하거나 조건에 맞는 데이터를 가공하는 역할을 한다. 현재 작업에서는 로그인 작업이 필요하기 때문에 로그인 처리를 해주는 로직을 사용할 것이다.

 

로그인을 하는 전반적인 처리를 하기 위해서 우리는 HTTP 프로토콜을 사용할 것이다. HTTP의 특징으로는 1. 비동기 처리를 하고 2. 무상태(상태가 없어야 함)여아 하는 특징이 있기 때문에 로그인한 유저인지 아닌지 알기 위해서는 로직에서 토큰이라는 값이 필요하다. 따라서 서버에서 토근을 처리해주는 로직이 들어 갈 것이다.

 

 

 

 

https://bit.ly/37BpXiC

 

패스트캠퍼스 [직장인 실무교육]

프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.

fastcampus.co.kr

 

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.

 

#패스트캠퍼스 #패캠챌린지 #직장인인강 #직장인자기계발 #패스트캠퍼스후기 #김민태의프론트엔드아카데미:제1강JavaScript&TypeScriptEssential

로그인 앱 설계

 

로그인 앱 설계 파트에서는 여러가지 API들을 호출하는 관점에서 어떻게 코드를 작성할 것인가에 대해, 두번째는 이전의 회원가입 웹앱에서 사용하고 구분했었던 필드부분(Text, Password, Address 등)의 클래스에서 공통적으로 사용했던 (vaildate나 render, template와 같은) 반복적인 처리를 어떻게 할 것인가에 대해 다룬다.

 

또한 이번 장에서는 API 여러처리를 위해 서버를 갖는다. node.js로 구성되어 있으며 서버를 거쳐야하는 여러가지의 처리를 제어할 것이다.

 

- 폴더 구조

server
  |- index.js
src
  |- page
    - login.js
    - login.template.js
    - page-not-found.js
    - page-not-found.template.js
    - profile.js
    - profile.template.js
  |- utils
    - api.js
    - index.js
  |- views
    - core.js
    - text-field.js
    - text-field.template.js
  - constant.js
  - index.js
  - store.js

이전까지의 폴더구조와 다르게 루트 경로에 server폴더와 안에 index.js라는 서버처리를 할 파일이 있다. 또 같은 경로엔 마찬가지로 src폴더가 있으며 클라이언트 사이드에서 사용하는 화면 처리 부분은 src 하위에서 작업한다. 먼저 index.js는 라우팅 처리를 하는 담당하는 파일이다. store.js는 스토어 패턴이라해서 getter와 setter로 이루어져 값을 변경하거나 반환할때 전역적으로 사용할 것이다. constant.js는 vaildateRules을 정의하는 파일이고 page폴더 안에 있는 파일들은 로직처리를 하는 파일과 템플릿을 지정한 파일 쌍으로 로그인, 404에러 페이지, 프로필 등으로 나누어져 있다. 또한 utils 폴더안의 api.js 파일은 api를 사용할 때 공통적으로 사용하는 get과 post방식의 구조를 정의한 파일이며 index.js 파일은 공통적으로 사용할 setTimeout을 통해 비동기처리를 정의한 파일이다.

 

로그인 파트에서 아이디를 입력할 때와 패스워드를 입력하는 필드를 사용하는데 views 폴더 하위에 core.js 파일을 정의했다. 회원가입 웹앱 부분에서는 텍스트나 패스워드, 어드레스 등을 따로 구분했지만 해당 파트에서는 core.js 파일에서 해당하는 파일의 필드의 공통적으로 사용되는 부분을 정의하고 다른 파일에서 상속을 통해 사용하여 코드를 줄이고 구조화 할 수 있다.

 

 

 

 

https://bit.ly/37BpXiC

 

패스트캠퍼스 [직장인 실무교육]

프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.

fastcampus.co.kr

 

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.

 

#패스트캠퍼스 #패캠챌린지 #직장인인강 #직장인자기계발 #패스트캠퍼스후기 #김민태의프론트엔드아카데미:제1강JavaScript&TypeScriptEssential

회원 가입 폼 - 정보 UX 선택하기

 

회원가입 폼에서도 그렇지만 어떤 기능을 하는 웹에는 API를 사용하는 경우가 많다. API를 구현하는 것은 그렇게 어렵지 않지만 사용하려고 하는 API가 만들려고 하는 서비스에 부합하는 기능을 지원하는지, 해당하는 API의 지속 가능성이라던지 문서화가 얼마나 잘 되어있는지 등의 요건들을 맞추고 선택하는 것이 더 중요할 것이다.

 

회원가입 웹앱에서는 다음의 지도 API를 사용할 것이다.

 

<script src="//t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js"></script>
export default class AddressField {
  private template = template;
  private container: string;
  private data: Props;
  private address1?: string;
  private zipcode?: string;

  constructor(container: string, data: Props) {
    this.container = container;
    this.data = { ...DefaultProps, ...data };
  }

  ...

  public render = (append: boolean = false) => {
    ...

    container.querySelector(`#search-address`)?.addEventListener('click', () => {
      new window.daum.Postcode({
        oncomplete: (data: DaumAddress) => {
          this.address1 = data.roadAddress;          
          this.zipcode = data.sigunguCode;
          
          (container.querySelector('#address1') as HTMLInputElement).value = `(${this.zipcode}) ${this.address1}`;
        }
      }).open();  
    });
  }
}

 

위에 있는 script 태그의 url은 카카오(다음)에서 지도를 사용하기 위해 사용하는 스크립트 파일이며 아래의 코드는 API 가이드에서 기능을 사용하는 방식이다. 렌더 메소드에서 address 필드를 선택자로 지정하고 클릭 이벤트를 통해 API 인스턴스를 생성한다. 주소를 입력하게되면 address 인스턴스에 address1, zipcode 필드에 API에서 가져오는 데이터의 주소와 우편번호를 저장할 수 있다.

 

 

 

 

https://bit.ly/37BpXiC

 

패스트캠퍼스 [직장인 실무교육]

프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.

fastcampus.co.kr

 

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.

 

#패스트캠퍼스 #패캠챌린지 #직장인인강 #직장인자기계발 #패스트캠퍼스후기 #김민태의프론트엔드아카데미:제1강JavaScript&TypeScriptEssential

회원 가입 폼 - 정보 UX 선택하기

 

기본적으로 buildData 메소드를 통해 기준에따라 맞는 데이터를 만들고 template에 반영하게 되면 회원가입 화면 필드에 입력된 값에 따라 변경되는 일련의 작업이 이루어진다.

 

이런 전체적인 구조는 비슷하지만 각 필드마다 약간의 차이가 있다. 패스워드 필드 같은 경우 기본 밸리데이션을 제외한 추가적인 밸리데이션 구조를 갖는다. 

 

import { nextTick } from '../utils';
import { ValidateRule } from '../types';
import template from './password-field.template';
import { RequireRule } from '../constant';

enum StrongLevel {
  None = 0,
  Light,
  Medium,
  Havey,
}

type Props = {
  id: string;
  label: string;
  text?: string;
  require?: boolean;
  placeholder?: string;
  strong?: StrongLevel;
}

const StrongMessage: [string, string, string, string] = [
  '금지된 수준',
  '심각한 수준',
  '보통 수준',
  '강력한 암호',
];

const DefaultProps: Props = {
  id: '',
  label: 'label',
  text: '',
  require: true,
  placeholder: '',
  strong: StrongLevel.None,
};

export default class PasswordField {
  private template = template;
  private container: string;
  private data: Props;
  private updated: boolean = false;
  private validateRules: ValidateRule[] = [];

  constructor(container: string, data: Props) {
    ...
  }

  private onChange = (e: Event) => {
    ...
  }

  private attachEventHandler = () => {
    ...
  }

  private buildData = () => { 
    let strongLevel = -1;
    const isInvalid: ValidateRule | null = this.validate();

    if (this.data.text!.length > 0) {
      strongLevel++;
    }

    if (this.data.text!.length > 12) {
      strongLevel++;
    }

    if (/[!@#$%^&*()]/.test(this.data.text!)) {
      strongLevel++;
    }

    if (/\d/.test(this.data.text!)) {
      strongLevel++;
    }

    return {
      ...this.data, 
      updated: this.updated,
      valid: this.updated ? !isInvalid : true,
      strongMessage: strongLevel < 0 ? '' : StrongMessage[strongLevel],
      strongLevel0: strongLevel >= 1,
      strongLevel1: strongLevel >= 2,
      strongLevel2: strongLevel >= 3,
      strongLevel3: strongLevel >= 4,
    };
  }

  private validate = (): ValidateRule | null => {
    ...
  }

  private update = () => {
    ...
  }

  public get name(): string {
    ...
  }

  public get value(): string {
    ...
  }

  public get isValid(): boolean {
    ...
  }

  public addValidateRule = (rule:ValidateRule) => {
    ...
  }

  public render = (append: boolean = false) => {
    ...
  }
}

 

password-filed.ts는 다른 필드와 다르게 추가적으로 StrongLevel이라는 enum과 StrongMessage라는 튜플을 갖는다. 기본적으로 가지고 있는 밸리데이션 안에서 추가적으로 체크하는 밸리데이션이며 이 밸리데이션은 충족하지 않아도 데이터를 전송할 수 있다. 다만 입력된 데이터의 유효성의 단계를 체크한다. StrongLevel은 숫자 형태의 값이며 StrongMessage는 그 숫자에 따라 메세지가 달라진다.

 

이 작업은 password-filed.ts의 buildData 메소드에서 진행한다. 유효성 체크에서 만족하는 부분이 없으면 -1 값이며 각각의 밸리데이션을 만족하게되면 1씩 숫자가 올라가고 리턴할 때 해당하는 값을 전달한다.

 

 

 

 

https://bit.ly/37BpXiC

 

패스트캠퍼스 [직장인 실무교육]

프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.

fastcampus.co.kr

 

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.

 

#패스트캠퍼스 #패캠챌린지 #직장인인강 #직장인자기계발 #패스트캠퍼스후기 #김민태의프론트엔드아카데미:제1강JavaScript&TypeScriptEssential

회원 가입 폼 - 정보 UX 선택하기

 

데이터와 기능에따라 화면을 변경하는 것으로 render 메소드와 update 메소드를 구분했다. render 메소드는 화면을 변경할 때 해당하는 컨테이너의 모든 내용을 전부 렌더링 하는 반면에 update 메소드는 해당하는 화면의 컨테이너의 기존 기능과 내용은 그대로 두고 새로운 기능이나 내용을 렌더링 한다. 

 

export default class TextField {
  private template = template;
  private container: string;
  private data: Props;  
  private updated: boolean = false;
  private validateRules: ValidateRule[] = [];

  constructor(container: string, data: Props) {
    this.container = container;
    this.data = { ...DefaultProps, ...data };

    if (this.data.require) {
      this.addValidateRule(RequireRule);
    }

    nextTick(this.attachEventHandler);
  }

  private validate = (): ValidateRule | null => {
    const target = this.data.text ? this.data.text.trim() : '';

    const invalidateRules = this.validateRules
      .filter(validateRule => validateRule.rule.test(target) !== validateRule.match);

    return (invalidateRules.length > 0) ? invalidateRules[0] : null;
  }

  private buildData = () => {
    const isInvalid: ValidateRule | null = this.validate();

    if (this.updated) {
      return {
        ...this.data, 
        updated: this.updated,
        valid: !isInvalid,
        validateMessage: !!isInvalid ? isInvalid.message : ''
      }
    } else {
      return {
        ...this.data, 
        updated: this.updated,
        valid: true,
        validateMessage: ''
      }
    }
  }

  private onChange = (e: Event) => {
    ...
  }

  private attachEventHandler = () => {
    ...
  }

  private update = () => {
    const container = document.querySelector(`#field-${this.data.id}`) as HTMLElement;
    const docFrag = document.createElement('div');

    docFrag.innerHTML = this.template(this.buildData());
    container.innerHTML = docFrag.children[0].innerHTML;
  }

  public get name(): string {
    ...
  }

  public get value(): string {
    ...
  }

  public get isValid(): boolean {
	...            
  }

  public addValidateRule = (rule:ValidateRule) => {
    ...
  }

  public render = (append: boolean = false) => {
    ...
}

 

update 메소드를 통해서 화면을 렌더링하는 부분에서 buildData 메소드를 사용하게 된다. 이 메소드는 fields에 저장된 데이터를 가져오는 역할을 하는데 데이터의 유효성을 체크하기 위해 vaildate 메소드를 사용할 것이다. validate 메소드는 저장 되어있는 데이터를 filter 함수를 통해 순회하게된다. rule이 정규식으로 이루어져 있기때문에 데이터의 입력과 매칭이 되는지 안되는지 체크를 할것이다. boolean 값으로 체크를 하게 되면 순회하고나서 하나도 체크되는 값이 없으면 통과가 될것이고 하나라도 체크된다면 해당하는 유효성을 검증하고 메세지를 보내줄 것이다.

 

돌아와서 validate 메소드에서 체크한 값을 buildData 메소드에서 사용하기전에 buildData 메소드는 updated 값을 체크하게 된다. 그 이유는 처음 화면을 로딩했을 때 한번이라도 필드의 값의 변경이 일어났는지 아닌지의 체크를하고 한번 이상일 시에만 밸리데이션 체크값을 보낼 수 있도록 체크를 한다.

 

이렇게 실행을 하고나면 template에 buildData 메소드에서 반환하는 값을 전달한다.

 

 

 

 

https://bit.ly/37BpXiC

 

패스트캠퍼스 [직장인 실무교육]

프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.

fastcampus.co.kr

 

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.

 

#패스트캠퍼스 #패캠챌린지 #직장인인강 #직장인자기계발 #패스트캠퍼스후기 #김민태의프론트엔드아카데미:제1강JavaScript&TypeScriptEssential

회원 가입 폼 - 정보 UX 선택하기

 

회원 가입 폼에서 해당하는 필드 값들을 입력했을 때, 이벤트 핸들러에서 변경이 되는 부분을 체크하고 해당하는 부분이 맞다면 onChange 메소드를 실행하여 변경된 값을 체크하고 값을 가져오는 부분까지 진행했다.

 

onChange 메소드에는 update 메소드를 실행하는데 update 메소드 이후에 진행에 대해 알아보겠다.

 

export default class TextField {
  private template = template;
  private container: string;
  private data: Props;  
  private updated: boolean = false;
  private validateRules: ValidateRule[] = [];

  constructor(container: string, data: Props) {
    this.container = container;
    this.data = { ...DefaultProps, ...data };

    if (this.data.require) {
      this.addValidateRule(RequireRule);
    }

    nextTick(this.attachEventHandler);
  }

  private validate = (): ValidateRule | null => {
    ...
  }

  private buildData = () => {
    ...
  }

  private onChange = (e: Event) => {
    const { value, id } = e.target as HTMLInputElement;
  
    if (id === this.data.id) {
      this.updated = true;
      this.data.text = value;
      this.update();
    }
  }

  private attachEventHandler = () => {
    ...
  }

  private update = () => {
    const container = document.querySelector(`#field-${this.data.id}`) as HTMLElement;
    const docFrag = document.createElement('div');

    docFrag.innerHTML = this.template(this.buildData());
    container.innerHTML = docFrag.children[0].innerHTML;
  }

  public get name(): string {
    ...
  }

  public get value(): string {
    ...
  }

  public get isValid(): boolean {
    ...
  }

  public addValidateRule = (rule:ValidateRule) => {
    ...
  }

  public render = (append: boolean = false) => {
    ...
}

 

update 메소드를 살펴보면 컨테이너를 받아오고 innerHTML을 통해서 만든 필드를 변경하는데, buildData 메소드를 통해 데이터를 받아온 것을 div 태그로 한번 감싸서 컨테이너에 innerHTML로 변경한다. 이렇게 하는 이유는 이벤트 핸들러 때문인데 가장 최상위 컨테이너를 남겨놓고 하위에 있는 필드값을 변경한다. 그렇게하면 이벤트 핸들러를 건드리지 않아서 값을 변경할 때마다 이벤트 핸들러를 새로 추가하지 않아도 된다. 그러면 여러가지 코드 구성이나 메모리 측면에서 생길 수 있는 문제 등을 보완 할 수 있다. 

 

 

 

 

https://bit.ly/37BpXiC

 

패스트캠퍼스 [직장인 실무교육]

프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.

fastcampus.co.kr

 

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.

 

#패스트캠퍼스 #패캠챌린지 #직장인인강 #직장인자기계발 #패스트캠퍼스후기 #김민태의프론트엔드아카데미:제1강JavaScript&TypeScriptEssential

회원 가입 폼 - 정보 UX 선택하기

 

예전 화면 방식을 살펴보면 정보를 전부 입력하고 submit 버튼을 눌렀을 때, 입력된 정보들의 밸리데이션을 체크하고 최종적으로 사용자에게 결과를 반환해준다.

 

하지만 해당 방식은 잘 사용하지 않는다. 사용자에게 가능한 즉시 결과를 반환해주고 수정할 수 있도록 하는 추세이다. 또한 한번도 입력하지 않았을 시에는 밸리데이션 체크를 하지않으며 한번 이상 입력을 하고 나왔을 시엔 밸리데이션 체크를 하도록 설계한다.

 

export default class TextField {
  private template = template;
  private container: string;
  private data: Props;  
  private updated: boolean = false;
  private validateRules: ValidateRule[] = [];

  constructor(container: string, data: Props) {
    this.container = container;
    this.data = { ...DefaultProps, ...data };

    if (this.data.require) {
      this.addValidateRule(RequireRule);
    }

    ...
  }

  private validate = (): ValidateRule | null => {
    ...
  }

  private buildData = () => {
	...
  }

  private onChange = (e: Event) => {
    const { value, id } = e.target as HTMLInputElement;
  
    if (id === this.data.id) {
      this.updated = true;
      this.data.text = value;
      this.update();
    }
  }

  private attachEventHandler = () => {
    document.querySelector(this.container)?.addEventListener('change', this.onChange);
  }

  private update = () => {
    ...
  }

  public get name(): string {
    ...
  }

  public get value(): string {
    ...
  }

  public get isValid(): boolean {
    ...
  }

  public addValidateRule = (rule:ValidateRule) => {
    ...
  }

  public render = (append: boolean = false) => {
   ...
  }
}

 

해당하는 필드에 값을 체크하기 위해선 이벤트리스너의 change 값을 체크 해보아야한다. attactchEventHandler 메소드에서 그 작업을 하며, change의 콜백으로 onChange 메소드를 사용한다.

 

onChange 메소드에서는 해당하는 이벤트 타겟의 value와 id 값을 가져와서 App 클래스에 TextField의 인스턴스로 지정 되어있는 id 값과 비교한다. 이유는 필드는 TextField, PasswordField, AddressField 클래스로 나누어져 있고 각 해당하는 필드는 인스턴스로 생성되어 있기 때문이다.

 

돌아와서, onChange 메소드에서 id 값을 체크하고 맞다면 this.updated 변수가 true가 된다. 이 부분이 위에서 설명했던 필드 값에 한번 이상 진입을 했는지 안했는지 체크를 하는 부분이다. 그리고 해당하는 this.data 오브젝트의 text 부분에 입력한 값을 저장하고 update 메소드를 실행한다.

 

 

 

 

https://bit.ly/37BpXiC

 

패스트캠퍼스 [직장인 실무교육]

프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.

fastcampus.co.kr

 

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.

 

#패스트캠퍼스 #패캠챌린지 #직장인인강 #직장인자기계발 #패스트캠퍼스후기 #김민태의프론트엔드아카데미:제1강JavaScript&TypeScriptEssential

회원 가입 폼 - 밸리데이션 구조 설계

 

회원 가입 폼 웹앱에 사용되는 밸리데이션 구조를 체크하는 로직을 constant.ts 파일에 만들었다. 이제 이러한 각각의 밸리데이션 룰을 어떻게 적용할 것인지에 대해 정해야 한다.

 

하나의 필드에 하나의 밸리데이션만 들어갈 수도 있지만 여러가지의 밸리데이션을 통해 유효성을 체크해야 하는 경우가 있을것이다.

 

export default class App {
  ...
  fields: AnyObject[];

  constructor(container: string, data: AnyObject = {}) {
    ...
    
    this.fields = [];
    this.initialize();
    
    ...
  }

  private initialize = () => {
    const nameField = new TextField('#required-fields', { 
      id: 'name', label: '이름', type: 'text', placeholder: '이름을 입력해주세요', require: true,
    });

    const idField = new TextField('#required-fields', { 
      id: 'id', label: '아이디', type: 'text', placeholder: '아이디를 입력해주세요', require: true,
    });

    const emailField = new TextField('#required-fields', { 
      id: 'email', label: '이메일', type: 'email', placeholder: '이메일을 입력해주세요', require: true,
    });
    
    const passwordField = new PasswordField('#required-fields', { 
      id: 'password', label: '비밀번호', placeholder: '비밀번호를 입력해주세요', 
    });

    const addressField = new AddressField('#optional-fields', {
      id: 'address', label: '배송지 주소',
    });

    idField.addValidateRule(CantContainWhitespace);
    idField.addValidateRule(CantStartNumber);
    idField.addValidateRule(MinimumLengthLimit(3));

    emailField.addValidateRule(CantContainWhitespace);

    this.fields.push(nameField);
    this.fields.push(idField);
    this.fields.push(emailField);
    this.fields.push(passwordField);
    this.fields.push(addressField);
  }

  private validFieldMonitor = () => {
    ...
  }

  private onSubmit = (e: Event) => {
    ...
  }

  public render = () => {
    this.container.innerHTML = this.template(this.data);
    this.fields.forEach(field => {
      field.render(true);
    });

    this.container.addEventListener('submit', this.onSubmit);
  }
}

 

App 클래스에 fields 배열엔 AnyObject 타입의 배열을 받는다. 또한 App 생성자함수에선 처음에 모든 기능을 초기화하는 initialize 메소드를 실행하는데 이 때, 각 필드별로 사용될 인스턴스를 생성하고 해당하는 인스턴스에 addVaildateRule 메소드를 통해 여러가지 밸리데이션을 등록한다. initalize 메소드를 보면 idField에는 세가지의 밸리데이션이 추가되고 emailField에는 한가지의 밸리데이션이 추가된다.

 

처음 생성시 초기화 작업이 되고나서 App 인스턴스의 render 메소드를 통해 해당하는 View 클래스의 인스

턴스에 추가된 render 메소드를 호출해주면 UI 전체가 만들어지는 형태가 될 것이다.

 

 

 

 

https://bit.ly/37BpXiC

 

패스트캠퍼스 [직장인 실무교육]

프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.

fastcampus.co.kr

 

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.

 

#패스트캠퍼스 #패캠챌린지 #직장인인강 #직장인자기계발 #패스트캠퍼스후기 #김민태의프론트엔드아카데미:제1강JavaScript&TypeScriptEssential

+ Recent posts