본문 바로가기
개발/Programming

Node와 Angular를 이용하여 간단한 TODO App 예제 샘플 만들어보기

by 카루딘 2017. 8. 4.
반응형

출처:  http://egloos.zum.com/mcchae/v/11103678




근 MEAN.IO 에 대한 이야기를 들었습니다.


그림 하단에 나오듯이 Angular.js, node.js express (node module) mongoDB를 이용하여 JavaScript 로만 Full App Stack을 만들 수 있는 방법이라 하더군요.

그런데 관련 샘플을 찾다가,
"Single Page Applicatiion with Node and Angular" 라는 소개 블로그를 보았습니다.

이 블로그의 내용을 따라하면서 샘플 앱을 만들어 보도록 하겠습니다.

여기서 잠깐, SPA(Single Page Application) 이라고 있습니다.

정의만 간단히 살펴보면 SPA(단일 페이지 앱) 또는 SPI (단일 페이지 인터페이스) 라는 것은 데스크탑 응용프로그램과 같이 유연하고 여러 기능을 제공하는 목적을 달성하고자 하는 단일 웹 페이지에 적합한 웹 앱으로 정의 될 수 있습니다.

결국 위의 데스크탑 App 처럼 웹 브라우저로 동일한 기능의 App을 사용하고자 하는 목적을 달성하고자
X-Internet, RIA 에 이어 SPA로 용어가 정리되고 있군요.

자 다시 본론으로 돌아와서,

만들어 보려고 하는 것은,

  • 할일 모듬을 만들거나 끝내거나 하는 간단한 SPA
  • Mongoose를 이용한 할일을 MongoDB에 저장
  • Express (MVC) framework를 이용
  • RESTful Node API 생성
  • 사용자 UI와 API를 접속하기 위하여 Angular 이용
1) 기본 설정


1.1) 파일 구조



1.2) Node 모듈 설치

$ mkdir -p ~/workjs/mean_todo
$ cd ~/workjs/mean_todo
$ vi package.json
  {
  "name"         : "node-todo",
  "version"      : "0.0.0",
  "description"  : "Simple todo application.",
  "main"         : "server.js",
  "author"       : "Scotch",
  "dependencies" : {
    "express"    : "~3.4.4",
    "mongoose"   : "~3.6.2"
    }
  }
$ npm install


1.3) Node 설정

위에 package.json 에서 server.js 가 메인 시작 프로그램이고 이곳에서 다음과 같은 일을 할 것입니다.

  • app 설정
  • DB 연결
  • Mongoose 모델 생성
  • RESTful API 라우트 정의
  • Frontend Angular app을 위한 라우트 정의
  • 브라우저에서 보이도록 포트 리슨

$ cd ~/workjs/mean_todo
$ vi server.js
// server.js
// set up ========================
var express  = require('express');
var app      = express();  // create our app w/ express
var mongoose = require('mongoose'); // mongoose for mongodb

// configuration =================
// connect to mongoDB database on modulus.io
mongoose.connect('mongodb://localhost/todo'); 

app.configure(function() {
// set the static files location /public/img will be /img for users
app.use(express.static(__dirname + '/public'));
// log every request to the console
app.use(express.logger('dev'));
// pull information from html in POST
app.use(express.bodyParser());
// simulate DELETE and PUT
app.use(express.methodOverride());
});
// listen (start app with node server.js) ======================================
app.listen(8080);
console.log("App listening on port 8080");

위에 PyCharm으로 열었습니다.
지난번에 [PyCharm]으로 HTML, Javascript, Less 이용하기 (기초) 와 같이 열어 보았습니다.

1.4) DB 설정

$ brew update
$ brew install mongodb
$ cd ~/workjs/mean_todo
$ mkdir mongodb
$ mongod --dbpath ./mongodb



2) 응용프로그램 구조




3) Node API 생성


3.1) Todo Model

위와 같이 configuration과 listen 사이에

// define model =================
var Todo = mongoose.model('Todo', {
text : String
});

를 넣었습니다.


3.2) RESTful API 라우터

다시 server.js 를 열어

위와 같이 listen 위에 

// routes ======================================================================

// api ---------------------------------------------------------------------
// get all todos
app.get('/api/todos', function(req, res) {

// use mongoose to get all todos in the database
Todo.find(function(err, todos) {

// if there is an error retrieving, send the error. nothing after res.send(err) will execute
if (err)
res.send(err)

res.json(todos); // return all todos in JSON format
});
});

// create todo and send back all todos after creation
app.post('/api/todos', function(req, res) {

// create a todo, information comes from AJAX request from Angular
Todo.create({
text : req.body.text,
done : false
}, function(err, todo) {
if (err)
res.send(err);

// get and return all the todos after you create another
Todo.find(function(err, todos) {
if (err)
res.send(err)
res.json(todos);
});
});

});

// delete a todo
app.delete('/api/todos/:todo_id', function(req, res) {
Todo.remove({
_id : req.params.todo_id
}, function(err, todo) {
if (err)
res.send(err);

// get and return all the todos after you create another
Todo.find(function(err, todos) {
if (err)
res.send(err)
res.json(todos);
});
});
});

를 넣어 줍니다.


3.3) node 디버깅 및 GET 테스트

자 이제는 원본에 없는 내용인데 PyCharm으로 디버깅 하는 것을 살펴보겠습니다.

