(AngularJS) 라우팅
*사용자 관리나 사용자 스토리관리, 그리고 데이터 시각화 등 기능적인 측면에서
복잡도가 증가한다.
그렇다면 사용자를 표시할 때와 사용자 스토리를 표시할 때를 어떻게 구분할 수 있을까?
아마 가능한 모든 경우의 수를 고려해서 이를 처리하려면 꽤나 복잡한 코드가 될 것이다.
모든 웹 플리케이션은 URL을 가지고 있으므로 이를 잘 활용하면 애플리케이션의 상태를 정의할 수 있다. 즉, 실ㅈ 사용자가 보고자 하는 애플리케이션의 특정영역을 URL로 표현할 수 있다.
이런 기법을 URL 라우팅(routing)이라고 하며, AngularJS는 URL라우팅을 구현하기 위한
ngRoute서브 모듈을 제공한다.
라우트를 이용하면 애플리케이션의 URL을 기준으로 어떤 내용을 보이고 숨길 것인지를 결정할 수 있다.
<ngRoute 구성요소>
1. $routeProvider : 라우트 설정 담당
2. $rotue : URL의 변경을 감지하여 ng-view 인스턴스를 제어한다.
3. ng-view : 현재 라우트를 처리할 컨트롤러와 뷰를 생성하고 제어
4. $routeParams : URL 매개변수를 해석하고 컨트롤러에 전달한다.
ngView는 라우트 템플릿을 가져와 라우트의 컨트롤러 내에서 컴파일 한 후, 컴파일이 완료된 뷰를 사용자에게 표시하는 역할을 담당한다.
* 복잡한 레이아웃
-> 라우트와 뷰 사이에는 1:1관계가 존재한다. 이 관계는 뷰가 중첩되는 등 복잡한 레이아웃을 구현할 경우 오히려 단점으로 작용한다.
이 문제를 해결하기 위한 방법은 AngularUI라우터를 이용
*라우트는 항상 모듈의 config블록에 작성한다. 그 이유는 애플리케이션이 실행되자마자 사용이 가능해야 하기 때문이다.
<라우트에 매개변수 사용하기>
라우트 경로에는 콜론을 이용해서 :userID와 같이 이름이 지정된 매개변수 그룹을 정의할 수 있다.
$route는 $location.path 속성을 통해 알아낸 경로에서 일치하는 매개변수를 찾아 $routeParams서비스에 저장하고 이를 적절한 컨트롤러에 주입한다.
예)
/users/:userID/preferences/:somePrefernece
/users/123/preferences/green/eggs/and/ham
여기서 $routeParams서비스가 /123과 /green/eggs/and/ham을 생성하게 된다.
angular.module('Angello.User')
.controller('UserCtrl', function($routeParams){
var myUser = this;
myUser.userId = $routeParams['userId'];
});
그렇다면 라우트 매개변수에 어떻게 userId 변숫값을 지정해서 users뷰에서 사용할 수 있을까?
users뷰의 진입점은 user 뷰이며, 이 페이지에서 등록된 모든 사용자와 그들의 ID를 파악할 수 있다.
따라서 ng-repeat 디렉티브 내에서 #/users/를 가리키는 새로운 링크를 생성하면 된다.
이때 사용자의 ID에 접근이 가능하므로 {{user.id}} 와 같이 사용자 ID를 바인딩하여 href="#/users/{{user.id}}" 라는 링크를 최종적으로 완성하게 된다.
예)
<tr ng-repeat = "user in users.users">
<td>
<button type = "button" class =" btn btn-link"
ng-click = "users.removeUser(user.id)">삭제</button>
<a class = "btn btn-link" href="#/users/{{user.id}}"> 보기 </a>
</td>
</tr>
<라우트에서 의존성 해석하기>
우리는 user 뷰가 users뷰에서 전달된 사용자를 올바르게 표시하는 것은 물론 사용 가능한 모든 스토리 목록을 모두 가져와서 그중 지정된 사용자에게 할당된 스토리들을 대입해야 한다.
그러기 위해서는라우트 설정객체($routeProvider.when 메소드의 두 번째 매개변수로 전달하는 객체) 의 resolve 속성을 이용해서 필요한 의존성을 정의하면 된다.
resolve속성은 여러 개의 의존성을 정의할 수 있는 객체 맵(map)이다.
myModule.confg(function ($routeProvider, $httpProvider, $provide) {
$routeProvider
//....
.when('/users/:userId' ,{
templateUrl : ~~
controller: 'UserCtrl',
controllerAs : 'myUser',
resolve :{
user : function($route, $routeParams, UserModel) {
var userId = $rotue.current.params['userId']
? $rotue.current.params['userId']
: $routeParams['userId'];
return UsersModel.fetch(userId);
},
stories: function(StoriesModel){
return StoriesModel.all();
}
})
.otherwise({redirectTo: '/' });
});
* 만약 애플리케이션이 로딩 중인지 아닌지를 표시하는 LoadingService를 로딩 중 이미지를 표시하는 모달 뷰에 바인딩한다면???
라우트를 변경할 때 로딩 중 애니메이션을 표시한다고하면?
그러려면 $routeChangeStart 와 $rotueChangeSuccess 이벤트를 리스닝 해야한다. 그래서 라우트의 변경이 시작되면 로딩 중 표시에 true를 지정하고 라우트의 변경이 완료되면 다시 false 값으로 되돌린다.
예)
//다음 동작은 애플리케이션 전체에 적용되기 때문에 module.run블록에 추가한다.
라우트 변경 이벤트를 리스닝하기 위한 $rootScope객체와 로딩 표시의 상태를 조정하기 위한 LoadingService서비스를 주입한다.
myModule.run(function ($rootScope, LoadingService) {
$rootScope.$on('$routeChangeStart', function(e, curr, prev) {
LoadingService.setLoading(true);
});
$rootScope.$on('$routeChangeSuccess', function(e, curr, prev) {
LoadingService.setLoading(false);
});
});
복잡도가 증가한다.
그렇다면 사용자를 표시할 때와 사용자 스토리를 표시할 때를 어떻게 구분할 수 있을까?
아마 가능한 모든 경우의 수를 고려해서 이를 처리하려면 꽤나 복잡한 코드가 될 것이다.
모든 웹 플리케이션은 URL을 가지고 있으므로 이를 잘 활용하면 애플리케이션의 상태를 정의할 수 있다. 즉, 실ㅈ 사용자가 보고자 하는 애플리케이션의 특정영역을 URL로 표현할 수 있다.
이런 기법을 URL 라우팅(routing)이라고 하며, AngularJS는 URL라우팅을 구현하기 위한
ngRoute서브 모듈을 제공한다.
라우트를 이용하면 애플리케이션의 URL을 기준으로 어떤 내용을 보이고 숨길 것인지를 결정할 수 있다.
<ngRoute 구성요소>
1. $routeProvider : 라우트 설정 담당
2. $rotue : URL의 변경을 감지하여 ng-view 인스턴스를 제어한다.
3. ng-view : 현재 라우트를 처리할 컨트롤러와 뷰를 생성하고 제어
4. $routeParams : URL 매개변수를 해석하고 컨트롤러에 전달한다.
ngView는 라우트 템플릿을 가져와 라우트의 컨트롤러 내에서 컴파일 한 후, 컴파일이 완료된 뷰를 사용자에게 표시하는 역할을 담당한다.
* 복잡한 레이아웃
-> 라우트와 뷰 사이에는 1:1관계가 존재한다. 이 관계는 뷰가 중첩되는 등 복잡한 레이아웃을 구현할 경우 오히려 단점으로 작용한다.
이 문제를 해결하기 위한 방법은 AngularUI라우터를 이용
*라우트는 항상 모듈의 config블록에 작성한다. 그 이유는 애플리케이션이 실행되자마자 사용이 가능해야 하기 때문이다.
<라우트에 매개변수 사용하기>
라우트 경로에는 콜론을 이용해서 :userID와 같이 이름이 지정된 매개변수 그룹을 정의할 수 있다.
$route는 $location.path 속성을 통해 알아낸 경로에서 일치하는 매개변수를 찾아 $routeParams서비스에 저장하고 이를 적절한 컨트롤러에 주입한다.
예)
/users/:userID/preferences/:somePrefernece
/users/123/preferences/green/eggs/and/ham
여기서 $routeParams서비스가 /123과 /green/eggs/and/ham을 생성하게 된다.
angular.module('Angello.User')
.controller('UserCtrl', function($routeParams){
var myUser = this;
myUser.userId = $routeParams['userId'];
});
그렇다면 라우트 매개변수에 어떻게 userId 변숫값을 지정해서 users뷰에서 사용할 수 있을까?
users뷰의 진입점은 user 뷰이며, 이 페이지에서 등록된 모든 사용자와 그들의 ID를 파악할 수 있다.
따라서 ng-repeat 디렉티브 내에서 #/users/를 가리키는 새로운 링크를 생성하면 된다.
이때 사용자의 ID에 접근이 가능하므로 {{user.id}} 와 같이 사용자 ID를 바인딩하여 href="#/users/{{user.id}}" 라는 링크를 최종적으로 완성하게 된다.
예)
<tr ng-repeat = "user in users.users">
<td>
<button type = "button" class =" btn btn-link"
ng-click = "users.removeUser(user.id)">삭제</button>
<a class = "btn btn-link" href="#/users/{{user.id}}"> 보기 </a>
</td>
</tr>
<라우트에서 의존성 해석하기>
우리는 user 뷰가 users뷰에서 전달된 사용자를 올바르게 표시하는 것은 물론 사용 가능한 모든 스토리 목록을 모두 가져와서 그중 지정된 사용자에게 할당된 스토리들을 대입해야 한다.
그러기 위해서는라우트 설정객체($routeProvider.when 메소드의 두 번째 매개변수로 전달하는 객체) 의 resolve 속성을 이용해서 필요한 의존성을 정의하면 된다.
resolve속성은 여러 개의 의존성을 정의할 수 있는 객체 맵(map)이다.
myModule.confg(function ($routeProvider, $httpProvider, $provide) {
$routeProvider
//....
.when('/users/:userId' ,{
templateUrl : ~~
controller: 'UserCtrl',
controllerAs : 'myUser',
resolve :{
user : function($route, $routeParams, UserModel) {
var userId = $rotue.current.params['userId']
? $rotue.current.params['userId']
: $routeParams['userId'];
return UsersModel.fetch(userId);
},
stories: function(StoriesModel){
return StoriesModel.all();
}
})
.otherwise({redirectTo: '/' });
});
* 만약 애플리케이션이 로딩 중인지 아닌지를 표시하는 LoadingService를 로딩 중 이미지를 표시하는 모달 뷰에 바인딩한다면???
라우트를 변경할 때 로딩 중 애니메이션을 표시한다고하면?
그러려면 $routeChangeStart 와 $rotueChangeSuccess 이벤트를 리스닝 해야한다. 그래서 라우트의 변경이 시작되면 로딩 중 표시에 true를 지정하고 라우트의 변경이 완료되면 다시 false 값으로 되돌린다.
예)
//다음 동작은 애플리케이션 전체에 적용되기 때문에 module.run블록에 추가한다.
라우트 변경 이벤트를 리스닝하기 위한 $rootScope객체와 로딩 표시의 상태를 조정하기 위한 LoadingService서비스를 주입한다.
myModule.run(function ($rootScope, LoadingService) {
$rootScope.$on('$routeChangeStart', function(e, curr, prev) {
LoadingService.setLoading(true);
});
$rootScope.$on('$routeChangeSuccess', function(e, curr, prev) {
LoadingService.setLoading(false);
});
});
댓글
댓글 쓰기