4

フォームのシリアル化手法を使用できない複雑なフォームがあります。フォーム内には多くのフィールドと動的グリッド (ユーザーがいくつかの条件を選択すると動的に生成されるグリッド) があります。

私がやりたいことは、ユーザー入力/選択を収集し、グリッドで利用可能な選択されたレコードを追加し、最終的にそれらのデータを含む JSON 配列を作成して、サーバー側に投稿できるようにすることです。

私の推測でgetCmpは、ExtJS の関数を使用してデータ全体を取得できますが、この方法では保守が少し難しくなります。また、この方法でグリッドデータを取得する方法がわかりません!

PS : コードが少し長いので、一部を切り取っています。

モデルとストアの定義

Ext.Loader.setConfig({enabled: true});
Ext.Loader.setPath('Ext.ux', '<?php echo js_url(); ?>resources/ux');

Ext.require([
  'Ext.grid.*',
  'Ext.data.*',
  'Ext.form.*',
  'Ext.state.*',
  'Ext.util.*',
  'Ext.layout.container.Column',
  'Ext.selection.CheckboxModel',
  'Ext.ux.RowExpander',
  'Ext.ux.statusbar.StatusBar'  
]);

var navigate = function (panel, direction) {

    var layout = panel.getLayout();

    layout[direction]();

    Ext.getCmp('move-prev').setDisabled(!layout.getPrev());
    Ext.getCmp('move-next').setDisabled(!layout.getNext());
};

// Article Model
Ext.define('Article', {
    extend: 'Ext.data.Model',
    fields: [
        {name: 'ARTICLE_ID', type: 'int'},
        {name: 'DESCRIPTION', type: 'string'}
    ]
});

// Article Json Store
var articles = new Ext.data.JsonStore({
    model: 'Article',
    proxy: {
        type: 'ajax',
        url: '<?php echo base_url() ?>create/get_articles',
        reader: {
            type: 'json',
            root: 'artList',
            idProperty: 'ARTICLE_ID'
        }
    }
});

