HOME > 開発者向けBLOG > Sencha Blog >  Ext JS 5 アプリでルーティングを使うには

Technology Note 開発者向けBLOG

Sencha Blog

Ext JS 5 アプリでルーティングを使うには

こんにちは、ゼノフィnakamuraです。

この記事は、US Sencha社ブログ How to Use Routing in Your Ext JS 5 Apps を翻訳したものです。

はじめに

Ext JS 5 は、豊富なエンタプライズ品質の Web アプリケーションを生成するために、たくさんの新しい機能を提供しているリリースです。MVVM と双方向データバインディングは、開発者の代わりにたくさんの労働作業を行います。Ext JS 5 のもう一つの新しい機能はルーティングで、これがあるとコントローラー内でヒストリーを管理するのが簡単になります。全てのブラウザの UI で「進む」「戻る」ボタンは通常ある部分なので、SPA でこのナビゲーションを管理するのは Ext JS 5 のお陰でとても簡単になりました。

Ext JS 5 ルーティング

Ext JS は、Ext.util.History クラスでヒストリーの変更は管理できていましたが、Ext JS 5 では、この処理をより簡単で柔軟にしました。ルーターは、ルート実行のフローを管理するためにアクションの前にパラメータがあって、裏で Ext.util.History を利用し、コントローラーメソッドにハッシュトークンをマッピングすることを簡単に構成することができます。簡単なサンプルをご覧ください。

    Ext.define('MyApp.controller.Main', {
        extend : 'Ext.app.Controller',
 
        routes : {
            'home' : 'onHome'
        },
 
        onHome : function() {}
    });

routes オブジェクトの、キー(‘home’)は一致するハッシュで、値(‘onHome’)は、ハッシュが一致(例えば、http://localhost#home)したらコントローラーが実行するメソッド名です。コントローラー内でハッシュを変更するには、redirectTo メソッドを使います。

this.redirectTo('home'); //redirects to http://localhost#home

これで URL ハッシュが #home に変わりますので、ルートを構成した MyApp.controller.Main コントローラーのインスタンスにスコープされた onHome メソッドを実行します。もし同じハッシュトークンと一致する複数のコントローラーがある場合には、実行する順番は Application インスタンスで定義されている controllers 配列の順番となります。

ハッシュトークンとパラメータ

ハッシュトークンはパラメータも含むことが出来て、ルーターは引数としてコントローラーメソッドに渡しますので、簡単に扱えます。パラメータ付きのハッシュは ‘#user/1234’ のようになります。この場合 1234 はユーザーIDですから、パラメータとして扱うべきです。次のようにコントローラーはハッシュをリッスンするように構成できます。

    Ext.define(‘MyApp.controller.Main', {
        extend : 'Ext.app.Controller',
 
        routes : {
            'user/:id' : 'onUser'
        },
 
        onUser : function(id) {}
    });

パラメータを要求するようにルートを構成する時、パラメータの名の前に「:」をつけます。この場合では :id がパラメータとなります。ルーターはパラメータとして渡された値と一致したと見なし、このパラメータを onUser メソッドに渡します。コントローラーメソッドに渡される引数の順番は、routes コンフィグで定義された順番と同じです。

通常の表現に基づいて、ハッシュのパラメータの一致を管理することもできます。ユーザー ID の例では、ID は数字に限られて、他の値は一致されないはずです。この一致を管理するために、routes の conditions コンフィグを使います。

    Ext.define('Fiddle.controller.Main', {
        extend : 'Ext.app.Controller',
 
        routes : {
            'user/:id' : {
                action     : 'onUser',
                conditions : {
                    ':id' : '([0-9]+)'
                }
            }
        },
 
        onUser : function(id) {}
    });

