Works by

Ren's blog

@rennnosuke_rk 技術ブログです

YEOMANでAngularJSプロジェクトにControllerを追加する

メモ。 YEOMANでジェネレータgenerate-angularをインストールしている場合、
以下のコマンドでControllerの作成も自動でやってくれます。

# 生成したいプロジェクトディレクトリ上で実行
$ yo angular:controller MyNewController 
# 生成
create app/scripts/controllers/mynewcontroller.js
create test/spec/controllers/mynewcontroller.js

ただし、controllerを作成するためには予めyo generate-angularでAngularJS用リポジトリを作成しておく必要があります。

.
├── README.md
├── app
│   ├── 404.html
│   ├── favicon.ico
│   ├── images
│   │   └── yeoman.png
│   ├── index.html
│   ├── robots.txt
│   ├── scripts
│   │   ├── app.js
│   │   └── controllers
│   │       └── main.js
│   ├── styles
│   │   └── main.scss
│   └── views
│       └── main.html
├── bower.json
├── gulpfile.js
├── package.json
└── test
    └── spec
        └── controllers
            └── main.js

YEOMANを使って高速にAngularJSプロジェクトを作る

YEOMANとは

http://cdn-ak.f.st-hatena.com/images/fotolife/w/watass/20150620/20150620165606.png

YEOMANはWebアプリケーションジェネレータと呼ばれるツールの一つです。
新しいアプリケーションを作成する際に必要なディレクトリやコンポーネントを自動作成することができます。

Web開発を始める時、プロジェクトのディレクトリ構成やツールの導入の仕方で迷うことはよくあると思いますが、 YEOMANを使うことで、構成に迷うことなくプロジェクトをすぐに立ち上げることができます。

またYEOMANのディレクトリ構成がある種のスタンダードになりつつあるようなので、
既にあるプロジェクトにもYEOMANの構成を取り入れてみる、というのもありだと思います。

YEOMANを使ってみる

さっそくYEOMANを使ってみましょう。

環境はMac OS Xです。
Windowsの方はPowerSHellかcmderでお願いします。。。

先ずはnpmを使い、コマンドツールyoをインストールします。

$ npm install -g yo 

このyoコマンドを使って、以降プロジェクトのテンプレート作成等を行っていきます。

yoをインストールしたら、次はWebアプリケーションジェネレータをインストールします。

$ npm install -g generator-[webapp]

[webapp]の箇所には作成したいWebアプリケーションのジェネレータ名が入ります。
インストールできるジェネレータ一覧はこちら -> Generator

ジェネレータ一覧を見るとフレームワークの名前がちらほらと見えるので、
自分の作成したいWebアプリケーションで使うフレームワーク用ジェネレータを入れていきましょう。

今回はAngularJSのジェネレータをインストールしていきます。

$npm install -g generator-webapp

次に、プロジェクトのテンプレートを作成したいディレクトリに移動し、
以下のyoコマンドを実行。

# ディレクトリ移動
$ cd yoman
# テンプレート作成
$ yo angular

初めてyoコマンドを実行する場合、匿名レポート提出許可のオプションが出てくると思いますがこちらはお好みでYまたはnを入力。

? ==========================================================================
We're constantly looking for ways to make yo better! 
May we anonymously report usage statistics to improve the tool over time? 
More info: https://github.com/yeoman/insight & http://yeoman.io
========================================================================== (Y/n) 

次におじさんAAが出てきます。
同時に「Gruntの代わりにGulp使う?」と聞いてきますが、ここではyを入力。

     _-----_     
    |       |    ╭──────────────────────────╮
    |--(o)--|    │    Welcome to Yeoman,    │
   `---------´   │   ladies and gentlemen!  │
    ( _´U`_ )    ╰──────────────────────────╯
    /___A___\   /
     |  ~  |     
   __'.___.'__   
 ´   `  |° ´ Y ` 

Out of the box I include Bootstrap and some AngularJS recommended modules.

? Would you like to use Gulp (experimental) instead of Grunt? Yes

ちなみにこのGruntおよび Gulpはタスクランナーと呼ばれるツールで、
Webアプリケーションの様々な処理をタスクという単位で自動実行するのに使います。

その後もYesを入力していきます。

# Sass : コンパイルするとcssになるスクリプト(Yes)
? Would you like to use Sass? Yes

# Bootstrap : イケてる鉄板CSSライブラリ(Yes)
? Would you like to include Bootstrap? Yes

# angular用ライブラリ群(Yes)
? Which modules would you like to include? 
angular-animate.js, 
angular-cookies.js, 
angular-resource.js, 
angular-route.js,
angular-sanitize.js,
angular-touch.js

最後に導入したいライブラリを選択してEnterを押すとプロジェクトの生成が開始されます。