winArticle = new Ext.Window({
width: 600,
modal: true,
title: 'Artikel Seçimi',
closeAction: 'hide',
bodyPadding: 10,
items: new Ext.Panel({
    items: [
        {
            xtype: 'fieldset',
            title: 'Artikel Sorgulama',
            defaultType: 'textfield',
            layout: 'anchor',
            defaults: {
                anchor: '100%'
            },
            height: '76px',
            items: [
                {
                    xtype: 'fieldcontainer',
                    layout: 'hbox',
                    defaultType: 'textfield',
                    items: [
                        {
                            xtype: 'combobox',
                            id: 'articleNo',
                            inputWidth: 320,
                            fieldLabel: 'ARTİKEL NO',
                            fieldStyle: 'height: 26px',
                            margin: '10 15 0 0',
                            triggerAction: 'query',
                            pageSize: true
                        },
                        {
                            xtype: 'button',
                            text: 'SORGULA',
                            width: 100,
                            scale: 'medium',
                            margin: '8 0 0 0'
                        }
                    ]
                }
            ]
        },
        {
            xtype: 'fieldset',
            title: 'Artikel Bilgileri',
            height: '140px',
            layout: 'fit',
            items: [
                {
                    xtype: 'fieldcontainer',
                    layout: 'hbox',
                    defaultType: 'textfield',
                    fieldDefaults: {
                        labelAlign: 'top'
                    },
                    items: [
                        {
                            fieldLabel: 'ARTİKEL TANIMI',
                            name: 'artDesc',
                            flex: 3,
                            margins: '0 5 0 0'
                        },
                        {
                            fieldLabel: 'PAKET İÇERİĞİ',
                            name: 'artgebi',
                            flex: 1
                        }
                    ]
                },
                {
                    xtype: 'fieldcontainer',
                    layout: 'hbox',
                    defaultType: 'textfield',
                    id: 'artContainer1',
                    fieldDefaults: {
                        labelAlign: 'top'
                    },
                    items: [
                        {
                            fieldLabel: 'SUBSYS',
                            name: 'artSubsys',
                            flex: 1,
                            margins: '0 5 0 0'
                        },
                        {
                            fieldLabel: 'VARIANT',
                            name: 'artVariant',
                            flex: 1,
                            margins: '0 5 0 0'
                        },
                        {
                            fieldLabel: 'VARIANT TANIMI',
                            name: 'artVariantDesc',
                            flex: 2
                        }
                    ]
                }
            ]
        },
        {
            xtype: 'fieldset',
            title: 'Aksiyon Seviyeleri',
            id: 'article-fieldset',
            items: [
                {
                    xtype: 'button',
                    id: 'btnArticleLevelAdd',
                    text: 'LEVEL EKLE',
                    scale: 'medium',
                    width: 100,
                    style: 'float: right',
                    margin: '0 7 0 0',
                    handler: function() {

                        var getLevels = function() {
                            var count = winArticle.down('fieldset[id=article-fieldset]').items.items.length;
                            return count;
                        }

                        var count = getLevels();

                        if (count === 3) {
                            Ext.getCmp('btnArticleLevelAdd').disable();
                        }

                        var container = 'artContainer' + count;
                        //console.log(container);

                        Ext.getCmp('article-fieldset').add([
                            {
                                xtype: 'fieldcontainer',
                                layout: 'hbox',
                                id: 'artContainer' + count,
                                defaultType: 'textfield',
                                fieldDefaults: {
                                    labelAlign: 'top'
                                },
                                items: [
                                    {

                                        name: 'artLevel' + count,
                                        allowBlank: false,
                                        inputWidth: 216,
                                        fieldStyle: 'text-align: right; font-size: 13pt; background-color: #EAFFCC;',
                                        margins: '0 5 5 0'
                                    },
                                    {

                                        name: 'artValue' + count,
                                        allowBlank: false,
                                        inputWidth: 216,
                                        fieldStyle: 'text-align: right; font-size: 13pt; background-color: #EAFFCC;',
                                        margins: '0 5 0 0'
                                    },
                                    {
                                        xtype: 'button',
                                        text: 'SİL',
                                        width: 40,
                                        cls: 'btn-article-remove',
                                        handler: function() {
                                            if(count <= 3) {
                                                Ext.getCmp('btnArticleLevelAdd').enable();
                                            } else {
                                                Ext.getCmp('btnArticleLevelAdd').disable();
                                            }
                                            winArticle.down('fieldset[id=article-fieldset]').remove(container);
                                        }
                                    }
                                ]
                            }
                        ]);
                    }
                },
                {
                    xtype: 'fieldcontainer',
                    layout: 'hbox',
                    id: 'article-level-container',
                    defaultType: 'textfield',
                    fieldDefaults: {
                        labelAlign: 'top'
                    },
                    items: [
                        {
                            fieldLabel: 'LEVEL',
                            name: 'artLevel',
                            inputWidth: 216,
                            margins: '0 5 5 0',
                            allowBlank: false,
                            fieldStyle: 'text-align: right; font-size: 13pt; background-color: #EAFFCC;'
                        },
                        {
                            fieldLabel: 'VALUE',
                            name: 'artValue',
                            inputWidth: 216,
                            allowBlank: false,
                            blankText: 'zorunlu alan, boş bırakılamaz',
                            fieldStyle: 'text-align: right; font-size: 13pt; background-color: #EAFFCC;',
                            listeners: {
                                change: function(textfield, newValue, oldValue) {
                                    if(oldValue == 'undefined' || newValue == '') {
                                        Ext.getCmp('btnArticleSave').disable();
                                    } else {
                                        Ext.getCmp('btnArticleSave').enable();
                                    }
                                }
                            }
                        }
                    ]
                }
            ]
        }
    ]
}),
buttons: [
    {
        text: 'KAPAT',
        scale: 'medium',
        width: 100,
        cls: 'btn-article-close',
        listeners: {
            click: function() {
                winArticle.close();
            }
        }
    },
    '->',
    {
        text: 'EKLE',
        scale: 'medium',
        disabled: true,
        width: 100,
        margin: '0 9 0 0',
        cls: 'btn-article-save',
        id: 'btnArticleSave'
    }
]
});

EXT.ONREADY機能

