logo

サイト内検索
ココログ最強検索 by 暴想

最近のトラックバック

無料ブログはココログ

« Test | トップページ | ココログへフォルダーごと一括アップロードする »

GwtExt FormPanelとGridの連携

  • ソースを表示して文中のリンクをクリックすると該当行が選択されます。
  • GwtExtの実装例ですが、ext.jsでも同じ考えで行けると思います。

Untitled

FormPanelからgetForm().loadRecord(record)を実行することで、Grid上の特定のレコードの内容をFormPanelに簡単に表示することができます。
http://www.gwt-ext.com/demo/#formGridにサンプルコードが掲載されているが、このケースはGrid→FormPanelは実装されているが、フォーム上で編集した内容をGrid側のデータに書き戻す部分が無かったのでそこを追加実装した例を示します。

前準備

Gridで使用しているStoreにFieldDefの配列をセットする(206-210)。ここで指定した文字列がFieldのカラム名になる。
    private static RecordDef recordDef = new RecordDef(new FieldDef[] {
            new StringFieldDef("company"), new FloatFieldDef("price"),
            new FloatFieldDef("change"), new FloatFieldDef("pctChange"),
            new DateFieldDef("lastChanged", "n/j h:ia"),
            new StringFieldDef("symbol"), new StringFieldDef("industry") });

FormPanelにのせるTextFieldのオブジェクト生成時に上記カラム名と一致したnameを付ける。(89-95)この例ではコンストラクターの2つ目の引数がnameになる。

        // the field names msut match the data field values from the Store
        fieldSet.add(new TextField("Name", "company", 120));
        TextField priceField = new TextField("Price", "price", 120);
        fieldSet.add(priceField);
        TextField pctChangeField = new TextField("% Change", "pctChange", 120);
        fieldSet.add(pctChangeField);
        fieldSet.add(new DateField2("Last Updated", "lastChanged", 120));

GridからFormPanelへ連携

まず、Grid→FormPanelの反映する部分をおさらいすると、以下の部分(49-62)

        final RowSelectionModel sm = new RowSelectionModel(true);
        sm.addListener(new RowSelectionListenerAdapter() {
            public void onRowSelect(RowSelectionModel sm, int rowIndex,
                    Record record) {
                formPanel.getForm().loadRecord(record);
            }
        });

行をGridから選択した際、RowSelectionModelのonRowSelectアクションで選択されたrecordが入手できるので、これをformPanel.getForm().loadRecord(record)とやるだけでOK。

FormPanelからGridへ連携(121-137)

逆の連携は少々手間がかかる。まず、FormPanel上のすべてのFieldのonChangeイベントを拾うListenerを仕込んでおいて、Fieldの変更時に該当のRecord側に値を設定する。

    private void setFieldListeners(FormPanel fp, final RowSelectionModel sm) {
        // FormPanel上のすべてのFieldにChangeイベントを拾うListenerを追加
        Field[] fds = fp.getFields();
        for (int i = 0; i < fds.length; i++) {
            Field fd = fds[i];
            fd.addListener(new FieldListenerAdapter() {
                public void onChange(Field field, Object newVal, Object oldVal) {
                    // Fieldの値変更時にRecordへ反映
                    Record record = sm.getSelected();
                    if (!(record.getAsString(field.getName()).equals(newVal))) {
                        setAsString(SampleGrid.recordDef, record, field);
                    }
                }
            });
        }
    }

ここで注意!

上記Listenerの設定は、RootPanel.get().add(panel);でFormPanelがrender(表示)された後でないと有効にならないようだ。だから、以下のように(115-117)最後に行う。

        RootPanel.get().add(panel);
        setFieldListeners(formPanel, gridPanel.getSelectionModel());

値の設定(139-159)はRecord定義時のRecordDefから型を判断してセットする。FloatFieldDefの場合はdoubleへの変換。DateFieldDefの場合はDateFieldのgetDateでDateオブジェクトを取る。

    private void setAsString(RecordDef def, Record record, Field field) {
        if (!field.validate()) {
            return false;;
        }
        FieldDef[] fdefs = def.getFields();
        for (int i = 0; i < fdefs.length; i++) {
            FieldDef fdef = fdefs[i];
            String id = field.getName();
            if (fdef.getName().equals(id)) {
                if (fdef instanceof FloatFieldDef) {
                    record.set(id, new Double(field.getValueAsString())
                            .doubleValue());
                } else if (fdef instanceof DateFieldDef) {
                    DateField df = (DateField) field;
                    record.set(id, df.getValue());
                } else {
                    record.set(id, field.getValueAsString());
                }
            }
        }
    }

さて、これでOKと思ったのだが、このまま動かすとFieldを編集した直後にGridをクリックして直接他の行に選択を移したケースで変更が反映されない事が判明。デバッグした結果、なぜかonRowSelectイベントがFieldのonChangeよりも前に呼ばれる事が原因だった。onRowSelectで新たに選択した行のrecordでFieldを上書きしてしまうので、編集したデータが失われる(onChangeをonBlurにしても同じ。納得いかないが..)
仕方が無いのでonDeSelectイベントを拾って、ここでも変更されたfieldの値をrecordに反映する処理(51-62)を行う事にした。

            public void onRowDeselect(RowSelectionModel sm, int rowIndex,
                    Record record) {
                // 行の選択が解除された時の処理
                // 変更されたfieldの値をrecordに反映
                Field[] fs = formPanel.getFields();
                for (int i = 0; i < fs.length; i++) {
                    Field field = fs[i];
                    if (field.isDirty()) {
                        setAsString(SampleGrid.recordDef, record, field);
                    }
                }
            }

入力チェックの実装

priceとpctChangeはdoubleに変換する都合上変な値を入力されると困るので、入力チェックを実装しましょう。正規表現を使用して以下のようにsetRegexに正規表現をしていすればOK。なお、この機能は内部的にRegExp.test()メソッドでチェックをしているので、regexの最初と最後にちゃんと^と$を入れないとザル状態になりますので注意。(そうしないと正規表現に一致する部分がどこかにあればOKになってしまう。これで少々ハマッタ)

        // 正規表現とalowblankによる入力チェック
        String regex = "^[-+]?[0-9]+(\\.[0-9]*)?$";
        String regexText = "数値が無効です";
        String blankText = "空白には出来ません";
        priceField.setRegex(regex);
        priceField.setRegexText(regexText);
        priceField.setAllowBlank(false);
        priceField.setBlankText(blankText);
        pctChangeField.setRegex(regex);
        pctChangeField.setRegexText(regexText);
        pctChangeField.setAllowBlank(false);
        pctChangeField.setBlankText(blankText);

なおsetAllowBlank(false)は空白値を許さない設定です。

« Test | トップページ | ココログへフォルダーごと一括アップロードする »

ext.js」カテゴリの記事

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック

この記事のトラックバックURL:
http://app.f.cocolog-nifty.com/t/trackback/1482716/39211839

この記事へのトラックバック一覧です: GwtExt FormPanelとGridの連携:

« Test | トップページ | ココログへフォルダーごと一括アップロードする »