.
├── README.md
├── app
│   ├── 404.html
│   ├── favicon.ico
│   ├── images
│   │   └── yeoman.png
│   ├── index.html
│   ├── robots.txt
│   ├── scripts
│   │   ├── app.js
│   │   └── controllers
│   │       └── main.js
│   ├── styles
│   │   └── main.scss
│   └── views
│       └── main.html
├── bower.json
├── gulpfile.js
├── package.json
└── test
    └── spec
        └── controllers
            └── main.js

AngularJS Webアプリケーションプロジェクトのテンプレートができました!


YEOMANを使えば、新しいフレームワークを試したいときにも簡単に開発を始めることができそうですね。
またテンプレート作成時に導入されるツールの種類から「このフレームワークにはこういうツールを導入すると良いのかも」というように、必要なWeb開発ツールについて新しい示唆を得ることもできそうです。

【AngularJS】ルーティングを設定する

AngularJSはSPAを実装するフレームワークであるため、単一のページを読み込んだ後にクライアント側で柔軟に表示を切り替えていく機能を備えています。

AngularJSでは$routeProviderを使うことによって、リクエストURL別にコントローラーやテンプレートを切り替えることができます。

ルーティングを設定

ルーティングの設定はconfigメソッドを使ってやっていきます。
configメソッドはAngularJSアプリケーションの前処理(configフェーズ)を記述するために使われます。

なお、configフェーズではServiceのインスタンスが生成されません。

// ルーティング情報を記述
angular.module('App')
.config(function($routeProvider) {
  $routeProvider
    .when('/', {
      templateUrl: '../../views/index.html',
      controller: 'MainController'
    })
    .when('/hoge', {
      templateUrl: '../../views/hoge.html',
      controller: 'HogeController'
      controllerAs: 'HogeCtrl'
      resolve: {
        currentHoge: 'currentHoge' 
      }
    })
    .otherwise({
      redirectTo: '/'
    });
  }]);

$routeProviderwhenメソッドを呼び出し、リクエストURLと対応するHTMLファイル、Controllerなどを登録していきます。

パラメータ

templateUrl

パスが入力されたときに表示するHTMLテンプレートファイルです。

controller

表示するHTMLテンプレートファイルに対応するControllerです。

controllerAs

Controllerの別変数名を設定できます。Controllerの持つ変数時などに、この変数を使うことができます。

resolve

Promiseオブジェクトを返戻するサービス名を指定すると、 サービス内の全てのPromiseに対してresolveが呼ばれたときに、Promiseの値を注入します。


そのほか、下記のパラメータを設定できます。

  • template : 文字列としてテンプレートを設定する
  • redirectTo : リダイレクト先を設定する
  • reloadOnSear : $location.search/hashが変更された時、設定したルーティング先を再読込するかどうか
  • caseInsentiveMatch : ルーティング先の大文字/小文字を区別する

【AngularJS】Controller間で共有可能な値を定義する

AngularJSでは、Controller間で共有可能な値を定義する方法が二通りあります。

  • value
  • constant

value

valueメソッドを使うことで、Controller間で共有できる値を定義することができます。
定義した値はControllerの引数に設定することで使用可能になります。
FactoryやService内でも同様にして利用可能です。

// 値の定義
angular.module('MyApp',[])
  .value("hogeStr", "hogehoge")
  .value("nHoge", 123)
  .value("isHoge", true)
  .value("hogeObj", {"hoge" : "1", "fuga" : "2"});

// 使用時はControllerの引数に渡す
angular.module('MyApp')
  .controller('MyController', [
    '$scope',
    'hogeStr',
    'nHoge',
    'isHoge',
    'hogeObj',
    function($scope, hogeStr, nHoge, isHoge, hogeObj) {
      console.log(hogeStr);  // hogehoge
      console.log(nHoge);    // 123
      console.log(isHoge);   //  true
      console.log(hogeObj); // {hoge: "1", fuga: "2"}
  }]);

constant

valueメソッド同様に、constantメソッドを使っても共有変数を定義することができます。

// 結果はvalueと同じ
angular.module('MyApp',[])
  .constant("hogeStr", "hogehoge")
  .constant("nHoge", 123)
  .constant("isHoge", true)
  .constant("hogeObj", {"hoge" : "1", "fuga" : "2"})
  .controller('MyController', [
    '$scope',
    'hogeStr',
    'nHoge',
    'isHoge',
    'hogeObj',
    function($scope, hogeStr, nHoge, isHoge, hogeObj) {
      console.log(hogeStr);   // hogehoge
      console.log(nHoge);      // 123
      console.log(isHoge);     //  true
      console.log(hogeObj);  //  {hoge: "1", fuga: "2"}
  }]);

valueとconstantの違い

話が飛びますが、AngularJSはアプリケーションを実行する際configrunと呼ばれる二つの工程を経由します。

configフェーズではangular.configメソッドを用い、Providerと呼ばれるモジュールの設定変更を行います。 (Providerはサービスの挙動を変更するために用いられます)

configフェーズではまだサービスがインスタンス化されていない状態なので、サービスを機能を利用することができません。 valueもサービスの一種であるため、configフェーズでは使うことはできません。
一方でconstantもサービスの一種なのですが、例外的にconfig内で使用することができます。

