├── .gitignore ├── README.md ├── client ├── index.html └── js │ ├── app.js │ ├── controllers │ └── TodomvcCtrl.js │ ├── directives │ └── todoItem.js │ └── services │ └── TodomvcStorage.js ├── gulpfile.js ├── package.json ├── screenshot-preview.png ├── screenshot-structure.jpg └── server └── app.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | /node_modules 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | todomvc-angular 2 | =============== 3 | 4 | ## 미리보기 5 | 6 | 이번 강의에서 만들 결과물을 미리 보자. 7 | 8 | * 투두(Todo) 목록을 조회 9 | * 추가, 편집, 삭제, 완료 처리 (CRUD) 10 | * 투두의 상태에 따라 completed(완료), active(진행중)로 필터링 11 | 12 | ![screenshot](screenshot-preview.png) 13 | 14 | ## 프로젝트 구조 15 | 16 | ### 백엔드 17 | 18 | * 서버는 [Node.js](https://nodejs.org/en/)기반의 [Express.js](http://expressjs.com) 웹프레임웍을 사용함 19 | * 서버는 1) html, css, javascript 등의 정적 파일을 호스팅하고 2) ajax 기능을 수행할 api를 제공함 20 | 21 | ### 프론트엔드 22 | 23 | * 웹페이지는 [Angular.js](https://angularjs.org)를 사용한 하나의 페이지(index.html)로 구성됨 24 | * 앵귤러 컨트롤러로 웹페이지를 조작하고 앵귤러 서비스를 통해 백엔드 api와 통신함 25 | 26 | ![screenshot-structure](screenshot-structure.jpg) 27 | 28 | ## 개발 환경 29 | 30 | ### Node.js 31 | 32 | * [https://nodejs.org/en/](https://nodejs.org/en/)에서 다운로드 후 설치 33 | * 웹서버 구동과 프로젝트 관리를 위해 사용 34 | 35 | ### NPM 36 | 37 | * Node Package Manager 38 | * 노드 패키지를 프로젝트에 추가, 삭제하거나 직접 작성한 패키지를 배포할 때 사용함. 39 | * 본 프로젝트에서는 angularjs등 외부 라이브러리 설치시 사용 40 | * 노드를 설치하면 자동으로 NPM도 설치됨 41 | * *이후 Bower, Gulp 등 개발 툴은 상황에 따라 추가 설명할 예정* 42 | 43 | ## 프로젝트 초기화 44 | 45 | * Npm으로 프로젝트 초기화 46 | 47 | ``` 48 | $ mkdir todomvc && cd todomvc 49 | $ npm init 50 | ``` 51 | 52 | * package.json: 프로젝트 정보를 담고 있음. 53 | * 특히 dependencies에는 프로젝트에서 사용하는 외부 라이브러리 정보가 기록됨 54 | 55 | ## 앵귤러 시작 56 | 57 | * index.html 작성 58 | 59 | ```html 60 | 61 | 62 | 63 | 64 | 65 | 67 | Angular | TodoMVC 68 | 69 | 70 | 71 | 72 | ``` 73 | 74 | * Npm 으로 앵귤러 설치: 75 | 76 | ``` 77 | $ npm install angular --save 78 | ``` 79 | * save 옵션을 주는 것은 이 프로젝트가 앵귤러 라이브러리를 사용한다는 것을 알리는 것 80 | * 이 정보는 package.json의 dependencies에 추가됨 81 | * 앵귤러 라이브러리를 로딩하고 **모듈(module)**, **컨트롤러(controller)** 생성 82 | * `ng-app`: 브라우져에게 앵귤러 모듈을 사용한다고 알림 83 | * `ng-controller`: 브라우져에게 앵귤러 컨트롤러를 사용한다고 알림 84 | 85 | ```html 86 | 87 | 88 | 89 | 90 | 91 | 98 | 99 | 100 | ``` 101 | 102 | ## [TIP] brower-sync 103 | 104 | * [bower-sync](https://www.browsersync.io/)는 코드변호에 따라 브라우져를 리프레시 해주는 툴 105 | * 내부적으로 웹서버를 구동함 106 | * Npm을 이용해 글로벌로 설치 107 | 108 | ``` 109 | $ npm install -g browser-sync 110 | $ browser-sync start --server --files "./**/*" 111 | ``` 112 | 113 | ## Controller 114 | 115 | * Html로 작성된 템플릿과 연결되어 데이터를 출력하고 사용자 입력을 처리하는 것이 컨트롤러의 역할 116 | * `angular.module().controller()` 함수로 컨트롤러 정의 117 | 118 | ```javascript 119 | // js/controllers/TodomvcCtrl.js: 120 | angular.module('todomvc') 121 | .controller('TodomvcCtrl', function ($scope) { 122 | $scope.message = 'Hello world!'; 123 | }); 124 | ``` 125 | 126 | * 컨트롤러스 생성과 동시에 스코프 변수(`$scope`)가 자동으로 생성됨 127 | * 이는 템플릿과 컨트롤러간의 연결을 위한 변수임 128 | * index.html에 스코프 변수 출력하기 (인터폴레이션) 129 | 130 | ```html 131 | 132 | 133 |

