AngularJS를 이용한
Todo app 만들기
Day 1
Conceptual Overview
- Module
- Template
- Controller
- Scope
- Directive
- Service
- Filter
- Conceptual overview
- MVW
Dev Environment
- Angular v1.5
- Nodejs v6.x
- node, npm
- Atom editor
- Chrome browser
- Git
Hello world
- View와 Controller의 관계
- Data binding
- Expression
- ngApp, ngInit
- git checkout ngInit
- ngController
- angular.module()
- controller()
- $scope
- git checkout helloWorld
ECMAScript 6
- Block scope (let, const)
- Arrow function
- Template string
- Class (getter, setter)
- Promise
Block Scope
- var: function scope
- let: block scope, 가변
- const: block scope, 불변
function foo() {
if (false) {
var a = 1;
}
console.log(a);
}
foo(); // undefined
function bar() {
if (false) {
let a = 1;
}
console.log(a);
}
bar(); // Reference Error
function foo() {
var a;
if (false) {
a = 1;
}
console.log(a);
}
foo(); // undefeind
function bar() {
if (false) {
let a;
a = 1;
}
console.log(a);
}
bar(); // Reference Error
const a = 1;
a = 2;
// TypeError:
// Assignment to constant variable.
const b;
// SyntaxError:
// Missing initializer in const declaration
Arrow Function
- arrow function
- arguments 가 없음
- this 가 없음 (lexical this)
- 위 binding 작업이 없어 가벼움
var foo = function(param) {
return true;
}
const foo = (param) => {
return true;
}
const foo = param => true;
let arr = [1,2,3,4,5];
arr.map(m = n * n)
.filter(n => n % 2 === 0)
.reduce((r, n) => r + n); // [4, 16]
Template String
- 코드 가독성
- 성능?
const protocol = 'http';
const ip = '127.0.0.1';
const port= 3000;
const resource = 'user';
const id = '402';
let url;
url = protocol + '://' + ip + ':' + port + '/' + resource + '/' + id;
url = `${protocol}://${ip}:${port}/${resource}/${id}`
Class
- class
- getter, setter
Promise
- bluebird
- q
- Promise
const async1 = r => {
return new Promise(rev => {
setTimeout(() => {
rev(r)
}, 1000);
});
};
const async2 = r => Promise.resolve(r + 1);
const async3 = r => Promise.resolve(r + 2);
Promise.resolve(1)
.then(async1)
.then(async2)
.then(async3)
.then(console.log); // 4
Promise.all([
async1(1),
async2(1),
async3(1),
]).then(console.log); // [1, 2, 3]
Directives ...
- ngRepeat
- ngClick
- Data binding (1way, 2way)
- Function Components
ngRepeat
- 컬렉션으로부터 템플릿을 생성하는 내장 디렉티브
-
<div ng-repeat="model in collection | orderBy: 'id' |
filter: x | limitTo: limit
as results"> {{model.name}} </div>
ngClick
- 엘리멘트가 클릭되었을때 특정 행동을 정의하는 디렉티브
- <div ng-click="expression">...</div>
ngModel
- Data binding
- 1 way: ngBind, {{ }}
- 2 way: ngModel
Function Components
- angular.copy()
- angular.element()
- angular.isDate()
- digest loop (?)
git checkout directives
Make Directives!
- directive()
- <todo-item>
- <todo-form>
- <todo-filters>
- <todo-list>
directive()
- directive('todoItem', ()=> {
return {
restrict: 'EA',
scope: { ... },
template: `<div></div>`,
compile: (tElement, tAttrs) => { ... }
link: (scope, iElement, iAttrs) => { ... },
}; }); - git checkout todoItem
- git checkout todoForm
- git checkout todoFilters
Make Filters!
- filter()
- dateKo
- timeKo
filter()
-
filter('capitalize', () => {
return v => {
if (!v) return '';return v.charAt(0).toUpperCase() + v.slice(1);
};
}); -
$filter
-
git checkout filters
Day 2
Form
- style
- validate
- custom validator
- todo-text-validator
Validation
- 폼 객체의 $error
- todo-form directive 개선하기
- button
- warning messages
- git checkout ngForm
Style
- ngForm
- ng-minlength, ng-maxlength
- ng-pristine, ng-dirty, ng-valid, ng-invalid ...
- 클래스 오버라이딩
Custom Validator
- 검증자도 일종의 directive
- require: 'ngModel'
- modelCtrl
- git checkout todoTextValidator
directive('todoTextValidator', () => {
return {
restrict: 'A',
require: 'ngModel',
link: (scope, elem, attrs, modelCtrl) => {
modelCtrl.$validators.todoText = (modelValue, viewValue) => {
if (viewValue) return /^(:\w+\s)/.test(viewValue);
}
}
};
});
SPA
- hashbang, html5 mode
- ngRoute
- lite-server
ngRoute
-
ngRoute
- ngView
- $routeProvidor
- $routeParams
- $localtion.html5Mode()
- git checkout ngRoute
Single Page App.
- 브라우져는 하나의 html을 요청
- 라우팅을 자바스크립트로 처리 (페이지 리프레시 불필요)
-
hashbang
- https://twitter.com/#!/JeonghwanKim4
- fragment identifier
-
html5 history api
- window.pushState()
- 단점: 자바스크립트 깨지면? 크롤러는?
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<ul>
<li><a href="africa">Africa</a></li>
<li><a href="asia">Asia</a></li>
<li><a href="europe">Europe</a></li>
<li><a href="north-america">North America</a></li>
<li><a href="oceania">Oceania</a></li>
<li><a href="south-america">South America</a></li>
</ul>
<div id="content"></div>
<script type="text/javascript" src="app.js"></script>
</body>
</html>
const load = country => {
document.getElementById('content').innerHTML = `${country} is loaded`
document.title = country;
};
window.addEventListener('click', e => {
e.preventDefault();
const country = e.target.text;
history.pushState({country: country}, `title: ${country}`, country);
load(country);
});
window.addEventListener('popstate', evt => {
var state = evt.state;
if (state !== null) load(state.country)
});
lite-server
- cors (in chrome)
- broken links (in safari, firefox)
- all request → index.html
- git ckeckout lite-server
Service
- 어플리케이션의 공유 로직, 싱글톤, DI
- provider(), factory(), serivce()
- todoStorage
- localStorage
서비스 만드는 방법
- provider()
- factory()
- service()
- constant()
- value()
- decorator()
- 앵귤러 내부 코드
factory('myService', function() {
var intstant = {
users: ['Alice', 'Bek', 'Chris']
};
return intstant;
});
factory('myService', function() {
this.users = ['Alice', 'Bek', 'Chris'];
});
todoStorage
- 컨트롤러에서 모델을 서비스로 분리
- git checkout todoStorage
localStorage
- localStoreage
- 브라우져의 key/value 저장소
- localStorage.setItem()
- localSotrage.getItem()
- 모두 문자열로 처리함
- todoStorage와 localStorage 연동
- update?
- git checkout localStorage
Asynchronouse
- Callback style
- Promise
- $q
- $http
Callback
- Callback style
- Callback hell
- 주도권이 없다
Promise
- 비동기의 주도권을 획득
- thanble
- bluebird, q, Promise (es6)
$q
- $q
- $q.defer
Day 3
Backend
- generator-weplajs
- GET /todos
- POST /todos
- PUT /todos
- DELETE /todos
Ajax
- $http
- todoService 개선
$http
- https://docs.angularjs.org/api/ng/service/$http
- $http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
}, function errorCallback(response) {
}); - $http.get
$http.post
$http.put
$http.delete
$httpProvider.interceptors
$provide.factory('myHttpInterceptor', function() {
return {
'request': function(config) {return config;},
'requestError': function(rejection) {
return $q.reject(rejection);
},
'response': function(response) {return response;},
'responseError': function(rejection) {
return $q.reject(rejection);
}
};});
$httpProvider.interceptors.push('myHttpInterceptor');
todoService 개선
angular.module('todomvc')
.factory('todoStorage', ($http) => {
const storage = {
data: [],
get() {
$http.get('http://localhost:3002/v1/todos')
.then(result => angular.copy(result.data, this.data))
.catch(err => console.error(err));
return this.data;
},
create(title) {
$http.post('http://localhost:3002/v1/todos', {title: title, done: false})
.then(result => this.data.push(result.data))
.catch(err => console.error(err));
},
destory(todo) {
$http.delete(`http://localhost:3002/v1/todos/${todo.id}`)
.then(result => angular.copy(this.data.filter(t => t.id !== todo.id), this.data))
.catch(err => console.error(err));
},
update(todo) {
const reqBody = {title: todo.title, done: todo.done};
$http.put(`http://localhost:3002/v1/todos/${todo.id}`, reqBody)
.then(result => undefined)
.catch(err => console.error(err));
}
};
return storage;
});
Authentication
- https://docs.google.com/presentation/d/1C9hbGHLuCfKSFcneCnKNDbaZCXTqZmlImQ62vF1aE_Q/edit?usp=sharing
- APIs
- POST /auth
- DELETE /auth
- POST /users
Login
- template
- controller
- angular-cookies
- authInterceptor
- redirection
Logout
- template
- MenuCtrl
- auth.service
Register
- template
- RegisterCtrl
- user.service
Angular2
Copy of AngularJS를 이용한 Todo app 만들기 (엔컴)
By BYUN Kyuhyun
Copy of AngularJS를 이용한 Todo app 만들기 (엔컴)
엔컴 사내 강의용 발표자료입니다
- 520