ProAngularJS Ch.22 뷰 라우팅

#실행결과 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 &amp;&amp; $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 = {};
 }

});

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중

%d 블로거가 이것을 좋아합니다: