SiNBLOG

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

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

以下のエントリーで作成したサンプルをGoogle+のAngularJS JPコミュニティにサンドバッグとして投下した結果

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


親切にふるぼっこにした上、pull requestまで送ってくれました!

G+
https://plus.google.com/u/0/114061805681880927213/posts/JpmZpC5CsNW

pull request
サンドバック part1 by teyosh · Pull Request #2 · sinmetal/angularjs-sample · GitHub


指摘してくださった内容は、以下の通り。

  • ng-appにmoduleを設定しましょう
  • controllerはcontroller関数で設定しましょう
  • categoriesの初期化にng-initはいらないかな
  • itemsとentryにはngResourceを使うと便利
  • factory使ったりdirectiveで隠蔽したりすればもっといいかも
  • form validationの機能もあるので使うといいかも

上記全て対応できたわけではないのですが、ある程度修正したのが以下のソース

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">
  </head>
  <body>
    <div ng-controller="MainController">
  	  <h2>Hello AngularJS !!</h2>
      <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">submit</button>
      </form>
    </div>
    <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"]);
  app.controller("MainController", function($scope, $resource){
    $scope.categories = [{"id" : "1", "name" : "野菜"}];
    var List = $resource("/item/list");
    var Entry = $resource("/store/entry");
    $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) {
      Entry.save($scope.entryForm, function(){
        console.log("success entry");
      }, function(){
        console.log("error entry");
      });
    };
  });
})();

それぞれ、修正した箇所は以下の辺り

ng-appにmoduleを設定しましょう

<html lang="ja" ng-app="sample">
・・・
<script src="//code.angularjs.org/1.0.6/angular-resource.min.js"></script>
var app = angular.module("sample", ["ngResource"]);

ng-appにmoduleを設定することで、angularの中にControllerなどが作れるようになりました
名前空間も汚染しないし、良い感じです
ngResourceも使うようになったので、jsの読み込みも増えています


controllerはcontroller関数で設定しましょう

app.controller("MainController", function($scope, $resource){

ng-appにmoduleを設定したので、Controllerもangularの中に作ります。


categoriesの初期化にng-initはいらないかな

$scope.categories = [{"id" : "1", "name" : "野菜"}];

load時に最初のコンボボックスの初期化にng-initを使っていたのだけど、普通に一番上に書いておけば良いみたい


itemsとentryにはngResourceを使うと便利

var List = $resource("/item/list");
var Entry = $resource("/store/entry");
・・・
$scope.items = List.query({id : $scope.entryForm.categoryid}, function(){
・・・
Entry.save($scope.entryForm, function(){

Server側をREST APIの形にすると、もっと便利らしいのだけど、今はこんな感じに
$httpを使っていた時より、シンプルになって良いです


と今の段階だと、この程度ですが、まだまだ機能があるようで、勉強が必要です
アドバイスしてもらった内容で、まだ分かってないこともあるので、その辺りから攻めなきゃ


色々とアドバイスしてくださった上に、pull requestまで送っていただいたTessei Yoshidaさんありがとうございました!