위와 같이 Local Node 실행을 하나 만들었습니다.

디버깅을 돌려봅니다~~

몽고 DB를 foreground 에서 돌리는데 위와 같이 다섯개씩 mongoose 가 Connection pool을 맺어 두는군요.

브라우저로 http://localhost:8080/api/todos 를 넣으면, get 이 호출되므로

위와 같이 Todo.find 안의 res.json(todos) 에서 브레이킹 되는군요.

PyCharm 으로 Node 개발까지 모두 끝내주다니... 끝내줍니다. (^^)



4) Angular로 Frontend 개발


4.1) Frontend 라우트 정의

다시 server.js 에서 

위와 같이

// application -------------------------------------------------------------
app.get('*', function(req, res) {
        // load the single view file
        // (angular will handle the page changes on the front-end)
res.sendfile('./public/index.html');
});

를 추가 했습니다.


4.2) Angular core.js 설정

위와 같이 (public 폴더를 만들고, 그 아래)에 core.js 를 만들어

// public/core.js
var scotchTodo = angular.module('scotchTodo', []);

function mainController($scope, $http) {
$scope.formData = {};

// when landing on the page, get all todos and show them
$http.get('/api/todos')
.success(function(data) {
$scope.todos = data;
console.log(data);
})
.error(function(data) {
console.log('Error: ' + data);
});

// when submitting the add form, send the text to the node API
$scope.createTodo = function() {
$http.post('/api/todos', $scope.formData)
.success(function(data) {
$scope.formData = {}; // clear the form so our user is ready to enter another
$scope.todos = data;
console.log(data);
})
.error(function(data) {
console.log('Error: ' + data);
});
};

// delete a todo after checking it
$scope.deleteTodo = function(id) {
$http.delete('/api/todos/' + id)
.success(function(data) {
$scope.todos = data;
console.log(data);
})
.error(function(data) {
console.log('Error: ' + data);
});
};
}

를 입력하고 저장합니다.

Angular module (scotchApp)와 컨트롤러 (mainController)를 만들었습니다.


4.3) FrontView index.html


public 폴더에 index.html 을 만듦니다.

  • Angular 모듈과 컨트롤러를 지정
  • 모든 할일을 구하여 페이지 초기화
  • todos 를 계속하여 수행
  • todo를 생성하기 위한 폼
  • 만약 체크되었다면 삭제
public 에 index.html을 새로 만들어

위와 같이,

<!-- index.html -->
<!doctype html>

<!-- ASSIGN OUR ANGULAR MODULE -->
<html ng-app="scotchTodo">
<head>
<!-- META -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"><!-- Optimize mobile viewport -->

<title>Node/Angular Todo App</title>

<!-- SCROLLS -->
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css"><!-- load bootstrap -->
<style>
html  { overflow-y:scroll; }
body  { padding-top:50px; }
#todo-list  { margin-bottom:30px; }
</style>

<!-- SPELLS -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script><!-- load jquery -->
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script><!-- load angular -->
<script src="core.js"></script>

</head>
<!-- SET THE CONTROLLER AND GET ALL TODOS -->
<body ng-controller="mainController">
<div class="container">

<!-- HEADER AND TODO COUNT -->
<div class="jumbotron text-center">
<h1>I'm a Todo-aholic <span class="label label-info">{{ todos.length }}</span></h1>
</div>

<!-- TODO LIST -->
<div id="todo-list" class="row">
<div class="col-sm-4 col-sm-offset-4">

<!-- LOOP OVER THE TODOS IN $scope.todos -->
<div class="checkbox" ng-repeat="todo in todos">
<label>
<input type="checkbox" ng-click="deleteTodo(todo._id)"> {{ todo.text }}
</label>
</div>

</div>
</div>

<!-- FORM TO CREATE TODOS -->
<div id="todo-form" class="row">
<div class="col-sm-8 col-sm-offset-2 text-center">
<form>
<div class="form-group">

<!-- BIND THIS VALUE TO formData.text IN ANGULAR -->
<input type="text" class="form-control input-lg text-center" placeholder="I want to buy a puppy that will love me forever" ng-model="formData.text">
</div>

<!-- createToDo() WILL CREATE NEW TODOS -->
<button type="submit" class="btn btn-primary btn-lg" ng-click="createTodo()">Add</button>
</form>
</div>
</div>

</div>

</body>
</html>

위와 같이 저장합니다.



5) 실행 및 기동


우측 상단의 실행 단추를 눌러 server.js 노드 앱을 기동시키고...

디폴트 라우트에 의하여 public/index.html 이 동작되었습니다.

열심히 네 개의 할일을 넣었더니만...

게중, 하나를 체크하였더니 ... 우왕 이렇게 쉽게 SPA 를 만들다니...

mongo 로 확인을 해 보면.. 이렇게 잘 연동이 되었습니다.

단일 mongoose로 ORM 모델링을 하여 바로 연동하여 이것을 RESTful 로 붙이는 것이 가장 간단한 앱을 쉽게 만들 수 있는 지름길 이군요.

AxisJ의 장기영 팀장님 강의를 들으니 RESTful 중에서 put 은 update 만을 위한 것이라는 것도 기억에 남네요...


어느분께는 도움이 되셨기를...


반응형