Ext.onReady(function () {

Ext.QuickTips.init();

Ext.state.Manager.setProvider(new Ext.state.CookieProvider({
    expires: new Date(new Date().getTime() + (1000 * 60 * 60 * 24 * 7))
}));

var Discounts = Ext.create('Ext.form.Panel', {
    id: 'discount-types',
    bodyPadding: 10,
    width: 760,
    height: 600,
    title: 'DNR TANIMLAMA / SCREEN 0',
    layout: 'card',
    bodyStyle: 'padding:20px',
    defaults: {
        border: false,
        anchor: '100%'
    },
    style: {
        'box-shadow': '0 2px 5px rgba(0, 0, 0, 0.6)',
        '-webkit-box-shadow': '0 0 8px rgba(0, 0, 0, 0.5)'
    },
    frame: true,
    buttons: [
        {
            text: 'ÖNCEKİ ADIM',
            id: 'move-prev',
            cls: 'np-button',
            scale: 'medium',
            iconCls: 'dnr-prev-icon',
            iconAlign: 'left',
            handler: function (btn) {
                navigate(btn.up('panel'), 'prev');
                var itemd = Discounts.getLayout().getActiveItem();
                Discounts.setTitle('DNR TANIMLAMA ' + ' / ' + itemd.cardTitle);
                Ext.getCmp('dnr-submit').disable();
                Ext.getCmp('dnr-submit').setVisible(false);
            },
            disabled: true
        },
        {
            text: 'SONRAKİ ADIM',
            id: 'move-next',
            scale: 'medium',
            cls: 'np-button',
            iconCls: 'dnr-next-icon',
            iconAlign: 'right',
            handler: function (btn) {
                navigate(btn.up('panel'), 'next');
                var itemd = Discounts.getLayout().getActiveItem();
                Discounts.setTitle('DNR TANIMLAMA ' + ' / ' + itemd.cardTitle);
                var cardNum = Discounts.items.indexOf(itemd);

                if (cardNum == 3) {
                    Ext.getCmp('dnr-submit').enable();
                    Ext.getCmp('dnr-submit').setVisible(true);
                }
            },
            disabled: true
        },
        '->',
        {
            text: '&nbsp KAYDET ',
            id: 'dnr-submit',
            scale: 'medium',
            iconCls: 'dnr-submit-icon',
            iconAlign: 'right',
            cls: 'dnr-submit',
            disabled: true,
            hidden: true,
            handler: function (btn) {

            }
        }
    ],
    items: [
        {
            id: 'screen-0',
            cardTitle: 'SCREEN 0',
            layout: 'form',
            items: [
                {
                    layout: {
                        type: 'vbox',
                        align: 'center'
                    },
                    margin: '60 0 0 0',
                    items: [
                        {
                            xtype: 'combobox',
                            inputWidth: 295,
                            fieldLabel: 'DNR TİPİ',
                            fieldStyle: 'height: 26px',
                            id: 'discount-type',
                            store: discounts,
                            valueField: 'DNR_TYPE_ID',
                            displayField: 'DNR_TYPE_DESC',
                            queryMode: 'remote',
                            forceSelection: true,
                            stateful: true,
                            stateId: 'cmb_disc_type',
                            allowBlank: false,
                            emptyText: 'DNR tipini seçiniz...',
                            triggerAction: 'all',
                            listeners: {
                                select: function (e) {
                                    var discType = Ext.getCmp('discount-type').getValue();
                                    var discDetail = Ext.getCmp('discount-detail');

                                    discdetails.removeAll();

                                    if (discType != 0) {
                                        discDetail.setDisabled(false);
                                        discdetails.proxy.extraParams = { 'dnrtype': discType };
                                        discdetails.load();
                                    }
                                }
                            }
                        },
                        {
                            xtype: 'combobox',
                            inputWidth: 400,
                            fieldStyle: 'height: 26px',
                            id: 'discount-detail',
                            valueField: 'ID',
                            displayField: 'DNR_TITLE',
                            store: discdetails,
                            forceSelection: true,
                            stateful: true,
                            stateId: 'cmb_disc_detail',
                            margin: '25 0 0 0',
                            disabled: true,
                            allowBlank: false,
                            msgTarget: 'side',
                            emptyText: 'İNDİRİM TİPİNİ SEÇİNİZ...',
                            blankText: 'İndirim tipi boş olamaz!',
                            triggerAction: 'all',
                            listeners: {
                                select: function (e) {
                                    var discDetail = Ext.getCmp('discount-detail').getValue();

                                    if (discDetail != 'null') {
                                        var value = discdetails.getAt(discdetails.find('ID', discDetail)).get('DNR_DESCRIPTION');
                                        Ext.getCmp('dnr-type-desc-panel').setVisible(true);
                                        Ext.getCmp('dnr-type-desc-panel').update(value);
                                    }
                                }
                            }
                        },
                        {
                            xtype: 'textarea',
                            grow: false,
                            name: 'invoiceText',
                            fieldLabel: 'FATURA METNİ',
                            id: 'invoice-text',
                            blankText: 'Fatura metni boş olamaz!',
                            width: 400,
                            height: 60,
                            margin: '30 0 0 0',
                            allowBlank: false,
                            msgTarget: 'side',
                            listeners: {
                                change: function (e) {
                                    if (Ext.getCmp('invoice-text').getValue().length === 0) {
                                        Ext.getCmp('move-next').disable();
                                    } else {
                                        Ext.getCmp('move-next').enable();
                                    }
                                }
                            }
                        },
                        {
                            xtype: 'panel',
                            id: 'dnr-type-desc-panel',
                            layout: {type: 'hbox', align: 'stretch'},
                            height: 145,
                            width: 400,
                            cls: 'dnr-desc-panel',
                            margin: '60 0 0 0',
                            html: '&nbsp',
                            hidden: true
                        }
                    ]
                }
            ]
        },
        {
            id: 'screen-1',
            cardTitle: 'SCREEN 1',
            layout: 'form',
            items: [
                {
                    layout: 'column',
                    width: 730,
                    height: 90,
                    items: [
                        {
                            xtype: 'fieldset',
                            title: 'ARTİKEL / HEDEF GRUP / MAL GRUBU SEÇİMİ',
                            cls: 'dnr-fieldset',
                            width: 730,
                            height: 80,
                            margin: '0',
                            items: [
                                {
                                    xtype: 'buttongroup',
                                    columns: 5,
                                    columnWidth: 140,
                                    frame: false,
                                    margin: '5 0 0 18',
                                    items: [
                                        {
                                            text: 'ARTİKEL',
                                            scale: 'medium',
                                            margin: '0 18px 0 0',
                                            width: 120,
                                            height: 36,
                                            id: 'btn-article',
                                            cls: 'btn-grp-choose btn-grp-article',
                                            listeners: {
                                                click: function () {
                                                    winArticle.center();
                                                    winArticle.show();
                                                }
                                            }
                                        },
                                        {
                                            text: 'PUAR',
                                            scale: 'medium',
                                            margin: '0 18px 0 0',
                                            width: 120,
                                            height: 36,
                                            cls: 'btn-grp-choose btn-grp-puar',
                                            listeners: {
                                                click: function() {
                                                    winPuar.show();
                                                }
                                            }
                                        },
                                        {
                                            text: 'MAL GRUBU',
                                            scale: 'medium',
                                            margin: '0 18px 0 0',
                                            width: 120,
                                            height: 36,
                                            cls: 'btn-grp-choose btn-grp-choose',
                                            listeners: {
                                                click: function() {
                                                    winArticleGroup.show();
                                                }
                                            }
                                        },
                                        {
                                            text: 'HEDEF GRUP',
                                            scale: 'medium',
                                            margin: '0 18px 0 0',
                                            width: 120,
                                            height: 36,
                                            cls: 'btn-grp-choose btn-grp-target',
                                            listeners: {
                                                click: function() {
                                                    winTargetGroup.show();
                                                }
                                            }
                                        },
                                        {
                                            text: 'SUPPLIER',
                                            scale: 'medium',
                                            width: 120,
                                            height: 36,
                                            cls: 'btn-grp-choose btn-grp-supplier',
                                            listeners: {
                                                click: function() {
                                                    winSupplier.show();
                                                }
                                            }
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                },
                {
                    xtype: 'gridpanel',
                    id: 'article-grid',
                    selType: 'rowmodel',
                    elStatus: true,
                    plugins: [
                        { ptype: 'cellediting', clicksToEdit: 1},
                        { ptype: 'datadrop'}
                    ],
                    /* ***************************************************************
                     * here is the tricky part! when user change any fields above
                     * this grid will dynamically generate upon user request. So that
                     * we arent sure which columns will be available.
                     * ***************************************************************/
                    columns: [
                        {
                            text: 'COLUMN A',
                            dataIndex: ''
                        }
                    ]
                }
            ]
        },
        renderTo: 'content'
})
});
4

2 に答える 2

6

更新された回答

いくつかの明確化の後、答えは非常に簡単だと思います(少なくとも私はそう思います)次の答えについては、フォームとグリッドデータを取得したいときにフォーム内にいて、1つしかないと仮定しますExt.form.Panel

// Navigate up to the form:
var form = this.up('form'),
// get the form values
    data = form.getValues(),
// get the selected record from the grid
    gridRecords = form.down('grid').getSelectionModel().getSelected(),
// some helper variables
    len = gridRecords.length,
    recordData = [];

// normalize the model data by copying just the data objects into the array
for(i=0;i<len;i++) {
    recordData .push(gridRecords[i].data);
}
// apply the selected grid records to the formdata. For that you will need a property name, I will use just 'gridRecords' but you may change it
data.gridRecords = recordData;

// send all back via a ajax request
Ext.Ajax.request({
    url: 'demo/sample',
    success: function(response, opts) {
        // your handler
    },
    failure: function(response, opts) {
        // your handler
    },
    jsonData: data
});

そうあるべき

グリッドから/グリッドによってフェッチできるデータのオプションをさらに提供するには

// get all data that is currently in the store
form.down('grid').getStore().data.items
// get all new and updated records
form.down('grid').getStore().getModifiedRecords()
// get all new records
form.down('grid').getStore().getNewRecords()
// get all updated records
form.down('grid').getStore().getUpdatedRecords()

以下の古い回答(より複雑なシナリオの場合)

あなたが言ったこと:

フォームとおそらくグリッドを含むグリッドがあります。フォームからデータを取得するときにグリッドも読み取る必要がある場合。

以下の回答では、 getValues、各グリッドへのイベントのバインド/バインド解除のみをカバーし、そうではありません

  • フォームのロード/送信
  • レコードのロード/更新
  • 設定値

これを処理できるように、フォームをよりインテリジェントにすることをお勧めします。

とはどういう意味ですか?

デフォルトのフォームは、本文のどこに挿入されたすべてのフィールドを考慮します。99.9% でこれは完全に問題ありませんが、すべてではありません。フォームは、挿入されるグリッドにも注意する必要があります。

どのようにそれを行うことができます

まず、フォームのグリッド パーツを作成するときは、name プロパティを指定することをお勧めします。2 つ目は、フォームがどのようにフィールドを収集して利用するかを知って、それをグリッドにコピーできるようにする必要があることです。そのためには、重要な部分であるExt.form.Basicクラスコンストラクターを確認する必要があります。

// We use the monitor here as opposed to event bubbling. The problem with bubbling is it doesn't
// let us react to items being added/remove at different places in the hierarchy which may have an
// impact on the dirty/valid state.
me.monitor = new Ext.container.Monitor({
    selector: '[isFormField]',
    scope: me,
    addHandler: me.onFieldAdd,
    removeHandler: me.onFieldRemove
});
me.monitor.bind(owner);

ここで何が起こるかというと、モニターが初期化され、これ以降、モニターが適切なハンドラーを呼び出すバインドされたコンポーネントに挿入されるフィールドが検索されます。現在、モニターはフィールドを探していますが、グリッドを探しているモニターが必要になります。このようなモニターは次のようになります。

me.gridMonitor = new Ext.container.Monitor({
    selector: 'grid',
    scope: me,
    addHandler: me.onGridAdd,
    removeHandler: me.onGridRemove
});
me.gridMonitor.bind(owner);

私はあなたのデータ構造についてあまり知らないので、必要なグリッドイベントを教えることはできませんが、 addHandler/removeHandler のように登録/登録解除する必要があります

onGridAdd: function(grid) {
    var me = this;
    me.mon(grid,'select',me.yourHandler,me);
},
onGridRemove: function(grid) {
    var me = this;
    me.mun(grid,'select',me.yourHandler,me);
}

さらに、次のヘルパー メソッドが必要になります。

/**
 * Return all the {@link Ext.grid.Panel} components in the owner container.
 * @return {Ext.util.MixedCollection} Collection of the Grid objects
 */
getGrids: function() {
    return this.gridMonitor.getItems();
},

/**
 * Find a specific {@link Ext.grid.Panel} in this form by id or name.
 * @param {String} id The value to search for (specify either a {@link Ext.Component#id id} or
 * {@link Ext.grid.Panel name }).
 * @return {Ext.grid.Panel} The first matching grid, or `null` if none was found.
 */
findGrid: function(id) {
    return this.getGrids().findBy(function(f) {
        return f.id === id || f.name === id;
    });
},

そして最も重要なのは、グリッドからデータを取得するメソッドです。ここでオーバーライドする必要があります

getValues: function(asString, dirtyOnly, includeEmptyText, useDataValues) {
    var values  = {},
        fields  = this.getFields().items,
        grids  = this.getGrids().items, // the grids found by the monitor
        f,
        fLen    = fields.length,
        gLen    = grids.length, // gridcount
        isArray = Ext.isArray,
        grid, gridData, gridStore, // some vars used while reading the grid content
        field, data, val, bucket, name;

    for (f = 0; f < fLen; f++) {
        field = fields[f];

        if (!dirtyOnly || field.isDirty()) {
            data = field[useDataValues ? 'getModelData' : 'getSubmitData'](includeEmptyText);

            if (Ext.isObject(data)) {
                for (name in data) {
                    if (data.hasOwnProperty(name)) {
                        val = data[name];

                        if (includeEmptyText && val === '') {
                            val = field.emptyText || '';
                        }

                        if (values.hasOwnProperty(name)) {
                            bucket = values[name];

                            if (!isArray(bucket)) {
                                bucket = values[name] = [bucket];
                            }

                            if (isArray(val)) {
                                values[name] = bucket.concat(val);
                            } else {
                                bucket.push(val);
                            }
                        } else {
                            values[name] = val;
                        }
                    }
                }
            }
        }
    }
    // begin new part
    for (g = 0; g < gLen; g++) {
        grid = grids[f];
        gridStore = grid.getStore();
        gridData = [];

        // You will need a identification variable to determine which data should be taken from the grid. Currently this demo implement three options
        // 0 only selected
        // 1 complete data within the store
        // 2 only modified records (this can be splitted to new and updated)
        var ditems = grid.submitData === 0 ? grid.getSelectionModel().getSelection() : 
                     grid.submitData === 1 ? gridStore.getStore().data.items : gridStore.getStore().getModifiedRecords(),
            dlen = ditems.length;
        for(d = 0; d < dLen; d++) {
            // push the model data to the current data list. It doesn't matter of which type the models (records) are, this will simply read the whole known data. Alternatively you may access the rawdata property if the reader does not know all fields.
            gridData.push(ditems[d].data);
        }
        // assign the array of record data to the grid-name property
        data[grid.name] = gridData;
    }
    // end new part
    if (asString) {
        values = Ext.Object.toQueryString(values);
    }
    return values;
}

それが何かのように見えるはずです

Ext.define('Ext.ux.form.Basic', {
    extend: 'Ext.form.Basic',

    /**
     * Creates new form.
     * @param {Ext.container.Container} owner The component that is the container for the form, usually a {@link Ext.form.Panel}
     * @param {Object} config Configuration options. These are normally specified in the config to the
     * {@link Ext.form.Panel} constructor, which passes them along to the BasicForm automatically.
     */
    constructor: function(owner, config) {
        var me = this;

        me.callParent(arguments);
        // We use the monitor here as opposed to event bubbling. The problem with bubbling is it doesn't
        // let us react to items being added/remove at different places in the hierarchy which may have an
        // impact on the dirty/valid state.
        me.gridMonitor = new Ext.container.Monitor({
            selector: 'grid',
            scope: me,
            addHandler: me.onGridAdd,
            removeHandler: me.onGridRemove
        });
        me.gridMonitor.bind(owner);
    },

    onGridAdd: function(grid) {
        var me = this;
        me.mon(grid,'select',me.yourHandler,me);
    },

    onGridRemove: function(grid) {
        var me = this;
        me.mun(grid,'select',me.yourHandler,me);
    },

    /**
     * Return all the {@link Ext.grid.Panel} components in the owner container.
     * @return {Ext.util.MixedCollection} Collection of the Grid objects
     */
    getGrids: function() {
        return this.gridMonitor.getItems();
    },

    /**
     * Find a specific {@link Ext.grid.Panel} in this form by id or name.
     * @param {String} id The value to search for (specify either a {@link Ext.Component#id id} or
     * {@link Ext.grid.Panel name }).
     * @return {Ext.grid.Panel} The first matching grid, or `null` if none was found.
     */
    findGrid: function(id) {
        return this.getGrids().findBy(function(f) {
            return f.id === id || f.name === id;
        });
    },

    getValues: function(asString, dirtyOnly, includeEmptyText, useDataValues) {
        var values  = {},
            fields  = this.getFields().items,
            grids  = this.getGrids().items, // the grids found by the monitor
            f,
            fLen    = fields.length,
            gLen    = grids.length, // gridcount
            isArray = Ext.isArray,
            grid, gridData, gridStore, // some vars used while reading the grid content
            field, data, val, bucket, name;

        for (f = 0; f < fLen; f++) {
            field = fields[f];

            if (!dirtyOnly || field.isDirty()) {
                data = field[useDataValues ? 'getModelData' : 'getSubmitData'](includeEmptyText);

                if (Ext.isObject(data)) {
                    for (name in data) {
                        if (data.hasOwnProperty(name)) {
                            val = data[name];

                            if (includeEmptyText && val === '') {
                                val = field.emptyText || '';
                            }

                            if (values.hasOwnProperty(name)) {
                                bucket = values[name];

                                if (!isArray(bucket)) {
                                    bucket = values[name] = [bucket];
                                }

                                if (isArray(val)) {
                                    values[name] = bucket.concat(val);
                                } else {
                                    bucket.push(val);
                                }
                            } else {
                                values[name] = val;
                            }
                        }
                    }
                }
            }
        }
        // begin new part
        for (g = 0; g < gLen; g++) {
            grid = grids[f];
            gridStore = grid.getStore();
            gridData = [];

            // You will need a identification variable to determine which data should be taken from the grid. Currently this demo implement three options
            // 0 only selected
            // 1 complete data within the store
            // 2 only modified records (this can be splitted to new and updated)
            var ditems = grid.submitData === 0 ? grid.getSelectionModel().getSelection() : 
                         grid.submitData === 1 ? gridStore.getStore().data.items : gridStore.getStore().getModifiedRecords(),
                dlen = ditems.length;
            for(d = 0; d < dLen; d++) {
                // push the model data to the current data list. It doesn't matter of which type the models (records) are, this will simply read the whole known data. Alternatively you may access the rawdata property if the reader does not know all fields.
                gridData.push(ditems[d].data);
            }
            // add the store data as array to the grid-name property
            data[grid.name] = gridData;
        }
        // end new part
        if (asString) {
            values = Ext.Object.toQueryString(values);
        }
        return values;
    }
});

次に、この基本的なフォーム タイプを使用するようにフォームを変更します。

Ext.define('Ext.ux.form.Panel', {
    extend:'Ext.form.Panel',
    requires: ['Ext.ux.form.Basic'],

    /**
     * @private
     */
    createForm: function() {
        var cfg = {},
            props = this.basicFormConfigs,
            len = props.length,
            i = 0,
            prop;

        for (; i < len; ++i) {
            prop = props[i];
            cfg[prop] = this[prop];
        }
        return new Ext.ux.form.Basic(this, cfg);
    }
});

ノート:

これはすべて未テストです!フォームの機能を拡張するために、さまざまな顧客に対して同様のことを行ってきましたが、この方法は非常にうまく機能し、高速であることがわかります。少なくとも、それがどのように行われるかを示す必要があり、フォームを設定したり、レコードをロード/更新したりするために簡単に調整できます。

于 2013-07-12T10:00:48.753 に答える