俺聞け11でExt JS 5について15分で説明しようとしてできなかった話

orekike11

俺聞け11 というイベントで、

「Sencha のフレームワーク Ext JS 5 について 15 分で説明するよ」という発表をしてきました。 そして、15分では説明しきれませんでした。orz

そのままで放置していてはいけないので、このブログでフォローしたいと思います。

当日の発表資料は、SlideShare の方に登録しました。ご覧ください。

スライドの中の、「ではアプリを作ってみます」のところから、順番に解説します。

始める前に、Sencha Cmd のインストールが必要です。

Sencha の公式サイトから、Sencha Cmd をダウンロード して、インストールしてください。

スキャッフォルディング

アプリケーションの雛形の作成です。 Sencha Ext JS でのプロジェクトの開始は、いつもこの作業から始まります。 Sencha Cmd を使って、スキャッフォルディングします。 どこかに作業用のディレクトリを作って、そこにプロジェクトの雛形を生成します。

mkdir myapp
cd myapp
sencha generate app -ext MyApp .

-ext をつけることで、Sencha の CDN からフレームワークをダウンロードして、スキャッフォルディングしてくれます。 MyApp はアプリケーションの「名前空間」で、次の「.」は、作成するディレクトリです。

雛形が出来上がりました。ディレクトリの内容をみてみます。

▾ myapp/
  ▸ app/
  ▸ build/
  ▸ ext/
  ▸ overrides/
  ▸ resources/
  ▸ sass/
    app.js
    app.json
    bootstrap.css
    bootstrap.js
    bootstrap.json
    build.xml
    index.html
    Readme.md

こんな風に出来上がっているのがわかります。 これをブラウザで確認してみましょう。 まず、Sencha Cmd で、簡易 Web サーバーを起動します。次のコマンドを実行します。

sencha app watch

すると、多くのメッセージが流れた後に、次の様に表示されます。

[INF] Mapping http://localhost:1841/ to /Users/sunvisor/Desktop/test...
[INF] ------------------------------------------------------------------
[INF] Starting web server at : http://localhost:1841
[INF] ------------------------------------------------------------------
[INF] Waiting for changes...

ここで表示されている、http://localhost:1841 にブラウザでアクセスします。 次の様な画面が表示されます。

fig 2015-02-17 10.04.11

サーバーからデータを取得

サーバーからデータを取得して、それを画面上に一覧表示する、というのをやりたいと思います。 まずは、サーバー上のデータを配置します。 プロジェクト下に data というディレクトリを作って、次のリンクのJSONファイルを配置します。

contact.json

配置したら、一度ブラウザでアクセスしてみてください。http://localhost:1841/data/contact.json JSON ファイルが表示されたでしょう?これをこれから綺麗に画面に表示します。

まずは、Model を作ります。app/model ディレクトリの下に Contact.js ファイルを作って、次の内容を入力します。

 
    Ext.define('MyApp.model.Contact', {
        extend: 'Ext.data.Model',

        fields: [
            // 
        ],

        proxy: {
            type: 'ajax',
            url: 'data/contact.json',
            reader: {
                type: 'json'
            }
        }

    });

Model は、データの構造を定義するクラスで、インスタンス化されたものが「レコード」になります。

fields は、サーバー上のデータのフィールドを定義するのですが、Ext JS 5 からは、サーバーのデータフィードにあるフィールドは、宣言なしでも使えるようになったので、ここでは何も指定していません。データの変換処理やバリデーションが必要な場合には、ちゃんと fields に定義する必要があります。それは後ほど勉強してください。

proxy の指定で、サーバーとのデータのやりとりの方法を指定しています。url でデータのありかを指定し、reader で、サーバー上のデータのタイプを指定しています。type には json の他 xml などが使えます。

orekike_sunvisor

グリッドにバインド

Ext JS 5 には、グリッドという強力なコンポーネントがあります。あっという間に一覧表を画面に表示できるすぐれものです。プラグインを使えば、Excel の用に画面上でセルの編集も簡単に実装できます。

今回は、グリッドに先ほどの JSON データを表示します。

まずは、ViewModel の stores を定義して、サーバーから取得したデータの保管場所にします。

