SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

AngularJSではじめるJavaScriptフレームワーク開発スタイル

ビジネスロジック記述の必須知識、AngularJSの「サービス機能」を理解しよう

AngularJSで初めるJavaScriptフレームワーク開発スタイル 第4回


  • X ポスト
  • このエントリーをはてなブックマークに追加

サービスの登録方法

 続いて、実際にサービスを作成していきます。サービスを登録するには表1で示すように5つのメソッドが用意されています。しかし、これらの違いを内部から理解することは難しく、当初はあまり違いに意識せずに利用してみてください。

表1:サービスの主な利用用途
メソッド名 説明
provider(name,function/object) 最も多機能で複雑なサービスの登録方法。他の登録方法の基本的実装。
factory(name,function) サービスを作成するための関数を登録。一般的に利用される。
service(name,constructor) サービスを作成するコンストラクタを登録。サービスがクラスの場合にfactoryより簡潔に記述できる。
value(name,value/object) 値やオブジェクトを設定。DIによる他のサービスが利用できない。また、構成フェーズ(サービスの設定)では利用できない。
constant(name,value/object) 値やオブジェクトを設定。DIによる他のサービスが利用できない。valueと異なり、構成フェーズでも利用できる。

 ビジネスロジックとしてサービスを登録するには、factoryもしくはserviceメソッドを使えば多くの場合には問題がないでしょう。また、単純な値やオブジェクトであるならば、valueメソッドで問題ありません。providerメソッドやconstantメソッドは、サービスを作成する際に設定等が行える構成フェーズというフェーズがありますが、そこで作成するサービスの設定等が行えます。しかし、通常の利用ではこれらのメソッドが不可欠になることはあまりありません。

自作のサービスを登録する

 実際のサービスの登録は、リスト1のようにすることができます。

リスト1:factory/serviceメソッドを使ったサービスの登録方法
(function(module){
    module.factory('Items',function($rootScope){   //(1)サービスの登録
        return new app.ArrayItems($rootScope);     //(2)実際のサービスの本体
    });
    // module.service('Items',['$rootScope',app.ArrayItems]);  //(3)serviceメソッドを使った場合
}(TodoModule));

 factoryメソッドの第一引数には登録するサービス名を指定します(1)。このサービス名は、DI機能(依存性注入)を使ってコントローラや他のサービスで利用します。サンプルアプリケーションで作成するサービスは、$rootScope(ルートスコープの説明は前回を参照)を利用します。続いて、returnで実際に作成したサービスオブジェクトのインスタンスを作成して返します(2)。

 また、このようにクラスからのインスタンス作成のみの場合には、(3)のようにserviceメソッドを使っても同じ事ができます。

 DIでの依存サービスの指定方法には配列を使った指定方法があります(「DIでの依存サービスの指定方法」を参照)。

 今回は、コンストラクタ時に引数が必要なために、この配列を使った記述を指定しています。

DIでの依存サービスの指定方法

 コントローラやサービスの作成時に依存するサービスの記述は、これまで紹介してきた(1)の方法とは別に(2)のような方法もあります。

