PhoneCat Tutorial App 7 - Routing & Multiple views

2014. 9. 30. 10:49JS&FRONT/AngularJS

이번 장에서는 레이아웃 템플릿을 만드는 방법과 ngRoute 이라 불리는 Angular 모듈을 이용해서  라우팅을 추가해서 다중 뷰를 가지고 있는 어플리케이션을 만드는 방법에 대해서 배워보겠습니다.

- app/index.html 에 이동 할 때, app/index.html#/phones로 리다이렉트되어지고, 
브라우저에서 폰 리스트를 나타냅니다.

- 폰 링크를 클릭할 때, URL은 폰과 폰 디테일 페이지의 일부분이 보여지는 곳으로 변경됩니다. 


Dependencies

이번 단계에서 추가된 라우팅 상관 관계는 코어 Angular 프레임워크로부터 세분화되어 분산되어진
ngRoute 모듈에서 angular에 의해 제공되어 집니다.


클라이언트 사이드 의존성들을 설치하기 위해 Bower를 사용하고 있습니다.
이번 단계에서 새로운 의존성을 포함하기 위해 bower.json 설정 파일을 업데이트 합니다.

새로운 의존성 “angular-route” : “~1.2.x” 은 버전 1.2.x과 일치하는 angular-route 컴포넌트의 버전을 설치하라고 bower에게 알립니다. 
bower에게 이 의존성을 다운로드하고 설치하라고 알려야 합니다. 
만약 전역적으로 bower가 설치 되어 졌다면, 여러분은 bower install를 작동 할 수 있으나 이번 프로젝트에서 우리를 위해 bower install이 작동하도록 npm을 미리 설정해 놨습니다.

npm install


Multiple Views, Routing and Layout Template

우리 어플리케이션은 천천히 성장하고 좀 더 복잡해 지고 있습니다.
이전 7장에서 어플리케이션은 우리 사용자에게 싱글 뷰(모든 폰 목록)을 제공 했고, 템플릿 코드 전체가 index.html 파일 안에 위치 했습니다.
이 어플리케이션을 만드는 다음 장에서는 우리 리스트에서의 각각의 장비에 관련된 상세 정보를 보여 view를 추가하는 것입니다.
상세 뷰를 추가하기 위해서, 우리는 뷰들을 위해 템플릿 코드를 추가 하기 위해  index.html를 확장 할 수 있습니다만, 결국 급속하게 거대해질 것입니다.
대신에 우리는 index.html 템플릿에서 레이아웃 템플릿이라고 불리는 것으로 변경할 것입니다.
이건 우리 어플리케이션에 모든 뷰들을 위한 공통 템플릿 입니다.
다른 부분적인 템플릿은 그때 현재 “route” – 최근에 사용자에게 보여진 뷰에 따라 이 레이아웃 템플릿에 포함시킬 것입니다.

Angular내 어플리케이션 라우트는 $route 서비스의 제공자 인 $routeProvider를 통해 선언되어집니다.
이 서비스는 컨트롤러들 과 View 템플릿들 그리고 브라우저의 현재 URL 위치를 감싸는 것을 쉽게 만들어 줍니다.
이 기능의 사용은 우리가 우리가 브라우저의 history 및 북마크를 사용하도록 하는 딥링킹을 구현할 수 있습니다.


A Note about DI, Injector and Providers 

알다시피 DI는 AngularJS의 코어에 있습니다. 그래서 여러분에게는 그것이 어떤 식으로 동작하는지에 대한 것 혹은 두 가지를 이해하는 것이 중요합니다.

어플리케이션이 부트스트랩될 때, Angular는 여러분의 어플리케이션에 의해 요구 되어지는 모든 서비스들을
찾고 주입하게 될 injector를 만듭니다.
injector 자신은 $http 또는 $route 서비스가 하는 것에 관해서는 적절한 모듈 정의와 함께 구성되었음에도 불구하고, 사실상 이런 서비스들의 존재 조차 알지 못하며 어떤 것도 알지 못합니다.

인젝터는 단지 아래 단계를 수행합니다.

