이번에는 Ajax를 이용해 데이터를 가져오고, 이를 바인딩 시켜주는 간단한 어플리케이션을 만들어 봅니다. 이번 강좌를 위한 환경 설정은 2018/07/11 - [개발자] - [TypeScript 기초] 1. 환경 설정을 참고 하시기 바랍니다.

우선 기존 튜토리얼에서 개발했던 모든 TypeScript 파일을 삭제합니다. 그 후 필요한 추가 모듈을 설치해 주어야 합니다. JQuery Ajax를 이용할 것이기 때문에 JQuery 모듈을 설치해 줍니다.

1
2
npm install jquery
npm install @types/jquery --save-dev
cs


2장부터 차례대로 따라왔으면 package.json 파일은 아래와 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
  "name": "typescript-example",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "light-server -s . -p 3000"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "jquery": "^3.3.1",
    "knockout": "^3.4.2"
  },
  "devDependencies": {
    "@types/jquery": "^3.3.4",
    "@types/knockout": "^3.4.58",
    "light-server": "^2.5.1"
  }
}
 
cs


index.html은 아래와 같이 변경해 줍니다. 화면에 예쁘게 뿌리기 위해서 Bootstrap을 CDN에서 import 해 주었습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>Hello Knockout!</title>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    </head>
    <body>
        <div class="container">
            <div class="row">
                <div class="col-12">
                    <h3>Received At: <span data-bind="text: receivedAt"></span></h3>
                </div>
            </div>
            <div class="table-responsive">
                <table class="table">
                    <thead>
                        <tr>
                            <th>Image</th>
                            <th>Title</th>
                        </tr>
                    </thead>
                    <!-- ViewModel에 있는 blogs property를 iterator하면서 데이터를 뿌려줍니다 -->
                    <tbody data-bind="foreach: blogs">
                        <tr>
                            <td><img class="img-thumbnail" data-bind="attr: {src: thumbnail.startsWith('http') ? thumbnail : ''}"></td>
                            <td data-bind="text: title"></td>
                        </tr>
                    </tbody>
                </table>
            </div>
        </div>
        
        <script src="/built/bundle.js"></script>
    </body>
</html>
cs

src 폴더에 다음 TypeScript를 개발해 줍니다.

Blog.ts

1
2
3
4
5
6
7
8
9
export default class Blog {
    title: string;
    thumbnail: string;
 
    public constructor(title: string, thumbnail: string) {
        this.title = title;
        this.thumbnail = thumbnail;
    }
}
cs


BlogService.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import * as $ from "jquery";
 
// IBlogService 인터페이스를 정의합니다.
export interface IBlogService {
    getBlogs(callback: Function): void;
}
 
// IBlogService에 대한 구현 서비스입니다.
export default class BlogService implements IBlogService {
    getBlogs(callback: Function): void {
        // Ajax를 이용해 blog를 가져옵니다. getBlogs의 callback method에 title과 thumbnail을 찾아 호출해 줍니다.
        $.ajax({
            url: "https://www.reddit.com/r/frontend.json",
            method: "GET",
            success: (response) => {
                // Array의 map 함수는 Array를 전개시켜 새로운 Array를 만들어 주는 함수 입니다.
                callback(response.data.children.map(child => ({ title: child.data.title, thumbnail: child.data.thumbnail })));
            },
            error: () => {
                console.log("Ajax error!");
            }
        });
    }
}
cs


BlogViewModel.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
import * as ko from "knockout";
import Blog from "./Blog";
 
export default class BlogViewModel {
    // blogs를 knockout observable array로 정의합니다.
    blogs: KnockoutObservableArray<Blog>;
    receivedAt: number;
 
    constructor() {
        this.blogs = ko.observableArray();
        this.receivedAt = Date.now();
    }
}
cs


index.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import * as ko from "knockout";
import Blog from "./Blog";
import BlogService from "./BlogService";
import BlogViewModel from "./BlogViewModel";
 
// ViewModel 객체를 생성하고, Knockout 바인딩을 해 줍니다.
const viewModel = new BlogViewModel();
ko.applyBindings(viewModel);
 
// BlogService 객체를 생성합니다.
const blogService = new BlogService();
 
// 블로그를 가져오는 서비스를 호출합니다.
// Callback function을 Fat arrow function으로 정의하고 함수 파라미터에 대한 interface를 정의하였습니다.
// data: {title: string, thumbnail: string}[] 가 함수 파라미터 인터페이스 정의 입니다.
// => 표시가 Fat arrow function 입니다.
blogService.getBlogs((data: {title: string, thumbnail: string}[]) => {
    const blogs = data.map(item => new Blog(item.title, item.thumbnail));
    viewModel.blogs(blogs);
});
cs


모든 개발이 완료 되었으면 터미널에서

tsc 커맨드로 컴파일을 해준 후 browserify --entry ./built -o ./built/bundle.js 로 번들링을 해 줍니다.

Web Server를 중지 시켰으면, npm start로 재시작 해줍니다.

Reddit에서 불러온 결과가 화면에 뿌려지는 것을 볼 수 있습니다.

매번 소스 변경 시 컴파일 후 번들링하는 커맨드는 매우 귀찮은 작업입니다. 이를 위해 Task를 관리할 수 있는 툴이 있는데 가장 유명한 것인 grunt와 gulp입니다. webpack은 원래 번들링툴인데, 추가적인 기능이 많아져서 요즘은 webpack을 많이 씁니다만, webpack도 gulp 기반으로 돌아갑니다. 다음 시간에는 gulp로 귀찮은 컴파일과 번들링 작업을 한방에 해결하는 방법을 알아보겠습니다.

Happy coding 하세요.


  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기