view/main/MainModel.js を開いてください。TODO とコメントされているところを削除して、stores を定義します。

    Ext.define('MyApp.view.main.MainModel', {
        extend: 'Ext.app.ViewModel',

        requires: [
            'MyApp.model.Contact'
        ],

        alias: 'viewmodel.main',

        data: {
            name: 'MyApp'
        },

        stores: {
            // 連絡先のストア
            contacts: {
                model: 'MyApp.model.Contact',
                autoLoad: true
            }
        }

    });

これで、先ほど作った MyApp.model.Contact を使った、contacts という Store ができました。 Store というのは、レコード (つまり Model のインスタンス) の集合で、データベースで言うとテーブルに相当します。 Store は、データのフィルタリングやソーティング、データの検索など多くの機能を持っています。

これで、Store が定義できましたので、いよいよそれを Grid に表示します。 これもとても簡単です。

view/main/Main.js を開いて、ソースコードを修正します。

  • layout は、'fit' に変更します。
  • items の中身は空にして、一つのグリッドに置き換えます。
    Ext.define('MyApp.view.main.Main', {
        extend: 'Ext.container.Container',
        requires: [
            'Ext.grid.Panel',
            'MyApp.view.main.MainController',
            'MyApp.view.main.MainModel'
        ],

        xtype: 'app-main',

        controller: 'main',

        viewModel: {
            type: 'main'
        },

        layout: 'fit',

        items: [{
            title: '俺聞け11',
            xtype: 'grid',
            // ViewModel のストアとバインド
            bind: {
                store: '{contacts}'
            },
            columns: [{
                text: '姓',
                dataIndex: 'last_name'
            },{
                text: '名',
                dataIndex: 'first_name'
            },{
                text: 'メールアドレス',
                dataIndex: 'e-mail',
                flex: 1
            }]
        }]
    });

このビューは、Ext.container.Container クラスを継承しています。「コンテナー」と言われるコンポーネントです。 コンテナーには、他のコンポーネントを配置することができます。 子コンポーネントは、items 配列の中に指定します。 items 配列の中に、子コンポーネントの属性を指定したオブジェクトを渡すと、Ext JS は必要に応じて、それらのコンポーネントのインスタンスを作って、親のコンテナーに配置してくれます。

ここでは、items 配列に一つだけコンポーネントを配置しています。xtype は全てのコンポーネントにつけられているユニークな名前です。xtype: 'grid' でこのコンポーネントはグリッドだということになります。

columns で、グリッドのカラム情報を指定します。ここでは 3つのカラムを定義しています。

bind 所で store: '{contacts}' を指定していますね。 この {contacts} と波括弧でくくったところが、ViewModel とバインドされます。 一つ前でセットした、contacts ストアが、このグリッドとバインドされるわけです。

ここまでできたら、ブラウザをリロードしてみましょう。

fig 2015-02-17 10.33.18

みごとに表示されましたね。これぐらい簡単にグリッドにデータをバインドできます。 すばらしいですね。 メールアドレスのヘッダの部分をクリックしてみてください。 メールアドレス順にソートされましたね。 こんな機能もアウトオブボックスですぐに使えます。

ViewController でイベントをハンドリング

次に、イベント操作を加えてみましょう。 グリッドの行をダブルクリックしたら、詳細をフォームに表示する、というのを実装します。

まずは、フォームを作ります。

app/view の下に Edit.js ファイルを作ります。 その内容を次の様にします。

    Ext.define('MyApp.view.Edit', {
        extend: 'Ext.window.Window',

        items: [{
            xtype: 'form',
            bodyPadding: 20,
            items: [{
                xtype: 'textfield',
                fieldLabel: '姓',
                name: 'last_name'
            }, {
                xtype: 'textfield',
                fieldLabel: '名',
                name: 'first_name'
            },{
                xtype: 'combobox',
                fieldLabel: '性別',
                name: 'gender',
                canEdit: false,
                store: {
                    fields: ['text'],
                    data: [
                        {text: '男'},
                        {text: '女'}
                    ]
                }
            },{
                xtype: 'textfield',
                fieldLabel: '電話番号',
                name: 'phone'
            },{
                xtype: 'textfield',
                fieldLabel: 'メール',
                name: 'e-mail'
            }]
        }]
    });

このクラスは、Ext.window.Window を継承しています。Window は、フローティングしたウィンドウのクラスです。情報をポップアップさせるときにとても便利なコンポーネントです。

今回も items の中身は一つだけで、xtypeform になっています。フォームには、フォームフィールドを配置できて、配置されたフォームフィールドとのデータのやり取りを簡単にするための機能が備わっています。 ここでは、姓、名など 5つのフィールドを定義しています。性別のフィールドには combobox を使っています。Ext JS には他にも多くの種類のフィールドが用意されています。

app/main/Main.js に、イベントリスナー設定をします。 columns の後に、listeners を定義して、行のダブルクリックイベントを拾います。

    Ext.define('MyApp.view.main.Main', {
        extend: 'Ext.container.Container',
        requires: [
            'Ext.grid.Panel',
            'MyApp.view.main.MainController',
            'MyApp.view.main.MainModel'
        ],

        xtype: 'app-main',

        controller: 'main',

        viewModel: {
            type: 'main'
        },

        layout: 'fit',

        items: [{
            title: '俺聞け11',
            xtype: 'grid',
            // ViewModel のストアとバインド
            bind: {
                store: '{contacts}'
            },
            columns: [{
                text: '姓',
                dataIndex: 'last_name'
            },{
                text: '名',
                dataIndex: 'first_name'
            },{
                text: 'メールアドレス',
                dataIndex: 'e-mail',
                flex: 1
            }],
            // リスナーの定義
            listeners: {
                itemdblclick: 'onItemDblClick'
            }
        }]
    });

itemdblclick イベントに 'onItemDblClick' という文字列をセットしています。 Ext JS フレームワークは、このリスナーを、ViewController 内にある同名のメソッドと結びつけます。

次に、ViewController にリスナーメソッドの本体を定義します。 app/main/MainController.js を開き、次の様にコーディングします。

    Ext.define('MyApp.view.main.MainController', {
        extend: 'Ext.app.ViewController',

        requires: [
            'MyApp.view.Edit'
        ],

        alias: 'controller.main',

        onItemDblClick: function (grid, rec) {
            var win = Ext.create('MyApp.view.Edit');

            // フォームにデータをロード
            win.down('form').loadRecord(rec);
            // 表示
            win.show();
        }
    });

onItemDblClick でやっていることは次の様なことです。

  • Edit.js で定義しているウィンドウのインスタンスを生成
  • ウィンドウ内にあるフォームに、グリッドから渡されたレコードをセット
  • ウィンドウを表示

データを取り出して表示するまでが、わずかこれだけのコードで実装できました。

ブラウザをリロードして、どこかの行をダブルクリックしてみてください。

fig 2015-02-17 10.54.19

ウィンドウが表示されました。

テーマ設定

次に見た目の設定をちょっとやってみます。

Ext JS 5 では、見た目の設定は「テーマ」というもので変更できます。 テーマは、すぐ使えるものがいくつか用意されていますし、独自のテーマを作成することも可能です。 また、既存のテーマの一部を変更して使うこともできます。

ここでは、既存のテーマをちょっとだけ変更する方法をお伝えします。

scss/var ディレクトリの下に、Application.scss というファイルを作って下さい。 その中に、次の1行を書きます。

$base-color: green;

保存すると、app watch が動き始め、CSS を作ってくれます。 それが終わったら、ブラウザをリロードしてみましょう。

fig 2015-02-17 10.56.56

色がグリーンをベースにするものに変わりました。 Ext JS のテーマは、SASS/Compass で作られているため、こういった変数を変更するだけで、画面イメージを大きく変えることができるようになっています。

まとめ

ここまでブログ記事にしてみて、改めて思うのは、これを 15分で説明しようと思ったのが間違いだってことですw。 しかし、ひょっとしたら「いけんじゃね?」と思えるぐらい、最初のステップは簡単に踏み出せるのです。 ここまで記事を読んでいただいた方にもおわかりと思います。 実際に、書いてある通りに実践していただいても、30分もかからずに、このチュートリアルを終えることができると思います。 15分は無理でしたが、それに近いものはあるということですね。

なお、「俺聞け11」で時間切れになってしまったのは、マクラのネタ振りに時間を使いすぎたというのが、本当のところですw。

「俺聞け」というイベントは、2回目の参加でしたが、とても楽しいイベントです。Web という縛りしかない守備範囲の広さから、本当に様々な立場の方が、さまざまな発表をされます。そして、みんな「いい意味で変態」ですw。

orekikeparty

Photography by Kenichi Hisaoka

また、東京とか大阪で開催されるそうですので、次回は皆さんも参加してみて下さい。楽しいですよ。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です