このサンプルでは二つのことを紹介しています。ルートにはオブジェクトをセットすることもできて、その場合は action キーがコントローラーメソッドで conditions コンフィグを使います。conditions コンフィグはパラメーター名と正規表現文字列のオブジェクトです。実際の正規表現ではなく、正規表現の文字列になっている理由は、ルーターはルート内のパラメータに基づいてマスターの正規表現を生成し、conditions コンフィグがデフォルトで使われるマッチング正規表現文字列をオーバーライドすることを可能とします。デフォルトのパラメータの正規表現文字列は ‘([%a-zA-Z0-9\\-\\_\\s,]+)’ です。

ハッシュを一致するルートが設定されてないということが起こると、アプリケーションで unmatchedroute イベントが発火します。このイベントはアプリケーションまたはコントローラーで同じ方法でリッスンできます。次はコントローラーでリッスンするサンプルです:

    Ext.define('Fiddle.controller.Main', {
        extend : 'Ext.app.Controller',
 
        listen : {
            controller : {
                '*' : {
                    unmatchedroute : 'onUnmatchedRoute'
                }
            }
        },
 
        onUnmatchedRoute : function(hash) {}
    });

ルートの実行プロセスにフックを入れて、処理を中断したり、Ajax リクエストなどの非同期処理を待つ、といったことをしたいことはよくあります。 これを実現するために、ルートには before アクションを設定できます。before アクションには、ルートに構成されたパラメータが渡されます。次は Ajax のリクエストを使ってリクエストが完了した後にルートの処理を継続するサンプルです。

    Ext.define('Fiddle.controller.Main', {
        extend : 'Ext.app.Controller',
 
        routes : {
            'user/:id' : {
                action     : 'onUser',
                before     : 'beforeUser',
                conditions : {
                    ':id' : '([0-9]+)'
                }
            }
        },
 
        beforeUser : function(id, action) {
            Ext.Ajax.request({
                url     : '/user/confirm',
                params  : {
                    userid : id
                },
                success : function() {
                    action.resume();
                },
                failure : function() {
                    action.stop();
                }
            });
        },
 
        onUser : function(id) {}
    });

beforeUser メソッドは、onUser メソッドと同様 id パラメータを受け取りますが、引数 action も受け取ります。action 引数はオブジェクトでルートの実行を管理する resumestop メソッドがあります。 Ext.Ajax.requestsuccess ハンドラーでやっているように action.resume(); を実行するとルートの実行を再開します。このため、ルートは非同期になれます。failure コールバックにある action.stop(); メソッドを実行すると、現在のルートの実行を止めます。もし stop メソッドに true が渡された場合、全ての順番待ちのルートの実行が停止され、ルートを完全に管理できます。

Ext JS アプリケーションは大きく、複雑になり、同時に複数のハッシュトークンがアクティブであることが必要となるかもしれません。Ext JS 5 は、複数のハッシュトークンを管理できて、それぞれ個別で実行できます。個別のトークンはサンドボックスになります。このため、もし action.resume メソッドに true を渡し、一つのルートをキャンセルしたら、そのハッシュトークンの他のルートだけ止めます。他のハッシュトークンの実行は続きます。各トークンはパイプ記号 “|” で繋げます。 ハッシュの例は次のようになります:

#user/1234|message/5ga

ルーターはこのハッシュを ‘user/1234’‘message/5ga’ に分けます。 ルーターはまず user トークンから始めて、そのトークンに一致するルートを全て発見し、一致したルートを実行させます。 トークンにルートが一致しなかった場合、unmatchedroute イベントが発火します。 ルーターは次に message トークンに進み、全ての一致するルートを発見し、実行させます。 また、トークンにルートは一致しなかった場合、unmatchedroute イベントが発火します。

まとめ

Ext JS 5 の新しいルーターは、コンフィグで簡単にブラウザヒストリーのスタックを処理でき、複雑なアプリケーションの需要に対応できる柔軟性と力があります。 MVC + VM、双方データバインディングなどの新しい機能と合わせて、Ext JS 5 はエンタプライズ アプリケーションに向けの完璧なフレームワークとなります。

PAGETOP