ナカザンドットネット

それって私の感想ですよね

Code SchoolのAngularJS入門がとても良かった

Ionicを勉強する機会があったので、基礎学習として元になっているAngularJSについても勉強してみました。

色々探してみて、最終的に公式サイトのメニューからたどり着いたのがCode Schoolのチュートリアルです。

www.codeschool.com

Code Schoolを利用したのは今回が初めてでしたが、動画レクチャーとハンズオンを交互に行うスタイルはインプットとアウトプットのイテレーションを素早く回せてよいですね。

また、授業の内容も上手に組み立てられていたように思います。一歩ずつ丁寧に説明してくれるので、頭の中にブラックボックスを作らずに理解を積み重ねていくことができました。特にありがたかった点は、一度たりとも$scopeが登場しなかったところです。

$scopeは使わなければならないのか?

AngularJS関連の記事を見ていると、とにかくそこら中に$scopeが出てきます。なんだこれはおまじないかと思うくらいに出てきます。

本当におまじないならひとまず無視して先に進めるのもアリなのですが、こいつの場合はコントローラとテンプレートの間のデータや挙動を共有するのに使われるので頭から追い出すわけにもいかず、初心者からすると魔法の箱にしか見えない感じの理解に落ち着いてしまいます。

グローバル変数への憎しみを持つ人間としては、得体の知れない同じ名前の場所に複数のコントローラから値を突っ込んでテンプレート側で取り出すなんて操作を行うのを強要されるのは、正直苦痛なのです。

ちょっと前までは、僕の中でのAngularJSのイメージは下記のような感じでした。

// app.js
angular.module('gemStore', [])
.controller('StoreController', function($scope) {
  $scope.product = { name: 'Azurite', price: 2.95 };
});
<!-- index.html -->
<body ng-controller="StoreController">
  <div class="product row">
    <h3>
      {{product.name}}
      <em class="pull-right">{{product.price}}</em>
    </h3>
  </div>
</body>

そのproductはどこから出てきたんだよ・・・・!!!!という感じですね。魔法っぽさMAXです。

しかし、Shaping up with Angular.jsでは下記のような形でチュートリアルを進めていくのです。

// app.js
angular.module('gemStore', [])
.controller('StoreController', function() {
  this.product = { name: 'Azurite', price: 2.95 };
});
<!-- index.html -->
<body ng-controller="StoreController as store">
  <div class="product row">
    <h3>
      {{store.product.name}}
      <em class="pull-right">{{store.product.price}}</em>
    </h3>
  </div>
</body>

あ、productStoreControllerに入っていたものを別名のstoreを通じて取り出したんだね。コントローラ側のthisとテンプレート側のstoreが同じものなんだね。わかりやすいね!

この"Controller As"と呼ばれる記法は、AngularJS 1.2で追加されたものだそうです。

えっ、$scope要らんやん。なんでみんな$scope使うん?

と思ってググったりリプもらったりした結果、やっぱり$scopeを使うべき場所というのはかなり減ってきている印象を受けました。

qiita.com

qiita.com

近い未来に現れるであろうAngular 2では$scopeは無くなるとのことですし、$scopeを使うやり方には慣れ親しまないほうがよさそうです。*1

バッドプラクティスを身につけずに済んだよ! ありがとうCode School! ありがとうGregg!

余談: IonicでハマったAngularJSの話

その後、Ionicの練習を始めてハマった点を紹介します。

その1: controllerしか指定できないところでController Asを使いたい

$ ionic start myApp tabs

上記のコマンドでIonicプロジェクトを作成すると、app.js内に下記のようなコードが生成されます。

$stateProvider
...
.state('tab.account', {
  url: '/account',
  views: {
    'tab-account': {
      templateUrl: 'templates/tab-account.html',
      controller: 'AccountCtrl'
      // controllerAs: 'account' <= これは指定できない????
    }
  }
})

Code Schoolのチュートリアルでは、controllerを指定した直後にcontrollerAsを指定する感じで中盤以降の話題が進んでいきます。

しかしリファレンスを見ると、残念ながらviewsオブジェクトにはcontrollerAsがありません。

これにはだいぶ悩まされましたが、最終的には下記の形でOKでした。

$stateProvider
...
.state('tab.account', {
  url: '/account',
  views: {
    'tab-account': {
      templateUrl: 'templates/tab-account.html',
      controller: 'AccountCtrl as account'
    }
  }
})

ng-controllerで似たようなことやってましたね。初心に帰れ的なやつでした。。。

その2: $IonicModalを使うと$scopeから逃げきれない

ionicframework.com

上記の公式チュートリアルではTodoアプリを作っていくのですが、タスクの作成にモーダルを用いています。こいつがちょっと厄介です。

$IonicModalリファレンスから、サンプルコードを一部抜粋します。

$ionicModal.fromTemplateUrl('my-modal.html', {
  scope: $scope, // <= 置き換え不可能
  animation: 'slide-in-up'
}).then(function(modal) {
  $scope.modal = modal; // <= Controller Asを利用すれば$scopeをthisに置き換え可能
});

$scopeの利用を強要してくるAPIつらいな・・・?

どうにかしてthis方面の何かに置き換えられないかと色々調べてみたのですが、StackOverflowで見つけた一番信憑性ありそうな回答がこれ↓でした。

stackoverflow.com

In order to access the $new() function that AngularJs provides to create child scopes, you need to provide an AngularJs $scope object

内部で$scopeをちゃんと使っちゃってるっぽいです。大人しく$scopeを使うか、そもそも$IonicModalを使わない設計にするかでしか解決できなさそうな問題でした。

まとめ

  • Code SchoolのShaping up with Angular.jsめっちゃよかった
  • $scopeは基本的に使わないほうがよさそう
  • IonicのAPIとかSampleがAngularJS初心者につらいときある

AngularJSとIonicの基本操作は分かってきたので、そろそろTypeScriptでやりたい気持ちが高まってきてます。

簡単なアプリ作って、モバイルアプリのプロトタイピング力を高めていきたいです。まる。

Full Stack Mobile App with Ionic Framework (English Edition)

Full Stack Mobile App with Ionic Framework (English Edition)

*1:$scopeを使わないとできないこともあるみたいなので、完全に使わないわけにもいかないでしょうけれども。