프론트엔드 웹앱 프레임웍 - bootstrap, backbone 그리고 angularjs
DESCRIPTION
K모바일 주관 WebMobileDevCon 2013 발표자료. http://www.kmobile.co.kr/k_conedu/Conference/Con_gProgram.asp?id=1140TRANSCRIPT
프론트엔드 웹앱 프레임웍Dongsu, Jang <iolothebard at gmail dot com>
차례
•Prologue
•Bootstrap
•Backbone.js
•AngularJS
•Demo
•Epilogue
Prologue
이미지 출처: http://www.hd-desk.com/spider_web_wallpapers/spider_web_wallpapers_1280_960.html
홈페이지?
웹 사이트?
웹 서비스?
웹 애플리케이션?
웹앱?
이미지 출처: http://funnypictures00.blogspot.com/2012/02/beautiful-road-pictures-and-wallpapers.html
웹의 역사
텍스트
출처: http://www.evolutionoftheweb.com
웹 프레임웍의 역사
2006200520042003200220012000
Struts 1.0
201220112010200920082007
Tapestry 2.1 JSF 1.0
Spring 1.0Grails 1.0
Flex 1.0
TurboGears 1.0
Servlet 2.2
Becomes part of J2EE 1.2 (JDK 1.2)
Servlet 2.3
Servlet 2.4
Struts 2.0
GWT 1.0
Tomcat 3.0.x (initial release)
Spring 3.0
JSF 2.0
Rails 2.0 Flex 3.0
Django 1.0
1999
AJAX term coined
Lift 1.0
GWT 2.0
Stripes 1.0
jQuery 1.0
Wicket 1.0WebWork 1.0
Closure Tools
CometD 1.0
ASP 3.0
ASP.NET 1.0
Symfony 1.0
Dojo 1.0
Zope 3Tapestry
4.0
CakePHP 1.0
Opera 4.0
IE 6.0
Play 1.0
Flask 0.9
Play 2.0
Express 1.0
Sinatra 1.0
2013
Backbone.js 0.1
Sproute Core 1.0
Emberjs1.0 RC
AngularJS1.0
jQueryMobile 1.0
EXT 4.0
jQuery2.0??
Sencha Touch 1.0
출처: http://www.flickr.com/photos/mraible/4378559350/
웹 개발의 역사홈페이지
HTML저작도구
정적 콘텐츠읽기
웹 사이트
CGI &서버 페이지
동적 콘텐츠쓰기
웹 서비스
MVC 서버프레임웍
+AJAX툴킷
기능성개발 생산성
웹 앱
경량 서버프레임웍
+프론트엔드프레임웍
실시간상호작용
프론트엔드 중심 웹앱시스템 아키텍쳐
웹앱
RESTfulAPI����������� ������������������ 서버
백엔드
모바일����������� ������������������ 앱
데이터베이스
정적웹����������� ������������������ 서버
정적컨텐츠
프론트엔드프레임웍
경량����������� ������������������ 서버프레임웍
HTTP
Java클라이언트
Objective-C클라이언트
Javascript클라이언트
애플리케이션서버
백오피스
JSON/HTTP
캐시
프론트엔드 웹앱요소 기술 스택
런타임(플랫폼) 웹브라우져
런타임 라이브러리 DOM, BOM, HTML5 JS API, W3C Web Apps WG API, ...
GUI 서브시스템 HTML5, CSS3, Canvas, WebGL, SVG, ...
I/O 서브시스템 HTTP, AJAX, 웹스토리지, IndexDB, 웹소켓, WebRTC, ...
프로그래밍언어 JavaScript, CoffeeScript, TypeScript, ...Objective-J, ...
Bootstrap
이미지 출처: http://www.inc.com/laura-smoliar/should-you-bootstrap.html
Bootstrap 개요
Bootstrap 개요
•CSS 초기화 & 기본 스타일
•12열 격자 시스템 : 고정 / 유동 레이아웃
•반응형 디자인
•"코딩이 필요없는" UI 컴포넌트
•"코딩이 필요한" UI 컴포넌트
•웹 기반 커스터마이징 도구
•Super-powered by Twitter
부트스트랩 적용하기<!DOCTYPE html><meta name=”viewport” content=” width=device-width,initial-scale=1.0” /><link rel=”stylesheet” href=”bootstrap.css” /><link rel=”styleheet” href=”bootstrap-responsive.min.ss” /><!--[if lt IE 9]><script src=”html5shiv.js”></script><![endif]--><script src=”jquery.min.js”></script><script src=”bootstrap.min.js”></script>
CSS Reset & 기본 스타일
•브라우저의 기본 스타일 차이 최소화
•Nomalize.css by Nicolas Gallagher
•http://necolas.github.com/normalize.css/
•(더 나쁘지 않은) 기본 스타일
•HTML5 필수: <?DOCTYPE html>
•IE8 이전 버전: html5shiv 등의 polyfill 필요
12열 격자 시스템고정 레이아웃
•전체 너비: 940px "고정"
•.container
•.row
•.span1 ~ 12 / .offset1 ~ 12
•열의 너비 + 간격
•60px + 20px "고정"
•@gridColumnWidth, @gridGutterWidth
•중첩된 열의 span 합계 <= 부모 열의 span
고정 레이아웃예제 123 9
9
9
http://tomato.iolo.kr:3000/bootstrap/layout-fixed.html
12열 격자 시스템유동 레이아웃
•전체 너비: 724px ~ 1140px "유동"
•.container-fluid
•.row-fluid
•.span1 ~ 12 / .offset1 ~ 12
•열의 너비 + 간격
•6.382978723% + 2.127659574% "유동"
•@fluidGridColumnWidth, @fluidGridGutterWidth
•중첩된 열의 span 합계 <= 12
유동 레이아웃예제 123 9
4
12
http://tomato.iolo.kr:3000/bootstrap/layout-fluid.html
반응형 디자인• 폰: .visible-phone, .hidden-phone
• 폰(세로): ~ 480px
• 폰(가로) ~ 태블릿(세로): ~780px
• 열의 너비 + 간격: "유동"
• 태블릿: .visible-tablet, .hidden-tablet
• 태블릿(세로) ~ 태블릿(가로): ~768~980px
• 열의 너비 + 간격: 40px + 20px "고정"
• 데스크탑: .visible-desktop, .hidden-desktop
• 태블릿(가로) ~ 데스크탑(기본): 980px~1200px
• 열의 너비 + 간격: 60px + 20px "고정"
• 고해상도: 1200px~
• 열의 너비 + 간격: 70px + 30px "고정"
반응형 디자인
480 768 980 1200
태블릿(세로) 데스크탑 고해상도
폰(가로)
폰(세로)
태블릿(가로)
% 42+20 60+20 70+30%
.visible-phone .visible-tablet .visible-desktop
반응형 디자인예제
http://tomato.iolo.kr:3000/bootstrap/layout-fixed-responsive.html
http://tomato.iolo.kr:3000/bootstrap/layout-fluid-responsive.html
반응형 디자인 - 데모
출처: http://www.gotfocussolutions.com/
기본 스타일• (거의 모든) 태그의 기본 스타일 재정의
• 특정 태그용 CSS 클래스
• .table, .form, .btn, .dl-horizontal, .unstyled, ...
• 태그와 무관한 CSS 클래스:
• .info, .success, .warn, .error, .muted, ...
• .disabled, .active, ...
• 유틸리티 CSS 클래스
• .text-left, .text-center, .text-right
• .pull-left, .pull-right, .clearfix, ...
• 태그의 구성과 CSS 클래스의 조합: "UI 컴포넌트"
기본 스타일예제
http://tomato.iolo.kr:3000/bootstrap/base-table.html
http://tomato.iolo.kr:3000/bootstrap/base-form.html
http://tomato.iolo.kr:3000/bootstrap/base-misc.html
기본 스타일 - Glyphicons•Powered by
•<i class="icon-glass"></i>
•<i class="icon-glass icon-white"></i>
Glyphicons & Font-Awesom예제
http://tomato.iolo.kr:3000/bootstrap/base-icon.html
코딩이 필요없는UI 컴포넌트
•Dropdowns
•Button Groups
•Button Dropdowns
•Navs
•Navbar
•Breadcrumbs
•Pagination
•Label & Badges
•Typhography
•Thumbnails
•Alerts
•Progress bars
•Media object
•...
코딩이 필요한UI 컴포넌트
•Transition
•Modal
•Dropdown
•Scrollspy
•Tab
•Tooltip
•Popover
•Alert
•Button
•Collapse
•Carousel
•Typeahead
•Affix
•...
UI 컴포넌트예제
http://tomato.iolo.kr:3000/bootstrap/comp-dropdowns.html
http://tomato.iolo.kr:3000/bootstrap/comp-navs.html
http://twitter.github.com/bootstrap/components.htmlhttp://twitter.github.com/bootstrap/javascript.html
&http://tomato.iolo.kr:3000/bootstrap/comp-alert.html
커스터마이징•웹 기반 커스터마이징 도구
•http://twitter.github.com/bootstrap/customize.html
•사용할 컴포넌트 & jQuery 플러그인 선택
•글꼴, 색, 메트릭 설정
•최적화된 빌드 다운로드
•더 복잡한 커스터마이징을 하려면:
•소스 코드: https://github.com/twitter/bootstrap
•LESS: http://lesscss.org
• jQuery & jQuery UI
커스텀 테마데모
http://bootswatch.com/
https://wrapbootstrap.com
추천 사이트• 한글 번역: http://webdesigncss3.com/bootstrap/
• 적용 사례: http://builtwithbootstrap.com
• 테마(무료): http://bootswatch.com
• 테마(유료): https://wrapbootstrap.com
• 테마(유료): http://themeforest.net/search?term=bootstrap
• 테마(유료): http://www.templatemonster.com/properties/features/bootstrap-templates/
• 테마 제작 도구: http://stylebootstrap.info
• 실용 예제 및 폼 제작 도구: http://bootsnipp.com
• jQuery UI 컴포넌트: http://addyosmani.github.com/jquery-ui-bootstrap/
• AngularJS 지원: http://angular-ui.github.com
• 아이콘 웹폰트: http://fortawesome.github.com/Font-Awesome/
• CDN: http://www.bootstrapcdn.com/
부트스트랩의 대체품들•Foundation: http://foundation.zurb.com
•Skeleton: http://www.getskeleton.com
•HTML KickStart: http://www.99lime.com
•HTML5 Boilerplate: http://html5boilerplate.com
•Initializr: http://www.initializr.com
•Blueprint: http://blueprintcss.org
•참고: http://www.smashingapps.com/2012/12/26/16-useful-responsive-css-frameworks-and-boilerplates.html
Twitter Bootstrap 요약•예쁘다!
•쉽다!
•유연하다!
•남들도 많이 쓴다!!!
•Super-Powered by Twitter
•Super-Powered by Designer / Developer Communities
Backbone.js
이미지 출처: http://www.rareresource.com/Blogs/labels/Dinosaur%20unit.html
Backbone.js 개요
Backbone.js 개요
•Events
•Model & Collection
•View
•Router
•History
•Underscore.js
Backbone.Events•on(event, callback, context)
== bind
•off(event, callback, context) == unbind
•once(event, callback, context)
•trigger(event, args...)
•listenTo(target, event, callback)== target.on(event, callback, this)
•stopListening(target, event, callback)== target.off(event, callback, this)
Backbone.js이벤트
•공통•all•Model•change(model, options)•change:attribute(model,
value, options)• invalid(model, error,
options)•sync(model, response,
options)•request(model, xhr,
options)•error(model, xhr,
options)
•Collection•add(model, collection,
options)•remove(model,
collection, options)•reset(collection,
options)•sort(collection, options)•destroy(model,
collection, options)•Router•route:name(params)•route(router, route,
params)
Backbone.Model
•엔티티 모델 + DAO
•엔티티 속성은 해시 객체
•모델 변경에 따른 이벤트 발생
•저장소와 동기화 with Backbone.sync
•기본 동기화 방식은 RESTful HTTP(with jQuery.ajax)
Backbone.ModelAPI
•extend•constructor /
initialize•get•set•escape•has•unset•clear•id•idAttribute
•cid•attributes•changed•defaults•toJSON•sync•fetch•save•destroy•validate•validationError
•url•urlRoot•parse•clone•isNew•hasChanged•changed
Attributes•previous•previous
Attributes
Backbone.Model 예제
var Item = Backbone.Model.extend({ urlRoot: '/todos'});
var item = new Item({ title: 'Backbone 예제 만들기'});
// HTTP POST 요청 --> 'sync' 이벤트 발생item.save();
// cf. 동기 처리item.save(null, {wait:true});
// cf. 콜백 처리item.save(null, { success: function (model) { }, error: function (model) { ... }});
Backbone.Model 예제
var item = new Item({ id: 1 });
// HTTP GET 요청 --> 'sync' 이벤트 발생item.fetch();
// 'change' & 'change:title' 이벤트 발생item.set({title:'Backbone 발표자료/예제 만들기'});
// HTTP PUT 요청 --> 'sync' 이벤트 발생item.save();
// HTTP DELETE 요청 --> 'sync' 이벤트 발생item.destroy();
// cf. 이벤트 처리item.on('change', function(model) { ... });item.on('sync', function (model) { ... });
Backbone.Collection•"Model"의 집합 + DAO
•목록 변경에 따른 이벤트 발생
•풍부한 순회 함수with Underscore.js
•저장소와 동기화 with Backbone.sync
•기본 동기화 방식은 RESTful HTTP(with jQuery.ajax)
Backbone.CollectionAPI
•extend•model•constructor /
initialize•models•toJSON•sync•add•remove•reset
•update•get•at•push•pop•unshift•shift•slice•length•comparator
•sort•pluck•where•url•parse•clone•fetch•create•28 Underscore
Methods...
Backbone.Collection 예제
var Items = Backbone.Collection.extend({ model: Item, url: '/todos'});
var items = new Items();
// HTTP 요청없이 초기화 --> 'reset' 이벤트 발생// 서버 사이드 템플릿에서 사용:// ex. items.reset(<%= @items.to_json %>);items.reset([ {id:123, title: 'first'}, {id:456, title: 'second'}, {id:789, title: 'third'}]);
// HTTP GET 요청 --> 'reset' 이벤트 발생items.fetch();
var item = items.get(123); // by idvar item = items.at(9); // by index
Backbone.Collection 예제
// HTTP POST 요청 --> 'add' 이벤트 발생var item = items.create({title: 'Bootstrap 예제 만들기'});
// HTTP POST 요청 --> 'add' 이벤트 발생items.add({title: 'AngulaJS 예제 만들기'});
// HTTP POST, PUT, DELETE 요청// --> 'add', 'remove', 'change'등의 해당하는 이벤트 발생items.update(item);items.update([ item1, model2, model3 ]);
// HTT DELETE 요청 --> 'remove' 이벤트 발생items.remove(item); // by modelitems.remove(123); // by iditems.remove([123, 456, 789]); // by iditems.remove([item1, item2, item3]); // by model
Backbone.View
•"Presenter" in MVP
•모델 / 컬렉션 조작 & 이벤트 처리
•DOM 조작 & 이벤트 처리
•템플릿 처리(선택 사항)
•완전 수동! MANUAL!!
Backbone.ViewAPI
• extend
• constructor / initialize
• el
• $el
• setElement
• attributes
• render
• remove
• delegateEvents
• undelegateEvents
• $
Backbone.View 예제
var ItemView = Backbone.View.extend({ tagName: 'li', events: { 'click button.update': 'doUpdate', 'click button.delete': 'destroy', }, initialize: function () { this.listenTo(this.model, 'change', this.render); }, render: function () { this.$el.html(this.model.get('title')); return this; }, doUpdate: function (event) { this.model.set({title: this.$('input.title').val()}); }});
Backbone.View예제
var ListView = Backbone.View.extend({ el: $('#items'), initialize: function () { this.listenTo(this.items, 'reset', this.render); this.items.fetch(); }, render: function () { this.items.each(this.addItem, this); return this; }, addItem: function (item) { var itemView = new ItemView({model:item}); this.$el.append(itemView.render().el); }});
new ListView({items: new Items()});
Template• 기본 템플릿 엔진: Underscore.js 템플릿
• "ejs"와 유사한 초경량 템플릿 엔진
• 컴파일된탬플릿함수 = _.template(템플릿소스문자열)
• 템플릿처리된문자열 = 컴파일된탬플릿함수(뷰모델)
• <%= unescaped %>
• <%- escaped %>
• <% script %>
• 참고: http://underscorejs.org/#template
• 권장 템플릿 엔진
• Mustache: http://mustache.github.com
• HAML-JS: https://github.com/creationix/haml-js
• Eco(Embedded CoffeeScript): https://github.com/sstephenson/eco
Template예제
<script type="text/template" id="item-template"> <li> <input type="text" class="title" value="<%= title %>"> <button class="save">Save</button> <button class="delete">Delete</button> </li></script>
var ItemView = Backbone.View.extend({ ... template: _.template($('#item-template'), //템플릿 초기화(컴파일) render: function () { var s = this.template(this.model.toJSON()); //템플릿 처리(렌더링) this.$el.html(s); return this; } ...});
Backbone.RouterAPI
•extend
•routes
•constructor / initialize
•route
•navigate
Backbone.historyAPI
•Backbone.history.start([options])
•options
•hashChange: location.hash / onhashchange 이벤트 사용(기본값: true)
•pushState: HTML5 history.pushState / popState 사용(기본값: false)
•root: 웹앱의 기본 URL(기본값: '/')
•slient: 최초 시작시 기본 라우팅 안함(기본값: false)
Backbone.Router & History예제
var AppRouter = Backbone.Router.extend({ routes: { '': 'loadItems' '/add': 'addItem', '/show/:id': 'showItem', '/edit/:id': 'editItem' }, loadItems: function () { ... }, addItem: function () { ... }, showItem: function (id) { ... }, editItem: function (id) { ... }});
var appRouter = new AppRouter();
Backbone.history.start();
appRouter.navigate('/add', true);
Backbone.sync()API
• Backbone.sync(method, model, [options])• method• create: POST /collection• read: GET /collection[/id]• update: PUT /collection/id• delete: DELETE /collection/id• options• success, error 콜백을 포함한 jQuery.ajax의 모든 요청 options• 요청 시작시 'request', 요청 성공시 'sync' : 요청 실패시 'error' 이벤트 발생• 저장소 플러그인• 브라우저 로컬 스토리지: https://github.com/jeromegn/
Backbone.localStorage• CouchDB: https://github.com/pyronicide/backbone.couchdb.js• Socket.io: https://github.com/logicalparadox/backbone.iobind• ...
Backbone.jsMVC(?)
템플릿
View
Model / Collection
저장소
DOM
모델 변경 & 이벤트 처리
저장소와 동기화
UI 갱신
사용자 입력& 이벤트 처리
Router
UI 선택
시작
기타•Backbone.emulateHTTP = true
•PUT / DELETE 요청 메소드 대신, POST 요청 메소드 & X-HTTP-Method-Override 요청 헤더 & _method 쿼리 파라메터 사용
•Backbone.emulateJSON = true
•application/json 요청 컨텐츠 타입 대신, application/x-www-form-urlencoded 사용.
•Backbone.noConflict
•Backbone.ajax == jQuery.ajax
•Backbone.$ == jQuery
추천 사이트• Backbone의 Backbone, Underscore.js: http://underscorejs.org
• 튜토리얼 모음: http://backbonetutorials.com
• 웹 스토리지 저장소 플러그인: https://github.com/jeromegn/Backbone.localStorage
• 관계형 모델 지원 플러그인: http://backbonerelational.org
• 페이지 지원 콜렉션 플러그인 https://github.com/wyuenho/backbone-pageable
• 폼 생성 / 바인딩 플러그인: https://github.com/powmedia/backbone-forms
• Mustache 템플릿 엔진: http://mustache.github.com
• Bootstrap 기반 그리드 컴포넌트: http://direct-fuel-injection.github.com/bbGrid/
• Backbone.js 기반 프로젝트 시드: https://github.com/tbranyen/backbone-boilerplate
• Backbone.js 기반 Full-Featured MVC 프레임웍: http://chaplinjs.org
Backbone.js 요약•MVC, MVP, MVVM
•작다!
•가볍다!
•해주는 게 없다!! 손발이 고생~
•그래서, 어디에 끼워 넣어도 어울린다!!!
•Powered by DocumentCloud
•Super-Powered by Developer Communities
AngularJS
이미지 출처: http://www.wallpaper-for-desktop.net/wallpapers/modern-cubism-wallpaper-gallery-desktop-265751.html
AngularJS 개요
AngularJS 개요
•Module & Dependency Injection
•Scope
•Model & Data Binding
•VIew
•Controller
•Expression & Directives & Filters
•Super-Powered by Google
AngularJS 적용하기자동 초기화
<!DOCTYPE html><html ng-app>...<body> ... <script src="angular.js"></script></body></html>
AngularJS 적용하기수동 초기화
<!DOCTYPE html><html>...<body> ... <script src="angular.js"></script> <script> angular.element(document).ready(function () { angular.bootstrap(document); }); </script></body></html>
AngularJS 웹앱디렉토리 구조(권장)
• AngularJS Seed 프로젝트: https://github.com/angular/angular-seed• app/ --> 웹을 통해 서비스되는 파일들• css/ --> CSS 파일들• img/ --> 이미지 파일들
• js/ --> 자바스크립트 파일들• app.js --> 웹앱 메인 모듈• controllers.js --> 컨트롤러 모듈• directives.js --> 지시자 모듈• filters.js --> 필터 모듈
• services.js --> 기타 서비스 모듈• lib/ --> 써드파티 라이브러리 파일들• angular/ --> AngulaJS 라이브러리 파일들
• partials/ --> View 템플릿 파일들
• index.html --> 레이아웃 템플릿 파일• ... --> 테스트 라이브러리, 설정 파일, 스크립트 등
모듈•모듈(module)은 컨트롤러(controller), 서비스(service), 지시
자(directive), 필터(filter) 등의 "컨테이너/패키지/빌더팩토리"
•HTML 페이지는 하나의 모듈(앱 모듈)과 결함
•ng-app 지시자, angular.bootstrap() API, 의존성 주입
•웹앱의 모듈 구성(권장)
•서비스 모듈
•지시자 모듈
•필터 모듈
•앱 모듈: 초기화 코드 등
모듈API
• angular.module(name, requires[, configFn])• .config(configFn)• .run(initializerFn))• .constant(name, obj)• .value(name, value)• .controller(name, constructor)• .service(name, constructor)• .directive(name, directoryFactory)• .filter(name, filterFactory)• .factory(name, providerFn)• .provider(name, providerType)• config(), run()을 제외한 함수는 다른 제공자 API를 호출하는 편의 함수
모듈예제
angular.module('services',[ 'controllers' ])// 모듈 설정 --> 제공자만 주입 가능.config(['$routeProvider', function ($routeProvider) { $routeProvider.when('/items', { templateUrl: 'partials/items.html', controller: 'itemListCtrl' }); ...}])// 모듈 초기화.run(['$rootScope', function ($rootScope) { $rootScope.on('error', function (err) { ... }); ...}]);// 서비스 정의.factory('apiService', [ '$http', function ($http) { return { loadItems: function(callback) { ... callback(items); }, saveItem: function(item) { ... }, deleteItem: function(item) { ... }, };}]);
의존성 주입•Dependency Injection(DI)는 코드 간의 의존성을 해결하기 위
한 소프트웨어 디자인 패턴
•http://en.wikipedia.org/wiki/Dependency_injection
•http://martinfowler.com/articles/injection.html
•angular.injector API
•annotate(injectingFunc)
•get(name)
•instantiate(constructorFunc, locals)
•invoke(func, self, locals)
의존성 주입예제
// 의존성 자동 주입angular.module('app', [ 'services' ]).run([ '$rootScope', 'apiService', function (root, api) { api.loadItems(function (items) { root.items = items; }); }]);
// 의존성 수동 해결(!)var injector = angular.injector(['services', 'ng']);var $rootScope = injector.get('$rootScope'); // from 'ng' 모듈var apiService = injector.get('apiService'); // from 'services' 모듈apiService.loadItems(function (items) { $rootScope.items = items;});
Scope• "모델" or "모델"의 컨테이너
• 표현식(expression)의 실행 문맥(execution context)
• 계층 구조
• 자식 Scope는 부모 Scope의 속성을 상속(mixin)
• 컨트롤러와 일부 지시자들은 자식 Scope를 생성
• 최상위 Scope: $rootScope
• Scope 이벤트는 상위 Scope로 전파: $emit()
• Scope 이벤트는 하위 Scope로 전파: $broadcast()
• Scope는 DOM 노드와 결합: angular.element(aDomElement).scope()
• 모델 변화를 감시: $watch()
• AngularJS 외부에서 발생한 모델 변화를 내부에 전달: $apply()
ScopeAPI
•$apply(expr)
•$broadcast(name, args...)
•$destroy()
•$digest()
•$emit(name, args...)
•$eval(expr)
•$evalAsync(expr)
•$new(isolate)
•$on(name, listener)
•$watch(expr, listener, equality)
•$id 속성
•$destroy 이벤트
Scope예제
angular.module('app', [ ]).config(['$httpProvider', function ($httpProvider) { $httpProvider.responseInterceptors.push(['$q', '$rootScope', function ($q, $rootScope) { $rootScope.pendingHttpRequests = 0; return function (promise) { $rootScope.pendingHttpRequests += 1; return promise.then(function (res) { $rootScope.pendingHttpRequests -= 1; return res; }).fail(function (res) { $rootScope.pendingHttpRequests -= 1; $rootScope.$broadcast('httpError', res.data); return $q.reject(res); }); }; }]);}]);
Scope예제
// 다른 모듈에서 $rootScope에서 발생한 이벤트 감시angular.module('errorLogger', []).run(['$rootScope', function ($rootScope) { $rootScope.on('httpError', function(event, error) { console.error('http error: ', error); });}]);
// 다른 모듈에서 상위 Scope($rootScope)에서 상속한 속성 감시angular.module('controllers', []).controller('itemEditCtrl', ['$rootScope', '$scope', function ($rootScope, $scope) { $rootScope.$watch('pendingHttpRequests', function(old, new)) { $scope.submitDisabled = (new > 3); });}]);
// 뷰 템플릿에서 상위 Scope($rootScope)에서 상속한 속성 참조<div ng-show="pendingHttpRequests">loading...</div>
컨트롤러• 컨트롤러는 하나의 Scope와 결합
• ng-controller 지시자, $route 서비스 또는 scope.$new() API
• 컨트롤러의 역할
• Scope 초기화
• Scope에 행위(behavior; 이벤트 핸들러) 추가
• 컨트롤러에서 하면 안되는 것들(권장)
• DOM 조작 --> 지시자 사용
• 입력 포매팅 --> Form Control 지시자 사용
• 출력 필터링 --> 필터 사용
• 다른 컨트롤러 접근 --> 서비스 사용
• 다른 컴포넌트의 생성 및 라이프 사이클 관리
컨트롤러예제
// 쉬운 방법// --> 파라메터의 "이름"을 통해서 의존성 자동 주입function ItemListCtrl($scope, $location, apiService) { apiService.loadItems(function (items) { $scope.items = items; });
$scope.editItem = function (item) { $location.path('/items/' + item.id + '/edit'); };
$scope.deleteItem = function (item) { apiService.deleteItem(item); };}
// 어노테이션을 이용한 명시적 의존성 주입// --> 자바스크립트 난잡화(UglyfyJS같은) 적용할 경우에는 필수ItemListCtrl.$inject = ['$scope', '$location', 'apiService'];
컨트롤러예제
// 좀 더 복잡하지만 뽀대나는 방법angular.module('controllers', [ ]).controller('itemListCtrl', [ '$scope', '$location', 'apiService', function($scope, $location, apiService) { apiService.loadItems(function (items) { $scope.items = items; });
$scope.editItem = function (item) { $location.path('/items/' + item.id + '/edit'); };
$scope.deleteItem = function (item) { apiService.deleteItem(item); }; }]);
뷰 & 템플릿• 결합된 Scope 및 상위 Scope들의 속성을 포함한 자바스크립트와 유사한 표현식
• {{ 표현식 }}
• 예) {{ title }}, {{ item.length }}, {{ 1 + 2 }}, {{ 'HelloWorld'.substring(5) }}
• 필터
• {{ 속성 | 필터 }}
• 예: {{ title | uppercase }}
• {{ 속성 | 필터:옵션 }}
• 예: {{ created | date:'yyyy-MM-dd HH:mm:ss Z' }}
• {{ 속성 | 필터1 | 필터2 | 필터3 }}
• 예: <li ng-repeat="item in items | filter:searchText | orderBy:created">
뷰 & 템플릿• 지시자
• 속성 형식
• ng-지시자, ng:지시자, ng_지시자, data-ng-지시자, x-ng-지시자
• 예: <input ng-model="title"/> <input ng_model="title"/> <input ng:model="title"/> <input data-ng-model="title"/> <input x-ng-model="title"/>
• 클래스 속성 형식
• class="ng-지시자", class="ng-지시자:옵션"
• 예: <input class="ng-model:title" />
• 태그 형식: IE8 이전 버전에서는 htmlshiv등의 polyfill이 필요
• 예: <ng-view>...</ng-view>
뷰 & 템플릿 예제
<html ng-app="app">...<body ng-controller="mainCtrl">
<header> <div ng-include="'common-header.html'"></div>
<div ng-show="currentUser"> <p>Welcome, {{currentUser.userame}}!</p> <button ng-click="logout()">Logout</login> </div>
<div ng-hide="currentUser" ng-controller="loginCtrl"> <input type="text" ng-model="username" /> <input type="password" ng-model="password" /> <button ng-click="login()">Login</login> <a href="#/signup">Sign Up!</a> </div> </header>...
뷰 & 템플릿 예제
<div ng-controller="itemListCtrl"> <p>There're {{items.length}} items</p> <ul> <li ng-repeat="item in items"> <p>{{title}}</p> <p>posted at {{created | date:'medium'}}</p> <a href="#/item/{{id}}/edit">Edit</a> <button ng-click="delete(item)">Delete</button> </li> </ul> </div>
<div ng-controller="itemAddCtrl"> <form ng-submit="addItem()"> <input type="text" ng-model="newItem.title" /> <button type="submit">Add</button> </form> </div>...
AngularJS의 MVC
<html ng-app>
<div ng-controller="ItemListCtrl"><ul><li ng-repeat="item in items>
</li></ul></div>
{{item.title}}<button ng-click="delete(item)">Delete</button>
function ItemListCtrl($scope) { $scope.items = [ {id:1, title:'first'}, {id:2, title:'second'}, {id:3, title:'third'} ];
$scope.delete=function(item) { delete $scope.items[item.id]; };}
$rootScope ng-repeat ScopeItemListCtrl Scope
items
delete()
id
title
라우팅• "앱 모듈"의 설정 단계에서, $routeProvider의 API를 통해 설정
• $routeProvider.when(path, route)
• path: 라우팅 경로. URL 해시(#)
• 경로 내에 :name 형식의 파라메터가 포함되면 $routeParams 서비스를 통해 전달.
• route: 라우팅 설정
• templateUrl: 템플릿 경로. ng-view 지시자가 사용.
• template: 템플릿 문자열.
• controller: 컨트롤러(서비스 ID 또는 생성자). $route, $routeParams 서비스를 주입할 수 있음.
• redirectTo: 리디텍트 경로(또는 경로를 리턴하는 함수)
• $routeProvider.otherwise(path): 기본 라우팅 경로
라우팅예제
angular.module('app', [ 'controllers' ]).config('$routeProvider', function(routes) { routes .when('/items/new', {templateUrl:'form.html', controller:'formCtrl'}) .when('/items', {templateUrl:'list.html', controller: 'listCtrl'}) .when('/items/:id/edit', {templateUrl:'form.html', controller: 'formCtrl'}) .when('/items/:id', { templateUrl: 'show.html', controller: 'showCtrl'}) .otherwise('/items');});
angular.module('controllers', []).controller('itemFormCtrl',[$scope, $routeParams, $http, function(scope, params, http) { if (params.id) { http.get('/api/items/' + params.id).then(function (res) { scope.item = res.data; scope.title = 'Edit Item'; }); } else { scope.title = 'New Item'; scope.item = { title: 'Untitled' }; }}]);
기본 지시자• ng-app• ng-bind• ng-bind-html-
unsafe• ng-bind-template• ng-change• ng-checked• ng-class• ng-class-even• ng-class-odd• ng-click• ng-cloak• ng-controller• ng-csp• ng-dblclick• ng-form
• ng-hide• ng-href• ng-include• ng-init• ng-list• ng-model• ng-mousedown• ng-mouseenteer• ng-mouseleave• ng-mousemove• ng-mouseover• ng-mouseup• ng-multiple• ng-non-bindable• ng-pluralize• ng-readonly
• ng-repeat• ng-selected• ng-show• ng-src• ng-style• ng-submit• ng-switch• ng-transclude• ng-view• a• form• input• script• select• textarea
커스텀 지시자예제
// my-rating 지시자 정의angular.module('directives', []).directive('my-rating', function() { return function(scope, element, attrs) { var tags = ''; var n = (isNaN(attrs.myRating) ? 0 : parseFloat(attrs.myRating); for (var i = 0; i < 5; i++) { var suffix = ((i < n) ? 'full' : 'empty'); tags += '<img src="star-' + suffix + '.png" />'; } element.html(tags); };});
// 앱 모듈에서 directives 모듈 로딩angular.module('app', [ 'directives' ])...
// my-rating 지시자 사용<span my-rating="{{rating}}"></span>
기본 필터•currency
•date
• filter
• json
• limitTo
• lowercase
•number
•orderBy
•uppercase
커스텀 필터예제
// truncatechars 필터 정의angular.module('filters', []).filter('truncatechars', function() { return function(text, maxlen) { return (text.length - 3 < maxlen) ? text : text.substring(0, maxlen-3) + '...'; };});
// 앱 모듈에서 filters 모듈 로딩angular.module('app', [ 'filters' ])...
// 템플릿 표현식에 truncatechars 필터 사용<span>{{ 'helloworld' | truncatechars:5 }}</span>
기본 서비스• $anchorScroll
• $cacheFactory
• $compile / $compileProvider
• $controller / $controllerProvider
• $document
• $exceptionHandler
• $filter / $filterProvider
• $http
• $httpBackend
• $interpolate / $interpolateProvider
• $locale
• $location / $locationProvider
• $log
• $parse
• $q
• $rootElement
• $rootScope / $rootScopeProvider
• $route / $routeProvider
• $routeParams
• $templateCache
• $timeout
• $window
kriskowal'sQ
전역 API•bind
•bootstrap
•copy
•element
•equals
•extend
• forEach
• fromJson
• identity
• injector
• isArray
• isDate
• isDefined
• isElement
• isFunction
• isNumber
• isObject
• isString
• isUndefined
• lowercase
•mock
•module
•noop
• toJson
•uppercase
•version
jQuery(Lite)
추천 사이트•모듈(Directive, Filter, 서비스 등) 모음: http://ngmodules.org
•예제 JSFiddle 모음: https://github.com/angular/angular.js/wiki/JsFiddle-Examples
• Bootstrap 지원: http://angular-ui.github.com
• Testacular 자바스크립트 테스트 프레임웍: http://testacular.github.com/
• AngularJS Tips and Tricks: http://deansofer.com/posts/view/14/AngularJs-Tips-and-Tricks-UPDATED
• AngularJS 페이스북 그룹(한국): http://angularjs.co.kr & http://www.facebook.com/groups/Korea.AngularJS.User.Group/
• ...
AngularJS 요약•DI?! 먹는 거임?
•복잡하다!
•어렵다!
•아무데나 끼워넣기 어렵다!!
•아무거나 끼워넣기 좋다!!
•프론트엔드 개발자를 위한 스프링?!
•Super-Powered by Google
•Mysterious Powered by "뽀대-Driven-Development"
Demo
이미지 출처: http://www.octopuscomms.net/who-are-we/blog/2010/1/25/welcome-to-blogtopus.aspx
Reinvent the wheel!게시판
•Post
•has_many :Comment
•Comment
•belongs_to :Post
https://github.com/iolo/blueberryseason
클래식 웹앱with Express
•Express on Nodejs
•Server-side rendering with “jade” template engine.
•Nothing Specials!
http://tomato.iolo.kr:3000/express
단일 페이지 웹앱with Backbone.js
•Backbone.js
•Client-side rendering with Underscore.js
•RESTful API Sever with Express on Node.js
http://tomato.iolo.kr:3000/backbone/
단일 페이지 웹앱with AngularJS
•AngularJS + Twitter Bootstrap
•Client-side rendering with AngularJS
•RESTful API Sever with Express on Node.js
http://tomato.iolo.kr:3000/angular/
Epilogue
이미지 출처: http://barry-overstreet.com/you-are-your-future/
프론트엔드 웹앱 이슈(1)검색 엔진 최적화(SEO)•Seach Engine Cloaking
•IP 주소나 User-Agent에 따라 봇을 위한 별도의 페이지 제공
•http://en.wikipedia.org/wiki/Cloaking
•http://support.google.com/webmasters/bin/answer.py?hl=en&answer=66355
•AJAX Crawling - Hashbang(#!)
•https://developers.google.com/webmasters/ajax-crawling/
•#!key=value --> ?_escaped_fragment_=key=value
프론트엔드 웹앱 이슈(2)접근성(Accessibility)•동적으로 바뀌는 DOM 노드는 스크린 리더에게 넘사벽?
•Accessible Rich Internet Application(ARIA)
•http://en.wikipedia.org/wiki/WAI-ARIA
•최신 HTML5, CSS3가 지원되지 않는 브라우져? 자바스크립트가 지원되지 않는 브라우져?
•Progressive Enhancement: http://en.wikipedia.org/wiki/Progressive_enhancement
•Unobtrusive Javascript: http://en.wikipedia.org/wiki/Unobtrusive_JavaScript
프론트엔드 웹앱 이슈(3)히스토리
•이전 / 다음 버튼 & 북마크
•화면의 각 단계마다 고유한 URL 해시(#) 부여
•window.location.hash 속성
•window.onhashchange 이벤트
•HTML5 브라우저 히스토리 API
•window.history.pushState()/popState()
•window.onpopstate 이벤트
프론트엔드 웹앱주요 프레임웍 비교
출처: http://codebrief.com/2012/01/the-top-10-javascript-mvc-frameworks-reviewed/
프레임웍 모듈-뷰 바인딩 UI 컴포넌트 HTML/CSS 친화도 확장성Backbone.js X X O O
SprouteCore O O X X
Sammy.js X X O O
Spine.js X X O O
Cappuccino O O X X
Knockout.js O X O O
JavascriptMVC X O O O
Google Web Tookit X O X X
Google Closure X O X X
Ember.js O O O O
AngularJS O X O O
Batman.js O X O O
May the Source be with you...
Questions?
That's all Folks!