1.2.0 timely-delivery (2013-11-08)
몇주 전 Angular.js의 새 안정버전인 1.2.0 timely-delivery가 나왔다. 그동안 1.0.7을 사용하고 있었기에 새 버전에서 달라진 점을 좀 찾아봤다.(개발 버전을 모니터링하고 있지는 않았기에...) Angular.js도 짝수 버전은 안정버진이고 홀수는 개발버전으로 진행하고 있는데 그래서 그동안은 1.0.x 버전이 안정버전으로 유지되고 동시에 1.1.x 버전이 개발되다가 이번에 1.2.x로 새 안정버전이 올라가기 시작한 것이다.
좀 정리된 문서를 찾아보려고 했는데 Angular.js 쓰는 사람들은 1.1.x 개발버전을 적극적으로 쓰고 있었는지 1.0과 1.2의 차이점을 설명한 글은 거의 없고 대부분은 1.1.5와 1.2의 차이점을 설명하는 글이 대부분이었다. 그래서 이번에 1.2를 사용하기 위해서 뭐가 바뀐지 파악할 겸 Changelog를 보면서 정리를 해봤다.(코드로 일일이 테스트한건 아니고 문서들을 보고 정리했기 때문에 혹 잘못설명된 내용이 있을 수도 있다.) 일반적으로 개발버전이 어느 정도 개발되면 그대로 안정버전으로 넘어가는데 Angular는 특이하게 1.1.5에서 1.2로 넘어가면서 새로운 변경을 많이 시도했다.(그래서 문제가 좀 많이 발생한듯...)
주요 변경사항
참고로 1.2.0에서 프로퍼티 이름에 언더스코어를 앞이나 뒤에 붙히면 Angular 표현식({{someProperty}}
)에서 접근할 수 없는 private 프로퍼티 기능이 추가되었는데 언더스코어를 이미 많이 사용하고 있어서 상당히 많은 문제가 발생했다. 그래서 이 기능은 1.2.1에서 다시 제거되었다.
디렉티브
- 조건에 따라 DOM을 추가/제거할 수 있도록 AngularUI의
ui-if
를 도입해서ngIf
디렉티브가 추가되었다. - 애니메이션을 위한
ngAnimate
가 추가되었다.
- 1.1.x 버전에서는
ng-animate
디렉티브를 기반으로 동작했는데 1.2.x에서는 CSS 기반으로 새로 작성하고ng-animate
디렉티브는 제거되었다. 그래서 HTML에.ng-enter
,.ng-enter-active
,.ng-leave
,.ng-leave-active
같은 클래스로 CSS 애니메이션/트래지션 효과를 줄 수 있다.(Remastered Animation in AngularJS 1.2 참고)
- 1.1.x 버전에서는
- 터치방식의 디바이스를 위한
ngTouch
디렉티브가 추가되었다.
- 1.1.x에서는 ngMobile로 추가되었다가 터치 기기가 모두 모바일 기기가 아니므로 ngTouch로 변경되었다.(angular-touch.js)
ngTouch
의ngClick
이 기존의ngClick
을 오버라이드해서 터치이벤트에 반응하고 비-터치 기기에서는 click 이벤트에 대응된다. 클릭시 스타일을 줄 수 있도록ng-click-active
CSS 클래스도 추가되었다.- 스와이프 액션을 위한
ngSwipeRight
,ngSwipeLeft
디렉티브가 추가되었다.
ngRoute
가ngResource
처럼 별도의 모듈로 분리되었다.$route
,ngView
,$routeParams
를 사용한다면angular-route.js
파일을 따로 불러와서 의존성에 추가해 주어야 한다.<script src="angular.js"></script> <script src="angular-route.js"></script> <script> var myApp = angular.module('myApp', ['ngRoute', 'someOtherModule']); </script>
ngFocus
와ngBlur
디렉티브가 추가되었다.ngKeydown
,ngKeyup
,ngKeypress
디렉티브 추가되었다.ngEventDirectives
에ngCopy
,ngCut
,ngPaste
가 추가되었다.- HTML5
<detail>
,<summary>
태그를 토글할 수 있는ngOpen
디렉티브가 추가되었다. - HTML5의
srcset
속성을 지원하는ngSrcset
디렉티브가 추가되었다. ngRepeat
에 홀수번째, 짝수번째 요소를 나타내는$even
,$odd
프로퍼티가 추가되었다.(기존에는$index
,$first
,$middle
,$last
프로퍼티만 있었다.)ngHtmlBindUnsafe
가 제거되고 새로 추가된ngHtmlBind
로 대체되었다.ngHtmlBind
는 SCE(Strict Contextual Escaping, 아래 참조)를 지원한다.ngSwitch
에서ng-switch
가 적용되지 않은 요소의 순서를 유지한다. 즉,<ul ng-switch="select"><li>1</li><li ng-switch-when="option">2</li></ul>
일 경우 전에는 2,1의 순서로 나왔지만 이젠 1,2의 순서로 나온다.- 이전에는
ngInclude
와ngView
가 수정된 요소의 내용만 변경했지만 이제는 포함된 모든 내용을 매번 새로 만든다. 이로써 모든 내용을 포함한 단 하나의rootElement
가 언제나 존재해서 css 애니메이션을 쉽게 정의할 수 있게 되었다.
서비스
- Strict Contextual Escaping 서비스를 위한
$sce
서비스가 추가되었다. Strict Contextual Escaping은 특정 컨텍스트를 안전하다고 간주할 수 있는 값에 바인딩하는 모드이다.(ng-bind-html-unsafe
로 사용자가 제어하는 HTML을 바인딩하는 컨텍스트) 1.2에서는 SCE가 기본적으로 활성화 된다.(IE8 quirks에서는 지원하지 않는다.) SCE로 안전한 코드를 작성할 수 있고 XSS, 클릭재킹(clickjacking)등의 보안취약점을 감시할 수 있다. 프로미스 객체의 자동 바인딩 기능이 제거되어서
$parse
와 템플릿이 프로미스 객체를 분해하지 않는다.$scope.foo = $http({method: 'GET', url: '/someUrl'});
이전에는 위와같이 사용한경우 바로 템플릿에서
{{foo}}
를 사용할 수 있었지만 1.2에서는 다음과 같이 사용해야 한다.(이 기능은 좋아보였는데 없어졌네.)$http({method: 'GET', url: '/someUrl'}) .success(function(data) { $scope.foo = data; });
이 기능이 필요하다면
$parseProvider.unwrapPromises(true)
를 실행해서 활성화 해야 한다.$resource
가 더이상$then
함수를 지원하지 않고$promise
프로퍼티를 가지게 되었다. 그리고$http
응답객체에 접근할 수 있도록 액션마다interceptor
가 추가되었다.- 이전에는
Resource.query().$then(callback);
와 같이 사용했지만 1.2.x에서는Resource.query().$promise.then(callback);
와 같이 사용해야 한다. Resource 메서드가 프로미스 객체가 아니라 인스턴스 자체를 반환하게 변경되었다.
resource.$save().chaining = true;
이전에는 위와 같이 사용했다면 1.2에서는 다음과 같이 사용해야 한다.
resource.$save(); resource.chaining = true;
성공했을 때 Resource 프로미를 HTTP 응답 객체가 아니라 Resource 인스턴스로 처리해야 한다. 그래서 HTTP 응답객체에 접근하려면
interceptor
를 사용해야 한다.Resource.query().$then(function(response) {...});
이전에는 위와 같이 사용했다면 1.2에서는 다음과 같이 사용한다.
var Resource = $resource('/url', {}, { get: { method: 'get', interceptor: { response: function(response) { // expose response return response; } } } });
- 이전에는
$compile
가 다중 엘리먼트 디렉티브를 지원해서 다음과 같이 사용할 수 있다.(ngInclude
나 다른 디렉티브들도 순회할 수 있다.) 그래서 디렉티브의 이름은-start
나-end
로 끝날 수 없다.<tr ng-repeat-start="item in list">I get repeated</tr> <tr ng-repeat-end>I also get repeated</tr>
$route
에서 슬래시를 포함한 경로를 모두 포함할 수 있는 named wildcard 기능의 문법이 변경되었다.$routeProvider.when('/Book1/:book/Chapter/:chapter/*highlight/edit', {controller: noop, templateUrl: 'Chapter.html'});
이전에는 이름을 가진 와일드카드 파라미터를 위처럼
*highlight
로 사용했지만 이젠 다음과 같이:highlight*
로 사용한다.$routeProvider.when('/Book1/:book/Chapter/:chapter/:highlight*/edit', {controller: noop, templateUrl: 'Chapter.html'});
$q
에서promise.always
가promise.finally
로 변경되어서$q
에 Q 프로미스 라이브러리를 사용할 수 있다.$http.get('/foo').always(doSomething);
이전에는 위와 같이 사용했지만 1.2에서는 다음과 같이 사용한다.
$http.get('/foo').finally(doSomething);
IE8 같은 브라우저에서는 ES5를 지원하지 않으므로 다음과 같이 사용해야 한다.
$http.get('/foo')['finally'](doSomething);
$controller
가 "Controller as"라는 문법을 지원해서ng-controller="MyController as my"
와 같이 사용할 수 있게 되었다. 이렇게 작성할 경우MyController
객체의my
라는 인스턴스를 만들어서 사용한다.(프로토타입 속성을 가지는 컨트롤러를 정의하고 인스턴스를 별도로 만들어서 사용할 수 있는 용도로 보인다.)setInterval
을 감싸는$interval
서비스가 추가되었다.- 모바일 브라우저에서 클릭해서 전화를 걸 수 있도록
$compile
가 링크(a[href]
)에tel:
을 지원한다. $location.search
가 같은 값을 가지는 다중 키를 지원하게 되었다.(배열에 저장된다.) 이전 버전에서는parseKeyValue
의 마지막 키가 이전의 모든 키를 덮어쓰고toKeyValue
는 콤마로 구분된 문자열로 키를 합쳤다.(이렇게 사용하고 있었다면 1.2에서는 꼭 수정해야 한다.)
테스트
- e2e 테스트에서는 애니메이션을 자동으로 비활성화한다.
- angular mocks가 mocha를 지원하게 되었다.
- ngScenario DSL에 dbclick, mouseover 메서드가 추가되었다.
- 시나리오 테스트에서
mousedown
과mouseup
이벤트가 추가되었다. ngMock
에서 편의를 위해서module
에 object 리터럴을 전달할 수 있다.ngMock
의 테스트코드내에서 동적 스타일시트를 생성할 수 있게 되었다.ngScenario
에서browserTrigger
가 마우스 이벤트의 파라미터 대신eventData
객체를 사용하도록 변경되었다. 1.2에서 사용하려면keys
,x
,y
파라미터를 객체로 만들어서browserTrigger
함수의 세번째 파라미터로 전달해야 한다.
그 외...
angular.noConflict
가 추가되어서 Angular의 네임스페이스가 충돌하는 경우 처리할 수 있다.- jQuery를 이전 버전에서는 전역적으로 참조하다가 1.2에서는 지역범위로 참조하게 변경되었다. 그래서 Angular.js가 아닌 코드에서 쉽게 jQuery를 사용할 수 있다.
<a>
와<img>
를 제외하고는src
속성에 단 하나의 표현식만 사용할 수 있게 되었다.(이는 XSS와 관련된 보안을 강화한 것이다.) 즉, 1.2에서는<iframe src="{{baseUrl}}?a={{a}&b={{b}}">
와 같이 사용할 수 없으므로 자바스크립트에서 하나의 값으로 만든 후에<iframe src="{{fullSrc}}">
로 사용해야 한다.- DOM 이벤트 핸들러에서는 인터폴레이션을 사용할 수 없게 되었다. 이전 버전에서는
$scope.foo = 'alert(1)';
와 같이 정의하고<div onclick="{{foo}}">
와 같이 사용할 수 있었지만 자바스크립트 코드를 평가하는게 안전하지 않으므로 1.2에서는scope.foo = function() { alert(1); }
로 정의하고<div ng-click="foo()">
와 같이 사용해야 한다. - 폼 이름에 표현식을 사용할 수 있게 되어서
<form name="ctrl.form">
와 같이 작성하면$scope.ctrl.form
로 접근할 수 있게 되었다.(이전에는$scope['ctrl.form']
로 접근해야 했다.) <input>
의 이름으로hasOwnProperty
를 사용할 수 없게 되었다. 이전 버전에서는 경고도 없이 이러한 input이 스코프에 추가되지 않았는데 1.2 부터는 badname 예외를 던진다.$compileProvider
로 설정한 화이트리스트를 안전한 URL을 점검하는데 사용할 수 있게 되었다. 기본적으로image/*
mime 타입을 가진data:
URI를 포함한 일반적인 프로토콜 접두사가 화이트리스트에 포함되어 있다. 이 변경사항은 어플리케이션에 영향을 주지는 않는다.select[multiple]
에 바인딩할 수 없도록 변경되었다. 이 기능은 원래 양방향 바인딩이 동작하지 않으므로 아무도 사용하지 않았다.고립된 스코프를 갖지 않는 디렉티브는 같은 엘리먼트에서 고립된 디렉티브에서 고립된 스코프를 가져오지 않는다. 이 동작에 의존하고 있다면 로컬에서 스코프를 사용하기 위해 명시적으로 전달하도록 고립된 디렉티브를 변경해야 한다.
<input ng-model="$parent.value" ng-isolate> .directive('ngIsolate', function() { return { scope: {}, template: '{{value}}' }; });
이전에는 위와 같이 사용했다면 1.2에서는 다음과 같이 사용해야 한다.
<input ng-model="value" ng-isolate> .directive('ngIsolate', function() { return { scope: {value: '=ngModel'}, template: '{{value}} }; });
그 밖에 수정된 기능
- FormController가 폼을 원래의 상태로 리셋할 수 있게 되었다.
- 스코프내에서 컬랙션을 감시하기 위한
$watchCollection
가 추가되었다. angular.bootstrap
가 지연된(deferred) 부트스트랩핑을 지원한다.(테스트 러너나 Batarang에서 유용하다.)ngModel
이ngTrim
속성을 지원해서 인풋의 trim여부를 지정할 수 있게 되었다.(trim을 하는게 기본값이다.)$log
에$log.debug()
추가되었다.- batarang에 transcluded 스코프와 isolate 스코프 정보도 나온다.
$watch
에 표현식이 상수면 한번만 평가한다.$interpolate
이 실행시 시작/종료 심볼(기본값은{{
와}}
)을 노출해서 변경할 수 있게 되었다.ng-options
에서 "track by [trackByExpression]" 문법을 사용해서 객체의 동일함을 확인하는 표현식을 사용할 수 있다.ngRepeat
에서 각 아이템을 추적할 수 있는 트래킹 함수를 사용할 수 있다.(같은 키를 가지면 오류가 발생할 수 있다.).ngInclude
에 몇개의 인클루드가 보내지고 완료되었는지 확인할 수 있도록$includeContentRequested
이벤트가 추가되었다.$digest
나$apply
밖에서$evalAsync
큐에 작업목록을 추가했으면 다음 차례(next tick)에 새로운$digest
가 스케쥴링된다. 흔한 경우는 아니지만 프로미스의 비동기를 보장하기 위해서$evalAsync
큐를 사용하는$q
프로미트를$digest
외부에서 처리할 수 있다.e2e 테스트에서는 애니메이션을 자동 비활성화한다.
$http
- XHR의 커스텀 responseType을 지원한다.
- 기본적으로
withCredentials
설정을 허용하게 되었다. - XSRF헤더와 쿠키명을 오버라이드할 수 있다.
timeout
인자가 프로미스 객체이면 프로미스객체가 처리되었을 때 요청을 거절한다.PATCH
요청시 기본 content type 헤더가 추가되었다.- JSONP 요청에 타이아웃을 지원한다.
- request/response의 프로미스 체이닝을 지원한다.
$http.defaults.cache
에 기본 캐시가 추가되었다. 기본 캐시를 끄려면 요청 설정에서{cache: false}
를 설정해야 한다.- 헤더값에 함수를 사용할 수 있다.
$resource
- 액션마다 커스텀 헤더를 지원한다.
- 모든
$http.config
액션(transformRequest, transformResponse, cache 등)을 지원하게 되었다. - 리소스 파라미터를 함수로 정의하면 기본 리소스 파라미터가 런타임시에 계산되는 동적 파라미터로 사용한다.
- 리소스 액션의 URL을 오버라이드 할 수 있다.
$compile
postlink
함수에서 DOM 구조를 변경할 수 있다.- 디렉티브가 인터폴레이션된 속성을 수정할 수 있다.
template
와templateUrl
프로퍼티를 함수로 정의해서 동적으로 생성할 수 있다.ngAttr*
로 속성 바인딩을 지원한다. SVG등 브라우저가 인터폴레이션이 진행되기 전에 파싱을 해서 생기는 오류를 막기 위해서ng-attr-
,ng:attr:
,ng_attr_
등의 접두사를 사용하면 바인딩이 완료되었을 때 속성을 설정한다.=?
로 바인딩을 하면 정의되지 않은 값이라 하더라도 예외를 던지지 않는다.(=
를 사용할 경우에는 NON_ASSIGNABLE_MODEL_EXPRESSION을 던진다.)
$parse
- Angular 표현식에서 동등비교(
===
,!==
) 지원한다. constant
와literal
프로퍼티가 추가되서 표현식이 상수값인지 리터럴(number, string, boolean 등) 알 수 있게 되었다.- 파서에서 삼항 연산자를 지원한다.
- Angular 표현식에서 동등비교(
$q
$q.all()
이 해쉬를 받는다.- 프로미스의 오류 핸들러를 쉽게 정의할 수 있도록
.catch()
가 추가되었다. - 진행상태를 알 수 있는
deferred.notify()
메서드가 추가되었다. - 프로미스가 성공하든 실패하든 호출되는
$q.always()
메서드가 추가되었다.
$route
when
의 template 파라미터에 함수를 사용할 수 있다.- URL 매칭을 할때 대소문자를 구별하도록
caseInsensitiveMatch
옵션이 추가되었다.
- filter
- linky 필터가
target
(_blank
,_parent
같은)을 지원한다. - date 필터에서 밀리초를 지원하는
[.,]sss
포매터가 추가되었다. - 필터에 임의의 비교를 할 수 있는 Comparator 함수를 전달할 수 있다.
$ControllerProvider.register
나$CompileProvider.directive
처럼$FilterProvider.register
에도 필터의 이름이나 팩토리의 맵을 전달할 수 있다.
- linky 필터가
- jqLite
triggerHandler()
추가되었다.ready()
가document.readyState=='complete'
를 지원한다.scope()
가 격리된 스코프는 반환하지 않게 되었으므로 격리된 스코프의 디렉티브에서는isolateScope()
를 대신 사용해야 한다.bind
,unbind
가 최신 jQuery처럼on
,off
로 변경되었다.
- 테스트
- ngScenario DSL에 mouseover 메서드가 추가되었다.
- ngScenario에서
<select>
의 값이 없는 option일 경우 실패하도록 수정되었다. $timeout-mock
에verifyNoPendingTasks
메서드 추가되었다.ngMock
이 특정시간의 지연을 주는$timeout.flushNext
가 추가되었다.ngMock
이$timeout.flush
에서 지연시간 제한을 파라미터로 받게 되었다.ngMock
이 데이터 파라미터를 매칭에 함수를 사용할 수 있게 되었다.
$sniffer
가 자동으로 CSP 모드를 감지한다.(현재는 Chrome Canary에서만 지원한다고 나와있었는데 시간이 지나서 지금은 정확히 모르겠음.)$interpolate
가 컨텍스트를 가진 오류 메시지 지원한다.$cacheFactory
에서cache.put
시에 추가된 값을 반환한다.ngSwitch
의ngSwitchWhen
와ngSwitchDefault
가 다중 매칭을 지원한다.$injector
가 프로퍼티를 가지고 있는지 확인할 수 있는has
메서드를 지원한다.ngPluralize
에서when
속성대신 속성으로도 매칭을 할수 있게 추가되었다.
머가 복잡하군요 ㅋㅋ
원래 좀 복잡해.. ㅠㅠ
안녕하세요. 좋은 자료 잘 보았습니다.
정리를 잘해 주셔서 출처를 적고, 카페에 자료를 퍼갔습니다.
혹 허락지 않으시면 올린 글은 삭제토록 하겠습니다.
CCL만 따라주시면 문제되지 않습니다.
한번 읽어보았는데 어렵네요.. ㅎ 한빛미디어 앵귤러 기초편 보면서 참고하려구요 ㅎㅎ
좋은 자료 감사합니다!
이제 또 새로운 버전 얘기가 오가고 있네요. ㅠㅠ