Форма с текстовым полем и сеткой: отправлять все значения на сервер

josei спросил: 28 марта 2018 в 03:46 в: extjs

В формах создания и обновления иногда необходимо предоставить пользователю возможность динамически добавлять поля к значениям одного и того же типа (более одного телефона, более одного адреса и т. д.).

Я изучаю несколько возможностей для этого.

Один из них - использовать сетку как поле формы.

Однако у меня есть сомнения в том, как лучше всего реализовать эту идею , особенно о том, как отправить все значения полей формы (текстовое поле и сетку) на сервер (а затем, как загрузить их позже в форме для редактирования).

Скрипать с некоторыми идеями:

Один с плагином для сокета https://fiddle.sencha.com/#view/editor&fiddle/2ftp

Еще один из них с номером gplugin на https://fiddle.sencha.com/#view / редактор & амп; скрипку / 2fto


1 ответ

Есть решение
Alexander ответил: 28 марта 2018 в 05:48

Не уверен насчет "лучшего в реализации", но я видел так много требований к многозначному вводу, что для повторного использования у меня в наборе инструментов есть поле сетки, похожее на следующее:

Ext.define('Ext.ux.GridField', {
    extend: 'Ext.form.FieldContainer',
    alias: 'widget.gridfield',
    initComponent: function () {
        var me = this;
        if(!me.columns) me.columns = {
             dataIndex: 'field1'
        };
        if(!me.mapFn) me.mapFn = function(value) {
            if(Ext.isObject(value)) return value;
            return {
                field1: value
            };
        };
        if(!me.unmapFn) me.unmapFn = function(record) {
            return record.get('field1');
        };
        me.grid = Ext.widget(Ext.apply({
            xtype: 'grid',
            viewConfig: {
                markDirty: false
            },
            store: me.store || Ext.create('Ext.data.Store', {
                fields: me.columns.map(function(column) {
                    return {
                        name: column.dataIndex,
                        type: column.dataType || 'auto',
                        defaultValue: column.defaultValue
                    };
                }),
                listeners: {
                    update: me.updateValue,
                    datachanged: me.updateValue,
                    scope: me
                }
            }),
            columns: [{
                xtype: 'actioncolumn',
                getClass: function () {
                    return 'x-fa fa-times'
                },
                handler: function(grid, rowIndex, colIndex, item, e, record) {
                    grid.getStore().remove(record);
                },
                width: 35
            }].concat(me.columns),
            bbar: [{
                xtype: 'button',
                iconCls: 'x-fa fa-pencil',
                text: 'Add',
                handler: function(btn) {
                    var grid = btn.up('grid'),
                        store = grid.getStore(),
                        record = store.add(Ext.clone(me.emptyRecord) || {})[0];
                    grid.getPlugin('editor').startEditByPosition({
                        row: store.indexOf(record),
                        column: 1
                    });
                }
            }],
            plugins: [
                Ext.create('Ext.grid.plugin.CellEditing', {
                    pluginId: 'editor',
                    clicksToEdit: 1
                })
            ]
        }, me.gridConfig)); // "gridConfig" config can override everything on each instance.
        me.hiddenField = Ext.widget({
            xtype: 'hiddenfield',
            name: me.name,
            value: '',
            allowNull: false,
            rawToValue: function (raw) {
                return raw;
            },
            valueToRaw: function (value) {
                return value;
            },
            getRawValue: function () {
                return Ext.valueFrom(this.rawValue, '')
            },
            isEqual: function (a, b) {
                return Ext.encode(a) == Ext.encode(b)
            },
            listeners: {
                change: function(field, nV, oV) {
                    if(!Ext.isArray(nV)) nV = [nV];
                    var store = me.grid.getStore();
                    store.removeAll();
                    store.add(nV.map(me.mapFn));
                }
            }
        });
        Ext.apply(me, {
            layout: 'fit',
            items: [{
                xtype:'container',
                border: 1,
                style: {
                    borderColor: '#d0d0d0',
                    borderStyle: 'solid'
                },
                items: [me.grid]
            }, me.hiddenField]
        });
        me.callParent(arguments);
    },
    updateValue: function() {
        var me = this,
            grid = me.grid,
            hiddenField = me.hiddenField,
            nV = grid.getStore().getRange().map(me.unmapFn, me),
            oV = me.hiddenField.getValue();
        if(!oV || Ext.isArray(oV) && Ext.encode(nV) != Ext.encode(oV)) {
            hiddenField.suspendCheckChange++;
            hiddenField.setValue(nV);
            hiddenField.suspendCheckChange--;
            me.fireEvent('change', me, nV, oV);
        }
    }
});

, который затем можно использовать следующим образом:

},{
    xtype: 'gridfield',
    fieldLabel: 'Contacts',
    name: 'contacts',
    columns: [{
        text: 'Type',
        dataIndex: 'type',
        editor:{
            xtype: 'combobox',
            name: 'type',
            valueField: 'name',
            displayField: 'name',
            store: combostore,
            queryMode: 'local'
        },
        flex: 0.7
    },{
        text: 'Description',
        dataIndex: 'description',
        editor:{
            xtype: 'textfield',
            name: 'description'
        },
        flex: 1
    }],
    mapFn: function(value) {
        return value;
    },
    unmapFn: function(record) {
        return record.getData();
    }
}, {

Я сделал для вас скрипку на основе вашей скрипки, включая операции загрузки и сохранения в форме, но в ExtJS 6.x. И я проверил, что он работает и с ExtJS 5, хотя вы должны добавить рабочие значки.

josei ответил: 28 марта 2018 в 06:52
Спасибо Александр. Отличная помощь (как всегда). Ваш пример очень полный, и он мне очень помогает. Мне нравится это решение. Я буду изучать это построчно (и постараюсь все правильно понять).
Alexander ответил: 28 марта 2018 в 06:55
@josei Всегда пожалуйста.
josei ответил: 12 мая 2018 в 07:55
Александр, компонент работает нормально, но у меня есть вопрос в обновлении. Я попытался одним запросом (используя PHP и MYSQL) внести в хранилище в каждой строке все данные, необходимые для обновления записи, но я не получил их в отношении данных, необходимых для поля сетки (многозначного). Как ты это делаешь? данные уже все доступны в магазине, или когда вы выбираете запись для редактирования, вы делаете новый запрос, отправляя идентификатор этой конкретной записи для фильтрации необходимых данных в поле сетки?