通常のウェブサイトでは、ユーザーはリンクをクリックしたりフォームに記入したりすることでページからページに移動します。ただし、単一ページアプリケーションでは、ユーザーが操作しても新しいページはロードされません。その代わり、単一ページ内で処理され、コンポーネントはその操作に反応します。それでは、どのようにユーザーにブラウザの [進む] や [戻る] ボタンの使用を許可するのでしょうか。その答えは、URI ハッシュ変更を Ext JS 5 の新しいルーターで消化することです。
ルーティングを使用するケース
ブラウザの履歴スタックを使用して、アプリケーションの状態を追跡するためにルーティングを使用できます。さらに、ルーティングはアプリケーションへの深いリンクも許可するため、アプリケーションの特定部分に直接リンクできます。
ルーティングを使用しないケース
データやセッションをストアするためにルーティングを使用しないでください。データはクッキーやローカルストレージなどの永続データソースにストアしてください。ルーティングはアプリケーションの状態を追跡する手段に過ぎません。
ハッシュとは
ブラウザは多くの部分から構成される URI を使用してインターネットをナビゲートします。サンプル URI を見てみましょう。
http://www.example.com/apps/users#user/1234
これは比較的馴染みがあると思います。ただし、#user=1234
は分からないかもしれません。URI のこのセクションは「ハッシュ」またはフラグメント識別子と呼ばれます。ハッシュに関する詳細は、このリソース(http://en.wikipedia.org/wiki/Fragment_identifier)をお読みください。このハッシュはアプリケーションが現在のページを再読み込みせずにブラウザの履歴スタックをコントロールする方法を提供します。ハッシュが変わると、ブラウザが URI 全体を履歴スタックに追加します。これによって、ブラウザの [進む] / [戻る] ボタンを利用して変更されたハッシュを含む URI を走査できます。例えば、ハッシュを更新した場合に何が起こるでしょうか。
http://www.example.com/apps/users#user/5678
ブラウザは hashchange
イベントを発火し、アプリケーション内で利用できるようになります。ユーザーは [戻る] ボタンをクリックして #user=1234
ハッシュに戻ることができます。この通知があると、アプリケーション内の変更に反応できます。ハッシュはサーバーに送信されないことを通知することが重要です。ハッシュは通常クライアントの URI の解釈内で消化されます。Ext Router はブラウザのハッシュ機能によって、アプリケーションの状態追跡と深いリンクを許可します。
アプリケーションでのルーティングの実装
Router クラスは MVC でのハッシュ変更の解釈をシンプルにするために作成された Ext JS 5 の新しい追加機能です。ハッシュ変更に反応するために使用できる Ext.util.History は既にありました。ただし、この Ext.util.History はより手動のプロセスが必要で、適切な Router クラスが必要でした。Router は、ビューコントローラでルートを定義することによって Ext JS 5 MVC アプリケーションとのシンプルな統合を提供します。ルートはハッシュに一致する文字列で、Ext アプリケーション内で深いリンクを許可します。次は Router を実装するコントローラの基本的な例です。
Ext.define('MyApp.view.main.MainController', {
extend : 'Ext.app.ViewController',
routes : {
'users' : 'onUsers'
},
onUsers : function() {
//...
}
});
このルートは #users
ハッシュに反応し、コントローラインスタンス専用の onUsers
メソッドを実行します。ご覧の通り、routes
コンフィグがルートレベルではなく config
オブジェクト内に配置されます。
ハッシュの更新
ハッシュを更新するために、コントローラには redirectTo メソッドがあります。
this.redirectTo('user/1234');
これはハッシュが "#user/1234"
となるように更新し、ハッシュを認識するように設定されたすべてのルートが実行されます。現在のハッシュが更新しようとしているハッシュと同じこともあります。この場合、redirectTo
は false
を返し、ハッシュは更新されません。これにより、設定ルートは実行されません。また、redirectTo
は第2のパラメータを受け入れて、Router に true
を渡してこのハッシュに反応するように強制します。
this.redirectTo('user/1234', true);
現在のハッシュが redirectTo
に渡されるハッシュに一致する場合でも、Router は一致するルートを実行します。
デフォルトトークン
アプリケーションが起動すると、ハッシュがない場合にデフォルトのハッシュに追加するように設定されていることがあります。例えば、#home
ハッシュが使用されるとアプリケーションがダッシュボードを表示する場合、#home
ハッシュを URI に追加します。デフォルトのハッシュを有効にするには、アプリケーション内にある /app/view/Application.js
ファイルで defaultToken
コンフィグを使用できます。
Ext.define('MyApp.Application', {
extend : 'Ext.app.Application',
//...
defaultToken : 'home'
});
アプリケーションが起動すると、URI の現在のハッシュを確認します。定義されているハッシュがあると、ルートハンドラを実行します。ハッシュが見つからない場合、#home
ハッシュを追加し、適切に処理できるようにルートハンドラが実行されます。
パラメータのあるハッシュ
また、アプリケーションはハッシュ内のパラメータを識別します。ユーザー ID はハッシュに含めたいパラメータの例です。#user/1234
をハッシュとして使用することは本ガイドで前述しています。この場合、1234
が id パラメータとなるようにします。次に、#user/1234
ハッシュに反応するようにコントローラを設定します。
Ext.define('MyApp.view.main.MainController', {
extend : 'Ext.app.ViewController',
routes : {
'user/:id' : 'onUser'
},
onUser : function(id) {
//...
}
});
使用したルートは 'user/:id'
とコロン :
でした。これは、パラメータが存在し、アプリケーションがそのパラメータを onUser メソッドに引数として渡すことを示します。メソッドはルートに指定されたものと同じ順序で渡された引数を同じ数だけ受け取ります。これによって、複数のパラメータを簡単に含めることができます。
ハッシュパラメータのフォーマット
アプリケーションはユーザー ID に特定のフォーマットを強制しようとすることがあります。今まで見てきたように ID は数値です。また、 conditions
コンフィグを使用することでオブジェクトに等しくなるようにルートを使用することもできます。
Ext.define('MyApp.view.main.MainController', {
extend : 'Ext.app.ViewController',
routes : {
'user/:id' : {
action : 'onUser',
conditions : {
':id' : '([0-9]+)'
}
}
},
onUser : function(id) {
//...
}
});
この例を見てみましょう。最初に、‘onUser’ メソッドは action コンフィグに移動されました。これは文字列をルートに渡した場合と同様に機能します。次に、conditions コンフィグを使用してオブジェクトを提供します。コントロールしたいキーはコロン付きのパラメータ名で Regular Expression 文字列(Regular Expression オブジェクトではなく)を提供します。:id
条件に対しては、([0-9]+)
を使用します。これによって 0 から 9 の任意の長さの数字を使用でき、一致を記憶します。Regular Expression オブジェクトはハッシュ全体と一致するようになっているため文字列を使用します。ルートに複数のパラメータがある場合、Regular Expression 文字列を単一の Regular Expression オブジェクトに連結する必要があります。パラメータに条件を提供しない場合、デフォルトが使用されます。
([%a-zA-Z0-9\\-\\_\\s,]+)
ルートの処理
アプリケーションがルートの処理を回避する必要がある場合があります。この場合、現在のユーザーがアプリケーションのビューを参照できるかどうか管理者権限を確認します。ルートは before アクションを使用するように設定できます。これは現在のルートを停止するか、すべてのルートを停止するか、ルート実行を続行することができます。
この例ではルート実行を続行します。
Ext.define('MyApp.view.main.MainController', {
extend : 'Ext.app.ViewController',
routes : {
'user/:id' : {
before : 'onBeforeUser',
action : 'onUser'
}
},
onBeforeUser : function(id, action) {
Ext.Ajax.request({
url : '/security/user/' + id,
success : function() {
action.resume();
}
});
},
onUser : function(id) {
//...
}
});
onBeforeUser
メソッドでは、:id
パラメータが引数として渡されますが、最後の引数は action
です。resume
メソッドを action
で実行すると、ルートが実行を続行し、onUser
メソッドが呼び出されます。AJAX リクエストを待って完了してから、ルート実行を続行できる点に注意してください。
stop
メソッドを実行し、アプリケーションに現在のルート実行を停止するように指示することでこの例を拡張します。
Ext.define('MyApp.view.main.MainController', {
extend : 'Ext.app.ViewController',
routes : {
'user/:id' : {
before : 'onBeforeUser',
action : 'onUser'
}
},
onBeforeUser : function(id, action) {
Ext.Ajax.request({
url : '/security/user/' + id,
success : function() {
action.resume();
},
failure : function() {
action.stop();
}
});
},
onUser : function(id) {
//...
}
});
Ext JS アプリケーションは複雑ですが、同じルートをリッスンするために設定されているコントローラが多数あることがあります。ただし、before アクションで設定するコントローラは1つだけなので、発火される ajax リクエストは1つだけです。true
を action
引数の stop
メソッドに渡すと、現在処理中のルートだけでなく、キューにあるすべてのルートの実行を停止することができます。
Ext.define('MyApp.view.main.MainController', {
extend : 'Ext.app.ViewController',
routes : {
'user/:id' : {
before : 'onBeforeUser',
action : 'onUser'
}
},
onBeforeUser : function(id, action) {
Ext.Ajax.request({
url : '/security/user/' + id,
success : function() {
action.resume();
},
failure : function() {
action.stop(true);
}
});
},
onUser : function(id) {
//...
}
});
これで、ajax リクエストが失敗すると、true
を渡してすべてのコントローラでこのルートのすべてのハンドラをキャンセルします。
注意:_resume
メソッドまたは stop
メソッドを実行しない場合、ルーティングは中断され、適切に完了しません。ある時点でいずれかのメソッドで実行することが重要です。_
一致しないルートの処理
ハッシュが変更されハッシュに一致するルートが見つからない場合、ルーターは何もしません。ルーターはハッシュを変更せず、一致しないハッシュだけを残します。ルーターは、Ext.application
呼び出しでリッスンできる unmatchedroute
イベントをアプリケーションインスタンスで発火します。
Ext.application({
name : 'MyApp',
listen : {
controller : {
'#' : {
unmatchedroute : 'onUnmatchedRoute'
}
}
},
onUnmatchedRoute : function(hash) {
//...
}
});
単一ハッシュでの複数ルートの使用
Ext JS アプリケーションは複雑なので、場合によっては単一ハッシュで複数のルートを使用する必要があります。ルーターはこれを処理するために設定されるので、コントローラで設定されるルートへの追加設定はありません。代わりに、ハッシュをパイプ(|
)で区切ることができます。ハッシュの例
`#user/1234|messages`
この場合、id 1234
のユーザーの詳細を表示しますが、メッセージも表示したいと思います。各ルートがハッシュで決められた順序で実行されます。次に、相互にサンドボックス化されます。分かりやすく言うと、user/1234
ルートを停止すると、messages
ルートが実行を続行します。個別のルートの実行順序がハッシュ内のルートと同じになることに注意してください。上記の例では、user/1234
ルートは常に messages
ルートよりも先に実行されます。
Ext.app.route.Router.multipleToken
プロパティを変更して、区切り文字を変更できます。