SiNBLOG

140文字に入らないことを、極稀に書くBlog

AngularJSで一覧画面を作る

今日はAngularJSで一覧ページを作ってみました

動いているのは、以下のページ
AngularJS sample

ちょっと、データが適当過ぎて、なんのこっちゃ分からん感がすごいですが、DBから取得したデータを表示しています

登録しているデータは以下のエントリーで作ったFormで登録したデータ

AngularJSで連動して動くコンボボックスを作る Part 1 - SinDiary


まずはソース一覧を列挙して、ちょっとずつ解説をしていきます

index.html

<!DOCTYPE html>
<html lang="ja" ng-app="sample">
  <head>
    <meta charset="utf-8">
    <title>AngularJS sample</title>
    <meta name="description" content="">
    <meta name="author" content="">
    <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
    <!--[if lt IE 9]>
      <script src="//html5shim.googlecode.com/svn/trunk/html5.js"></script>
    <![endif]--><!-- Le styles -->
    <link rel="stylesheet" href="/lib/bootstrap/css/bootstrap.min.css">
    <link rel="stylesheet" href="/lib/bootstrap/css/bootstrap-responsive.min.css">
    <style type="text/css">
      body {
        padding-top: 30px;
        padding-left: 30px;
      }
    </style>
  </head>
  <body>
    <div>
  	  <h2>Hello AngularJS !!</h2>
      <div ng-view></div>
    </div>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script src="//code.angularjs.org/1.0.6/angular.min.js"></script>
    <script src="//code.angularjs.org/1.0.6/angular-resource.min.js"></script>
    <script src="/js/main.js"></script>
  </body>
</html>

main.js

(function() {
  var app = angular.module('sample', ['ngResource']).
    config(function($routeProvider) {
      $routeProvider.
        when('/', {controller:'ListController', templateUrl:'list.html'}).
        when('/entry', {controller:'EntryController', templateUrl:'entry.html'});
    });

  app.controller('ListController', ['$scope', '$resource', function($scope, $resource) {
    var Store = $resource("/store");
    $scope.stores = Store.query(function() {
      console.log("success store query");
    }, function(){
      console.log("error store query");
    });
  }]);

  app.controller('EntryController', ['$scope', '$location', '$resource', function($scope, $location, $resource) {
    $scope.categories = [{"id" : "1", "name" : "野菜"}];
    var List = $resource("/item/list");
    var Store = $resource("/store");

    $scope.changeCategory = function() {
      $scope.items = List.query({id : $scope.entryForm.categoryid}, function(){
        console.log("success list");
      }, function(){
        console.log("error list");
      });
    }

    $scope.submit = function($event) {
      console.log($scope.entryForm);
      Store.save($scope.entryForm, function(){
        console.log("success entry");
        $location.path('/');
      }, function(){
        console.log("error entry");
      });
    };
  }]);
})();

list.html

<div>
  <table class="table">
    <thead>
      <tr>
        <td>No</td>
        <td>CategoryId</td>
        <td>ItemId</td>
        <td>Name</td>
      </tr>
    </thead>
    <tbody ng-repeat="s in stores">
      <tr>
        <td>{{$index}}</td>
        <td>{{s.CategoryId}}</td>
        <td>{{s.ItemId}}</td>
        <td>{{s.Name}}</td>
      </tr>
    </tbody>
  </table>
  <a href="#/entry" class="btn btn-primary">Entry</a>
</div>

entry.html

<div>
  <form ng-submit="submit()">
    <select ng-model="entryForm.categoryId" ng-options="c.id as c.name for c in categories" ng-change="changeCategory()">
      <option value="">-- chose category --</option>
    </select>
    <br />
    <select ng-model="entryForm.itemId" ng-options="i.id as i.name for i in items">
      <option value="">-- chose item --</option>
    </select>
    <br />
    <input type="text" ng-model="entryForm.name"></input>
    <br />
    <button type="submit" class="btn btn-primary">Save</button>
    <a href="#/" class="btn">Cancel</a>
  </form>
</div>


これだけです
まずはファイルの構成ですが、以下の様な感じ

  • index.html - 最初に表示されるhtml
  • main.js - ControllerなどAngularJSを使っているJS
  • list.html - 一覧部分のDOMを持つtemplate
  • entry.html - EntryFormのDOMを持つtemplate

index.htmlには、ほとんど何も記述されておらず、主なDOMはtemplateにあります
これには以下のような理由があります

index.htmlにAngularJS用のDOMを書くと、AngularJS適用前にチラ見えする

今回だと、list.htmlにあるtableなんかが、index.htmlに書くと、最初にちらちら見えます
特に{{s.CategoryId}}とかが見えるので、ユーザにはなんじゃこりゃ?感が溢れ出ることでしょう
ということで、index.htmlには以下のように書いておきます

<div ng-view></div>

これで、templateの内容をこの中に表示してくれます
特にmoduleとかの名前も付いてないですが、1つのng-appの中で1つしか作れないのかな・・・?


後、重要なところはmain.jsの以下の部分でしょう

var app = angular.module('sample', ['ngResource']).
    config(function($routeProvider) {
      $routeProvider.
        when('/', {controller:'ListController', templateUrl:'list.html'}).
        when('/entry', {controller:'EntryController', templateUrl:'entry.html'});
    });

この部分でpathとController, templateを紐付けています
前のエントリーでcontrollerの範囲が分からないと言いましたが、上記だとそれっぽい範囲になっています
共通で使うmenuみたいなのがあると、また悩み始めると思いますが、少なくともページごとのcontrollerにはなってます

その他のソースは、だいたい前回のエントリーの内容と同じです
AngularJSで連動して動くコンボボックスを作る Part 1 - SinDiary
$routeProvider使う関係で細かい部分は変わっていますが


ソースはgithubにあるので、全体を見たい方は以下をご覧ください
Server側がgae/goではありますが・・・
GitHub - sinmetal/angularjs-sample


今は新規登録しかないですが、編集とか削除もぼちぼち作って行きたいと思います
後、もうちょっと中身のデータをまともなものにしたりとかw


疑問に思っていること
$routeProvider使った状態で、controllerをcontroller関数で生成する方法が分からない・・・
minify対策のこともあるし、直したいところ
AngularJSのDIの仕組み、minify対策は覚えておこう! - Qiita


2013-05-25 修正
コメントでminify対策用のcontrollerの書き方を教えてもらったので、修正しました!
ありがとうございます!