module.factory('Foo',function($http){ .... });                 //(1)
module.factory('Foo',['$http',function($http){ .... });        //(2)

 (2)の記述では、配列を利用して依存するサービスを文字列で指定し、配列の最後にこれまでと同様に処理の記述をする方法があります。これはJavaScriptのミニマイズ処理時で問題を起こさないようにするための対応です。ミニマイズ処理では変数名が短く変更されてしまうこともあるため、引数に指定した変数名がDIの指定として使えなくなります。そのため、依存サービスを文字列として指定できるようになっています。

 また、(2)でのfunctionの引数名は、これまでと同じようなわかりやすさのために合わせてありますが動作上は関係がなく、実行時に渡される引数はその前に指定した配列での順番となります。

サービスを作る

 続いてサービスの中身を作ります。サービスには大きく分けて2つの機能があります。

 ひとつは、詳細を表示する際に一覧からどのタスクが選択されたかを管理するためにコントローラ間でのデータ共有する機能、もうひとつはタスクの取得・追加・削除をするための機能です。これらのメソッドは図4に示すように、6つのメソッドを持ちます。

図4:Itemsサービスのメソッド
図4:Itemsサービスのメソッド
リスト2:ArrayItemsのソース抜粋
(function(app){
    var ArrayItems = function($scope){  //(1)依存するサービスを引数に指定
        this.init($scope);
    };
    var p = ArrayItems.prototype;
    p.init = function($scope){  //(2)依存するサービスを保存
        this.$scope = $scope;
        this.items = new Array();
        this.serial = 0;       //(3)各タスクに識別用のシーケンス
    };
    p.setCurrentItem = function(item){ //(4)選択されたアイテムを保存する
        this.current = item;
    };
    p.getCurrentItem = function(){  //(5)選択されたアイテムを取得する
        return this.current;
    };
    p.list = function(callback){  //(6)タスクの一覧を取得するメソッド
        callback.call(this,this.items);
    };
    p.add = function(item, callback){  //(7)タスクを追加するメソッド
        this.serial++;
        item.id = "id_" + this.serial;  //(8)タスクにIDを付与
        var $scope = this.$scope;
        this.items.push(item);          //(9)タスクを保存
        // : (省略)
    };
    p.remove = function(item,callback){  //(10)タスクを削除するメソッド
        var id = item.id;
        var tmp = new Array();
        for(var i = 0; i < this.items.length; i++){
            if(item.id != this.items[i].id){
                tmp.push(this.items[i]);
            }
        }
        this.items = tmp;                //(11)削除したタスクを除いたリストで更新
        //(省略)
    };
    app.ArrayItems = ArrayItems;
}(this.app));

 コンストラクタでは、先ほどのサービスの登録時に指定したサービスを受け取ります(1)。内部での初期化処理であるinitメソッドを使って、thisに対してサービスを登録します(2)。(3)では内部でタスクを管理する為のIDを作成する為のシーケンス番号用の変数を初期化します。このIDは保存時に(8)のように使用します。(4)では選択されたタスクを保存、(5)でその保存されたタスクを取得できるようにします。(6)、(7)、(10)では管理しているタスクデータに対して一覧、追加、削除を行うようにします。

 また、実際のデータは(9)のように保存し、(11)で削除します。

作成したサービスを使う

 実際のサービスの実装が完了したところで、コントローラ内で利用します。リスト3は、一覧画面のコントローラ部分の実装です。

リスト3:controllers.jsの抜粋(タスク追加と削除の実装)
module.controller('listController',function($scope,Items) {  //(1)Itemsを指定するだけ
    //(2)一覧データを取得する
    Items.list(function(list){
        $scope.items = list;
    });
    //(3)一覧からクリックされた時の処理(詳細ページに遷移)
    $scope.show = function(item){
        Items.setCurrentItem(item);
        $scope.$parent.changePage('info');
    };
    //(4)一覧データ変わったときには、再度一覧データを取得し直す
    $scope.$on('changeItems',function(){
        Items.list(function(list){
            $scope.items = list;
        });
    });
});

 作成したItemsサービスの使用は、(1)のように引数内にItemsを指定するだけで可能です。まず、(2)ではこのコントローラが初めて実行された時に一覧データを取得しておきます。(3)は一覧で各タスクがクリックされた時の処理ですが、setCurrentItemメソッドを使ってクリックされたタスクを覚えておきます。実際に詳細ページに遷移した時にはgetCurrentItemメソッドを使ったそのタスクデータを取得します。このようにして、サービスでは各コントローラ間でデータを共有できます。また、(4)ではItemsサービス側でタスク追加、もしくは削除された時のイベントを取得し、再度一覧データを取得し直しています。

次のページ
HTML上のフォームの扱い

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
AngularJSではじめるJavaScriptフレームワーク開発スタイル連載記事一覧

もっと読む

この記事の著者

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

WINGSプロジェクト 小林 昌弘(コバヤシ マサヒロ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/8377 2015/01/23 19:06

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング