注目の記事

AngularJS コードの構造化

2013.12.17

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

angularjs125title

複数人で AngularJS を利用した Web アプリケーションを構築するときに必要なルールをまとめてみました。
( あくまで策定中のルールであり、今後も改変する可能性があります。また、ベストプラクティスを謳うものではありません )

使用 AngularJS のバージョン

  • angular.js 1.2.5
  • angular-route.js 1.2.5

参考サイト

ナナメ読みした参考書籍

いずれも 1.2 系以前のバージョンで書かれていますが、基本的なことを抑えるスタートアップ書籍としては十分かと思います。

Application HTML

アプリケーションの基盤となる HTML です。 HTML タグの ng-app 属性にアプリケーション名を設定して、アプリケーションとして展開される領域に単一の ng-view 属性を設定します。アプリケーション内の画面遷移や UI の表示切替といった機能は、angular-route.js のサービスである $routeProvider を使用します。ディレクトリ構造はアプリケーションの要件によって変化すると思われるので、当記事では割愛します。

index.html

<!DOCTYPE html>
<html ng-app='testApp'>
<head>
<script src='//ajax.googleapis.com/ajax/libs/angularjs/1.2.5/angular.js'></script>
<script src='//ajax.googleapis.com/ajax/libs/angularjs/1.2.5/angular-route.js'></script>
<script src='app/app.js'></script>
<script src='service/hogeService.js'></script>
<script src='filter/hogeFilter.js'></script>
<script src='controller/HogeController.js'></script>
<script src='controller/FugaController.js'></script>
<script src='directives/cmHogeDirective.js'></script>
<link rel='stylesheet' href='view/styles.css' />
<title>Structuring AngularJS Code</title>
</head>
<body>
<header><h1>Sample</h1></header>
<div ng-view></div>
<footer></footer>
</body>
</html>

Application JS

アプリケーション本体の JS です。ネームスペースを示すグローバルオブジェクトを用意して、任意のプロパティにアプリケーションのモジュールの参照を代入します。モジュールの作成には angular#module メソッドを使用します。前述の $routeProvider を使用して、各画面の URL に対する View(templeteUrl) と Controller(controller) のペアを定義します。

app.js

'use strict';
var ns = ns || {};
ns.App = angular.module('testApp', ['ngRoute'], function($routeProvider) {
$routeProvider
.when('/hoge/',{ controller: 'HogeController', templateUrl: 'view/HogeView.html' })
.when('/fuga/',{ controller: 'FugaController', templateUrl: 'view/FugaView.html' });
});

匿名関数の引数 $routeProvider の名前を変更すると動作しなくなるので、minify するときには注意する必要があります。( または、このファイルのみ minify の対象から外すのもアリかもしれません )

View(templateUrl)

アプリケーションの外観を構築します。ここにはプレーンな HTML タグや AngularJS のカスタム Directive を配置します。動的に変わるパラメータは、二重の波括弧で括ったバインディング式を定義して値を渡します。この View 内部で AngularJS の $filter を用いたフィルタリング処理を実装することができますが、複数回実行される現象を確認しているため、原則 Controller で使用ことを掟とします。

HogeView.html

<h2>{{title}}</h2>
<div data-value="{{value}}"></div>

Filter

Contoroller で使用する整形ユーティリティ ( のようなもの? ) です。

以下のファイルは、引数の文字列に対して語尾に "Hoge!!" を付与して返すフィルタです。

hogeFilter.js

(function () {
    var hogeFilter = function () {
        return function (value) {
            return value + " Hoge!!";
        };
    };
    ns.App.filter('hogeFilter', hogeFilter);
}());

Controller

先述の View に値を渡したり、サービスを実行したりします。また $inject プロパティを用いて $scope, $filter, 任意のサービスなどの依存性を抽入することにより、IntelliJ IDEA ではコードヒントが有効になり、かつ、何も気にせず minify できるので、以下のような構造を保つことを掟とします。引数 $scope はペアとなる View の参照となるので必須、その他の参照は必要に応じて定義します。

HogeController.js

(function() {
    var HogeController = function($scope, $filter, hogeService) {
        $scope.title = $filter('hogeFilter')("Sample 1");
        $scope.value = hogeService.getHoge();
    };
    HogeController.$inject = ['$scope', '$filter', 'hogeService'];
    ns.App.controller('HogeController', HogeController);
}());

Service

任意の通信処理やライブラリの利用などといった特定の処理単位で用意します。似たような機能で Factory が存在しますが、使用せず Service で統一することを掟とします。

hogeService.js

(function () {
    var hogeService = function($http) {
        this.getHoge = function() {
            return 'hogehoge';
        };
    };
    hogeService.$inject = ['$http'];
    ns.App.service('hogeService', hogeService);
}());

Directive

内部で完結した独自ロジックを DOM に紐付けて部品化したいときに使用します。

  • 独自の接頭辞を付与する ( 'cmXxxxDirective' の 'cm' )
  • View から参照するときは全て小文字で各単語をハイフンで区切る
  • Controller 同様、$inject プロパティは任意
  • restrict オプションは原則 'A' ( デフォルト )
  • link オプション関数の引数 attrs プロパティの値は、Directive を使用している View を制御する Contoroller から与えられる

cmHogeDirective.js

(function () {
    var cmHogeDirective = function ($window, $timeout) {
        return {
            restrict: 'A',
            scope: {
                data: '=',
                label: '@',
                onClick: '&'
            },
            link: function(scope, ele, attrs) {
                //TODO:独立した処理
                // ex: var hoge = attrs.value;
            }
        };
    };
    cmHogeDirective.$inject = ['$window', '$timeout'];
    ns.App.directive('cmHogeDirective', cmHogeDirective);
}());

cmHogeDirective.js を View から参照するとき

<div cm-hoge-directive data-value="{{value}}"></div>

命名規則

  • View, Controller はアッパーキャメルケース
  • 上記以外はローワーキャメルケース