- 여러분의 어플리케이션에서 여러분이 명시한 모듈 정의를 로드합니다.

- 그 모듈 정의에서 정의된 모든 Provider들을 등록합니다.

- 그렇게 하는 것을 요청 했을 때 , 명시된 함수와 그들의 Provider를 통한 게으른 인스턴스들인 어떤 필수적인 의존성들(서비스)을 주입합니다.

프로바이더는 서비스들을 인스턴스를 제공하고 창조물과 서비스의 런타임 행동을 조정하는 것에 사용되어 질 수 있는 설정 API들을 표출하는 오브젝트들입니다. 

$route 서비스의 경우 , $routeProvider는 여러분들이 여러분들의 어플리케이션에 routes를 정의 하기 위해 허가하는 APIs들을 표출한다.

Note : 프로바이더는 config 함수들 안에 주입되어 질 수 없습니다. 따라서 여러분은 PhoneListCtrl 안에 $routeProvider를 주입 할 수 없었습니다.

Angular 모듈은 어플리케이션으로부터 전역 단계를 제거하는 문제를 풀고,
인젝터를 설정하는 방법을 제공합니다.
AMD 또는 require.js 모듈과 반대로, Angular 모듈은 스크립트 로드 순서 또는 지연 스크립트 패칭의 문제를 해결하기 위해 노력하지 않습니다.
이들의 목표들은 완전히 독립적이고 모듈시스템 둘 다 나란히 살수 있고 그들의 목표를 수행할 수 있습니다.

보다 더 심도 깊은 Angular의 DI에 대해서 보고자 한다면 아래 링크를 참고하세요.

URL : https://github.com/angular/angular.js/wiki/Understanding-Dependency-Injection 


Template

$route 서비스는 ngView 지시어와 함께 보통 접속어로 사용되어 집니다.
ngView 지시어의 역할은 레이아웃 템플릿 안에 현재 라우터를 위한 view template을 포함하기 위함입니다.
이것은 우리 index.html 탬플릿을 위해 완벽한 핏을 만드는 것입니다.

NOTE : AngularJS 버전 1.2의 시작, ngRoute은 해당 버전 안에 있고, 위의 Bower를 통해 우리가 다운로더 한 추가적인 angular-route.js 파일을 로딩한 것에 의해 로드 되어져야 합니다.

App/index.html

 우리 어플리케이션 안에 추가적인 자바스크립트 파일들을 로드업하기 위해 index 파일안에 새로운 <script> 태그를 추가했습니다.

- Angular-route.js : 라우팅를 우리에게 제공하는 Angular ngRoute 모듈을 정의합니다.

- App.js : 이 파일은 현재 우리 어플리케이션의 루트 모듈을 잡고 있습니다.

index.html 탬플릿에서 대부분의 코드를 지웠고 ng-view 속성이 있는 div를 포함한 한줄을 대신 넣습니다.
우리가 지운 코드는 phone-list.html 탬플릿에 놓습니다.

App/partials/phone-list.html


폰 디테일 뷰를 위해 플레이스 홀더 탬플릿을 추가했습니다.

App/partials/phone-detail.html : 

 

PhoneDetailCtrl 컨트롤러에 정의되어질 phoneId 표현식을 사용하고 있는 방법을 알아두세요.


The App Module.

어플리케이션의 조직을 증진시키기 위해, 우리는 Angular의 ngRoute의 사용을 하고 있고 우리는 컨트롤러를 phonecatControllers 모듈안으로 옮겨 놨습니다.(아래 보시는봐와 같이)
angular-route.js를 index.html에 추가했고 새로운 phonecatController 모듈을 controller.js에 생성했습니다.
그러나 이건 그 코드을 사용할수 있도록 하기 위해 필요로 한 모든게 아닙니다.
우리는 또한 우리 어플리케이션의 의존성들로 모듈을 추가해야만 합니다.
phonecatApp의 의존성들로써 이 두개의 모듈의 리스팅에 의해, 우리는 지지서와 그들이 제공하는 서비스를 사용 할 수 있습니다.

App/js/app.js

