#실행결과 http://study.jeju.onl/ch22/products.html
(21장의 예제를 다시 사용하고 있어서 수정하여 작성했음)
이 장에서는 URL 라우팅을 활용하는 법에 대해 설명한다. URL 라우팅은 뷰를 사용해 애플리케이션 내에서 복잡한 네비게이션을 구현하는 기법이다. 이것은 사용자가 보는 콘텐츠를 제어할 수 있게 함으로써 복잡한 애플리케이션을 단순화하는데 도움이 된다. (작은 서비스는 필요없음)
주내용은 다음과 같다.
- ngRoute 모듈 설치
– URL 라우트 정의: config에서 routeProvider, locationProvider 이용 - ng-view 디렉티브
– $route 서비스는 프로바이더를 통해 정의된 라우트를 생성해서 ng-view가 적용된 엘리먼트의 내용을 변경한다 - 코드 및 마크업 연결
– $location.path(“<경로>”) - 라우트 파라미터 활용
– routeProvider의 경로 정의에서 /edit/:<id> 템플릿 정의
– $route 서비스의 이벤트에서 파라미터 값을 가져와 처리
: $routeChangeStart, -ChangeSuccess, -Update, -ChangeError - 라우트 고급 활용
– controller 분리: 개별적으로 컨트롤러 사용
– resolve 동작 정의: 뷰의 로드가 완료 되었을 때 실행
– resource를 factory로 분리: 애플리케이션 전역에서 접근 가능
이에 대한 소스코드는 다음과 같다.
1) /ch21/products.html
<!DOCTYPE html> <html ng-app="exampleApp"> <head> <title>Ch21. REST서비스 - ProAngularJS</title> <link href="/node_modules/bootstrap/dist/css/bootstrap.css" rel="stylesheet" /> <link href="/node_modules/bootstrap/dist/css/bootstrap-theme.css" rel="stylesheet" /> <a href="/node_modules/angular/angular.js">/node_modules/angular/angular.js</a> <a href="/node_modules/angular/angular-resource.js">/node_modules/angular/angular-resource.js</a> <a href="/node_modules/angular/angular-route.js">/node_modules/angular/angular-route.js</a> <base href="/ch21/"> <a href="http://products.js">http://products.js</a> <a href="http://increment.js">http://increment.js</a> </head> <body ng-controller="defaultCtrl"> <div class="panel panel-default"> <h3 class="panel-heading">Products</h3> <div></div> </div> </body> </html>
2) /ch21/tableView.html
<div class="panel-body"> <table class="table table-striped table-bordered"> <thead> <tr> <th>Name</th> <th>Category</th> <th class="text-right">Price</th> <th></th> </tr> </thead> <tbody> <tr> <td>{{ item.name }}</td> <td>{{ item.category }}</td> <td class="text-right">{{ item.price | currency }}</td> <td class="text-center"> Delete Edit --> <a href="edit/{{ item.id }}" class="btn btn-xs btn-primary">Edit</a> <!-- $save메소드 호출을 통해 변경된 값이 DB에 저장된다 --> </td> </tr> </tbody> </table> <div> Refresh New --> <!-- 상대주소로 이동: /create라고 하면 study.jeju.onl/create로 이동 --> <a href="create" class="btn btn-primary">New</a> </div> </div>
3) /ch21/products.js
angular.module("exampleApp", ["increment","ngResource","ngRoute"]) .constant("dataUrl", "http://study.jeju.onl:5500/products/") // 애플리케이션 전역에서 쉽게 접근할 수 있게 factory로 패키징함 .factory( "productsResource", function( $resource, dataUrl) { return $resource( dataUrl+":id", { id: "@id"}, { create: { method: "POST"}, save: { method: "PUT"}} ); }) .config( function( $routeProvider, $locationProvider) { $locationProvider.html5Mode( true); $routeProvider.when("/edit/:id", { templateUrl: "/ch21/editorView.html", controller: "editCtrl" }); $routeProvider.when("/create", { templateUrl: "/ch21/editorView.html"}); // templateUrl은 절대 주소로 적어야 한다 //$routeProvider.when("/list", { templateUrl: "/ch21/tableView.html"}); // '/list' 라우터를 통합해서 정의 $routeProvider.otherwise( { templateUrl: "/ch21/tableView.html", controller: "tableCtrl", resolve: { // 뷰가 resolve 되면 $resource로부터 query()를 실행해 데이터를 리턴한다 data: function( productsResource) { return productsResource.query(); } } }); }) .controller("defaultCtrl", function( $scope, $location, productsResource) { /* $scope.currentProduct = null; $scope.$on( "$routeChangeSuccess", function() { if( $location.path().indexOf("/edit/") == 0) { var id = $routeParams["id"]; for( var i=0; i<$scope.products.length; i++) { if( $scope.products[i].id == id) { $scope.currentProduct = $scope.products[i]; break; } } } }); $scope.productsResource = $resource( dataUrl+":id", { id: "@id"}, { create: { method: "POST"}, save: { method: "PUT"}} ); $scope.listProducts = function() { $scope.products = $scope.productsResource.query(); $scope.products.$promise.then( function( data) { // Do something }); //$location.path("/list"); } $scope.editProduct = function( product) { $scope.currentProduct = product; $location.path("/edit"); } $scope.listProducts(); */ // 팩토리 productsResource로부터 생성된 products를 담아둘 포인터 변수 $scope.data = {}; $scope.deleteProduct = function( product) { product.$delete().then( function() { $scope.data.products.splice( $scope.data.products.indexOf(product), 1); }); $location.path("/list"); } $scope.createProduct = function( product) { // new 연산자와 함께 save() 또는 create() 사용 가능 //new $scope.productsResource( product).$create().then( function( newProduct) { new productsResource( product).$create().then( function( newProduct) { $scope.data.products.push( newProduct); $location.path("/list"); }); } }) .controller( "tableCtrl", function( $scope, $location, $route, data) { $scope.data.products = data; $scope.refreshProducts = function() { $route.reload(); } }) .controller( "editCtrl", function( $scope, $routeParams, $location) { $scope.currentProduct = null; if( $location.path().indexOf("/edit/") == 0) { var id = $routeParams["id"]; for( var i=0; i<$scope.data.products.length; i++) { if( $scope.data.products[i].id == id) { $scope.currentProduct = $scope.data.products[i]; break; } } } $scope.cancelEdit = function() { /* if( $scope.currentProduct && $scope.currentProduct.$get) { $scope.currentProduct.$get(); } $scope.currentProduct = {}; */ $location.path("/list"); } $scope.updateProduct = function( product) { product.$save(); $location.path("/list"); } $scope.saveEdit = function( product) { if( angular.isDefined( product.id)) { $scope.updateProduct( product); } else { $scope.createProduct( product); } $scope.currentProduct = {}; } }); angular.module( "exampleApp", [ "ngResource", "ngRoute"]) .constant( "dataUrl", "http://study.jeju.onl:5500/products/") // 애플리케이션 전역에서 쉽게 접근할 수 있게 factory로 패키징함 .factory( "productsResource", function( $resource, dataUrl) { return $resource( dataUrl+":id", { id: "@id"}, { create: { method: "POST"}, save: { method: "PUT"}} ); }) .config( function( $routeProvider, $locationProvider) { // base 태그가 필요하다 $locationProvider.html5Mode( true); $routeProvider.when("/edit/:id", { templateUrl: "/ch22/editorView.html", controller: "editCtrl" }); // 바보야, 컨트롤러가 있어야 작동을 하지! $routeProvider.when("/create", { templateUrl: "/ch22/editorView.html", controller: "editCtrl" }); // '/list' 라우터를 통합해서 정의 $routeProvider.otherwise( { templateUrl: "/ch22/tableView.html", controller: "tableCtrl", resolve: { // 뷰가 resolve 되면 $resource로부터 query()를 실행해 데이터를 리턴한다 data: function( productsResource) { return productsResource.query(); } } }); }) .controller("defaultCtrl", function( $scope, $location, productsResource) { // 팩토리 productsResource로부터 생성된 products를 담아둘 포인터 변수 $scope.data = {}; $scope.createProduct = function( product) { //console.log("enter createProduct(): "+product.name); new productsResource( product).$create().then( function( newProduct) { $scope.data.products.push( newProduct); $location.path("/list"); }); } $scope.deleteProduct = function( product) { product.$delete().then( function() { $scope.data.products.splice( $scope.data.products.indexOf(product), 1); }); $location.path("/list"); } }) // 기능별로 컨트롤러를 분리해 놓으면 코드 수정이 편해진다 .controller( "tableCtrl", function( $scope, $location, $route, data) { $scope.data.products = data; $scope.refreshProducts = function() { $route.reload(); } }) .controller( "editCtrl", function( $scope, $routeParams, $location) { $scope.currentProduct = null; if( $location.path().indexOf("/edit/") == 0) { var id = $routeParams["id"]; for( var i=0; i<$scope.data.products.length; i++) { if( $scope.data.products[i].id == id) { $scope.currentProduct = $scope.data.products[i]; break; } } } $scope.cancelEdit = function() { //console.log("enter cancelEdit(): "+$scope.currentProduct.name); $location.path("/list"); } $scope.updateProduct = function( product) { product.$save(); $location.path("/list"); } $scope.saveEdit = function( product) { //console.log("enter saveEdit(): "+product.name); if( angular.isDefined( product.id)) { $scope.updateProduct( product); } else { $scope.createProduct( product); } $scope.currentProduct = {}; } });