Ext.ux.Routerの話

ExtJSMVCではControllerでviewが発火するイベントをlistenして、モデルの適切な処理を呼び出す。

でよいはずだが、Controllerから別のコントローラーを呼び出す時のコードの書き方がいまいち良くわかってない。

遷移元に遷移先のコントローラXXXの定義を書いておいて、直接getXXXController()等として、コントローラーのメソッドを呼び出せばいいけど、しっくりこない。 しっくりこない理由が自分でもよくわかってないけど、コントローラー間の依存関係を明確に定義しないと動かないというのが違和感あるのかもしれない。

Ext.ux.Routerというのがあって、これを使うと、ExtJSMVCRailsっぽく書ける。

app.js.coffee

Ext.application
    paths:
        'Ext.ux': 'path_to_Ext.ux.Router'
    requires:[
        'Ext.ux.Router'
        ...
    ]
    controllers: [
        'Homes'
        'Users'
        ...
    ]
    routes : {
        '/': 'Homes#index'
        '/users' : 'Users#index'
        '/users/new' : 'Users#new'
        '/users/:id' : 'Users#show'
        ...
    }

    launch : ->
        Ext.ux.Router.on 'routemissed', (token)->
            console.log "routemissed #{token}"

        #画面遷移前の処理です。
        Ext.ux.Router.on 'beforedispatch', (token, match, params)=>
            console.log "beforedispatch #{token}, #{JSON.stringify params}"

        # 画面遷移後の処理です。
        # Controllerの処理でparamsに
        Ext.ux.Router.on 'dispatch', (token, match, params, controller)->
            console.log "dispatch #{token}"
            #viewのクラスをロードして、メイン領域を差し替える。
            if params.renderConfig
                container = Ext.getCmp('app-container')
                viewClass = Ext.ClassManager.get(params.renderConfig.viewClass)
                view = Ext.create viewClass, params if viewClass
                if view
                    container.removeAll()
                    container.add(view)

別の画面に遷移する場合は Controllerのメソッドの中でExt.ux.Router.redirectを使う。

controller/UsersController.js.coffee

Ext.define 'Users', {
    views: ['user.ListView']

    init: ->
        @control
            'newbutton' :
                click: @onNewButtonClick
    # xxx.user.ListViewを描画します。
    index: (params)->
        params.renderConfig = 
            viewClass: 'user.ListView'

    onNewButtonClick: ->
        params = {}
        Ext.ux.Router.redirect '/users/new', params
    ...
}

#(ハッシュ)以降の文字列を判断して呼び出すコントローラーを切り分けている感じ。 history.pushState使った実装の方がかっこいいと思ってますが、ExtJS自体がHistory APIに対応していないので、まぁこんなところかと。