angular.module를 지나 [‘ngRoute’,’phonecatControllers’] 두 번째 인자를 알아두세요.
이 배열은 phonecatApp 이 의존하는 모듈을 리스트 한 것입니다.

 

phonecatApp.config() 메소드의 사용, 우리는 $routeProvider에게 우리 config 함수안으로 주입되어지는 것을 요청하고 우리의 라우트를 정의하기 위한 $routeProvider.when() 메소드의 사용합니다.
우리 어플리케이션 라우트는 아래와 같이 정의되어 집니다.

- when(‘/phones’) : phone 리스트 뷰는 URL 해시 프라그먼트가 /phones 일때 보여질 것입니다. 이 뷰를 제작하기 위해서, Angular는 /phone-list.html 탬플릿 과 PhoneListControl 컨트롤러를 사용할 것입니다. 

- When(‘/phones/:phoneid’) : 폰 상세 뷰는 URL 해시 프라그먼트가 :phoneid가 URL의 변경되는 부분인 ‘/phones/:phoneId’ 와 일치하는 경우에 보여질 것입니다.

이 뷰를 제작하기 위해서는 , Angular는 /phone-detail.html 탬플릿과 PhoneDetailCtrl 컨트롤러를 사용할 것입니다.

- Otherwise({redirectTo: ‘/phones’}) : 브라우저 주소가 우리 다른 라우트과 매치가 안될 때는 /phones로 리다이렉션되는 트리거합니다. 

우리가 이전 장에 구성했던 phoneListctrl 컨트롤러와 폰 디테일 뷰를 위해 app/js/controller.js 파일에 추가했던 새로운 빈 phoneDetailCtrl 컨트롤러를 재사용 했습니다. 

두번째 라우트 선언에서 :phoneId 파라미터의 사용을 적어두세요.

$route 서비스는 라우트 선언- ‘/phones/:phoneID’ –  현재 URL상에 매치되는탬플릿으로써 사용합니다. 모든 :과 함께 선언되어지는 변수들은 $routeParams 객체들안에서 추출되어 집니다.


Controllers

app/js/controller.js

다시 말하지만, 우리는 phonecatControllers 라고 불리는 새로운 모듈을 만들었습니다.
작은 AngularJS 어플리케이션을 위해, 여러분의 컨트롤들의 모두를 위해 단지 하나의 모듈을 만드는 것은 일반 적입니다. 만약 양 적다면 말이죠.
여러분의 어플리케이션이 규모가 성장함에 따라, 추가적인 모듈들안에 있는 여러분의 코드가 리팩터 되어야 하는 것인 상당히 일반적인 것입니다.
보다 큰 어플리케이션을 위해서는, 여러분은 아마도 여러분의 어플리케이션의 각각의 주요한 기능들로 분리된 모듈을 만들기를 원할 것입니다.
우리 예제 어플리케이션은 상대적으로 작기 때문에, 우리는 우리 모든 컨트롤러들을 phonecatControllers 모듈에 추가 할 것 입니다.


Test

적당히 감싸진 모든 것들을 자동으로 검증하기 위해, 우리는 다양한 URL들에 대해 이동하고 정확한 뷰가 표현되어 졌는지에 대한 검증하는 E2E 테스트를 작성했습니다.

 



테스트가 동작하는 것을 보기 위해 Npm run protractor 를 지금 재 동작 할 수 있습니다.


Experiments

{{orderProp}} 바인딩을 index.html에 추가하려고 해보세요 그리고 여러분은 아무것도 일어나지 않는 것을 볼 수 있을 것입니다. 여러분이 폰리스트 뷰에 있을 때 조차도.
orderProp 모델은 <div ng-view>요소와 함께 구성 되어진 phoneListCtrl에 의해 관리되는 스코프 안에서만 보여집니다. 
만약 여러분이 같은 바인딩을 phone-list.html 탬플릿에 추가했다면, 바인딩은 예상한대로 작동 할것 입니다.


Summary

라우팅 설정 과 폰 리스트 구현된 뷰 와 함께 우리는 폰 상세 뷰를 구현하기 위해 8장으로 갈 준비를 해야 합니다..