そのためconfigフェーズで共有変数を利用したい場合は、必然的にconstantを利用することになります。

じゃあvalueは使う意味ないじゃないかと思うかもしれませんが、
「constantはconfigフェーズでのみ利用する」「valueはrunフェーズ以降で利用する」のように、
各メソッドに意味を与えつつ使い分けるというやり方が可能です。


やっぱりconstantだけで良い気がしてきた

参考文献

プロバイダーについて | AngularJS 1.2 日本語リファレンス | js STUDIO

【AngularJS】AngularJSで動的にイベントハンドラを定義する

AngularJSのモジュールを使い、動的にイベントハンドラーを追加する方法メモ。

// controller
angular.module('myApp',[])
  .controller('myController',[
    '$window',
    function($window){

      // 画面全体に対するクリックリスナー
      angular.element($window).bind('click', function(){
        console.log('click...');
      });

      // スクロールリスナー
      angular.element($window).bind('scroll', function(){
        console.log('scrolling...');
      });

      // 組み込みの要素参照を使っても定義可能
      angular.element(document.getElementById('hoge')).bind('click', function(){
        console.log('click...');
      });

    }
  ]);

上記コードでは、windowオブジェクトに対してクリックイベントやスクロールイベントのリスナーを登録しています。

$window

AngularJS 1.2 日本語リファレンス | js STUDIOより

ブラウザのwindowオブジェクトを参照します。

JavaScript組み込みオブジェクトでもあるwindowへの参照をもつ、Angularの変数。

angular.element

素のDOM要素、またはHTML文字列をjQuery要素としてラップします。 もし、jQueryが利用可能であれば、angular.elementはjQuery関数へのエイリアスになります。 そうでなければ、angular.elementは、"jQuery lite"また は"jqLite"と呼ばれる、 Angular組み込みのjQueryのサブセットに委譲します。

JQueryが使える環境であれば、JQueryのラッパーになるようです。
使えない環境でもAngularJSに組み込まれている軽量なDOM操作ライブラリを使ってくれる模様。

angular.element.bind

要素に任意のイベントで実行させたい関数を紐づけます。

JQueryで書く場合

$('window').on('click', function(){
    console.log("click...");
);

$('window').on('scroll', function(){
    console.log("click...");
);

参考文献

angular.element | AngularJS 1.2 日本語リファレンス | js STUDIO

【AngularJS】Viewにhtml文字列を挿入、htmlとしてレンダリングする

AngularJSを使ったフロント開発の中で、技術記事のAPIで取得したHTMLを画面に表示させたくなった ときの処理をメモ。

ng-bind-htmlでViewにhtml文字列をサニタイズされた形で挿入できます。

View
<!-- article.bodyプロパティにはHTMLが入っている-->
<div ng-bind-html="article.body"></div>
    // APIで記事を取得
      articleService.getArticle().then(function(response) {
        // 記事情報
        $scope.selectedArticle = response.data;
      });
    };
実行結果

f:id:rennnosukesann:20180311235625p:plain


実際にはQiitaAPIを叩いてMarkdownをHTMLに変換して、マテリアルデザインにして・・・とか色々やっているのですが割愛。 ちゃんとHTMLの文章を挿入することができました。

ちなみにHTMLを普通の文字列としてViewに挿入する場合はng-bindで可能。

参考文献

AngularJS アプリケーションプログラミング

【AngularJS】既存のServiceを拡張した派生Serviceを定義する

AngularJSで既存のServiceが持つ機能を拡張させたServiceを定義したかったので、
以下のようにしてServiceを派生させてみました。

Service定義
"use strict";

// 基底Service(factory形式)
angular.module('App')
  .factory('baseService',[
    function(){
      let service = {
        hoge: function(){
          return 'hoge';
        }
      };
    return service;
  }]);

// 派生Service
angular.module('App')
  .factory('childService', [
    'baseService',
    function(baseService){
      let service = {
        hoge: function(){
          return 'hogehoge';
        },
        fuga: function(){
          return 'fuga';
        }
      };
      // 二つのサービスを結合(基底サービスと一致するプロパティがある場合上書き)
      return Object.assign(Object.assign({}, baseService), service);
  }]);
実行
"use strict";

angular.module('App', [])
.controller('MainController', [
  'childService',
  function(childService) {

  console.log(childService.hoge());
  console.log(childService.fuga());

}]);
実行結果
hogehoge
fuga


いわゆるコンポジット(プロパティではないので多分違いますが)のような形に落ち着きました。

派生Service内の実行関数の引数として基底Serviceをとり、基底Serviceで定義したserviceオブジェクトと、 派生Serviceで定義したserviceオブジェクトを結合しています。
両者が同じプロパティを保つ場合、派生側で上書きされるようにしました。

両者は継承関係にあるとは言えないので、派生という言い方も微妙かもしれません。。。