134 | {{ message }} 135 |

136 | 137 | 138 | ``` 139 | 140 | ## 투두 목록 출력하기 (ngRepeat) 141 | 142 | * 컨트롤러에 배열 데이터 `$scope.todos` 만들기 143 | 144 | ```javascript 145 | // js/controllers/TodomvcCtrl.js 146 | angular.module('todomvc') 147 | .controller('TodomvcCtrl', function ($scope) { 148 | $scope.todos = [{ 149 | id: 1, 150 | title: '요가 수행하기', 151 | completed: false 152 | }, { 153 | id: 2, 154 | title: '어머니 용돈 드리기', 155 | completed: true 156 | }]; 157 | }); 158 | ``` 159 | 160 | * `ngRepeat`으로 배열 출력하기 161 | 162 | ```html 163 | 164 | 171 | ``` 172 | 173 | ## 삭제 기능 만들기 (ngClick) 174 | 175 | * ngClick 디렉티브를 이용해 버튼의 클릭 이벤트 후킹 176 | 177 | ```html 178 | 179 | 180 | 181 | ``` 182 | 183 | * ngClick에 설정한 컨트롤러 함수를 이용해 이벤트 핸들러 구현 184 | 185 | 186 | ```javascript 187 | // js/controllers/TodomvcCtrl.js 188 | angular.module('todomvc') 189 | .controller('TodomvcCtrl', function ($scope) { 190 | $scope.remove = function (id) { 191 | if (!id) return; 192 | 193 | // 배열에서 제거할 인덱스를 검색 194 | var deleltedTodoIdx = $scope.todos.findIndex(function (todo) { 195 | return todo.id === id; 196 | }); 197 | 198 | if (deleltedTodoIdx === -1) return; 199 | 200 | // 배열에서 제거 201 | $scope.todos.splice(deleltedTodoIdx, 1); 202 | } 203 | 204 | }); 205 | ``` 206 | 207 | ## 새로운 투두 추가하기 (ngForm) 208 | 209 | * 앵귤러로 폼 작성하기 210 | * 폼에서 submit 이벤트 발생시 ngSubmit 디렉티브에 설정한 컨트롤러 함수가 동작하는 구조 211 | * 폼버튼을 만들고 ngSubmit에 컨트롤러 함수를 연결 212 | 213 | ```html 214 | 215 |
216 | 217 | 218 |
219 | ``` 220 | 221 | * ngSumbit에 연결된 컨트롤러 함수 구현 222 | 223 | ```javascript 224 | // js/controllers/TodomvcCtrl.js 225 | angular.module('todomvc') 226 | .controller('TodomvcCtrl', function ($scope) { 227 | $scope.addTodo = function (title) { 228 | title = title.trim(); 229 | if (!title) return; 230 | 231 | // 새로 추가할 아이디 계산 232 | var newId = !$scope.todos.length ? 233 | 1 : $scope.todos[$scope.todos.length - 1].id + 1; 234 | 235 | // 새로운 투두 객체 236 | var newTodo = { 237 | id: newId, 238 | title: title, 239 | completed: false 240 | }; 241 | 242 | // todos 배열에 새로운 투두 추가 243 | $scope.todos.push(newTodo); 244 | }; 245 | }); 246 | ``` 247 | 248 | ## 스타일 입히기 (Twitter Bootstrap) 249 | 250 | * [Twitter Bootstrap](http://getbootstrap.com)은 반응형웹, 모바일 웹을 위한 스타일시트 라이브러리 251 | * Npm으로 부트스트랩 설치 252 | 253 | ``` 254 | $ npm instsall bootstrap --save 255 | ``` 256 | * index.html에 라이브러리 로딩 257 | 258 | ```html 259 | 260 | 261 | ``` 262 | 263 | * 부트스트랩 클래스 적용하기 264 | 265 | ```html 266 | 267 | 268 | 269 | 270 | 271 | 273 | Angular | TodoMVC 274 | 276 | 277 | 278 |
279 |

Todos

280 | 281 | 294 | 295 | 308 |
309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | ``` 317 | 318 | ## 7. 투두 목록 필터링 319 | 320 | * 출력된 투두목록을 아래 기준으로 필터링해 보자 321 | * `completed`: 완료된 투두 리스트 322 | * `active`: 미완료된 투두 리스트 323 | * `all`: 모든 투두 리스트 324 | 325 | * `ngRepeat`의 필터링 기능 326 | * index.html: 327 | 328 | ```html 329 |