PDA

View Full Version : Grid as Form Field



KimSchneider
27 Apr 2012, 5:08 AM
Hi all,

I had the requirement that I needed a remote grid as form field. So I wrote a grid panel component which extends Ext.form.field.Base.

Everything worked fine in Ext 4.0.7, but things seem to have changed with Ext 4.1. The only thing I see is the header of the grid an nothing else.

This is my code:

Ext.define('ux.form.remote.Grid', { extend : 'Ext.grid.Panel',


mixins : {
field : 'Ext.form.field.Base'
},


alias : 'widget.remotegrid',


height : 150,


_value : null,


initComponent : function() {
this._initStore();
this._initCols();


this.selModel = {
mode : this.settings.gridType === 'grid' ? 'SINGLE' : 'SIMPLE'
};


this.callParent(arguments);


this.on('selectionchange', this._selectionchange, this);


this.addEvents('change');
},


_initStore : function() {
var fields = this.settings.reader.fields;


this.store = Ext.create('Ext.data.Store', {
fields : fields,
proxy : {
type : 'ajax',
url : BASE_URL + 'remote/setting',
extraParams : {
id : this.settingRecord.get('agent_id'),
information : this.settings.store && this.settings.store.information
},
reader : {
type : 'json',
root : 'data',
messageProperty : 'message'
},
listeners : {
exception : function(proxy, res, op) {
this._exception(op.error);
},
scope : this
}
},
listeners : {
load : this._load,
scope : this
}
});


this.settings.sort && this.store.sort(this.settings.sort.field, this.settings.sort.direction);
},


_initCols : function() {
this.columns = this.settings.dataview.columns;


Ext.Array.each(this.columns, function(c) {
c.flex = c.width;
delete c.width;
});
},


_exception : function(error) {
if(Ext.isObject(error)) {
error = error.statusText;
}
this.getView().emptyText = '<div class="no-data-message">' + L10N.get(error, 'remoting') + '</div>';
this.store.removeAll();
},


_load : function() {
var values = this._value ? this._value.split('|,|') : [];
var sm = this.getSelectionModel();
sm.deselectAll();
Ext.each(values, function(v) {
var idx = this.store.find(this.settings.valueColumn, v);
idx > -1 && sm.select(idx, true);
}, this);
},


_selectionchange : function(m, selected) {
var vs = [];
Ext.each(selected, function(s) {
vs.push(s.get(this.settings.valueColumn));
}, this);


this._value = vs.join('|,|');
},


isValid : function() {
return this.settings.allowBlank || this._value != null;
},


getValue : function() {
return this._value;
},


setValue : function(v) {
this._value = v;
this.store.load();
}
});

Resulting HTML:

<table id="remotegrid-1287" class="x-panel x-grid-with-row-lines x-panel-default x-grid" style="height: 150px; width: 300px; " cellpadding="0"><div id="headercontainer-1288" class="x-grid-header-ct x-docked x-grid-header-ct-default x-docked-top x-grid-header-ct-docked-top x-grid-header-ct-default-docked-top x-box-layout-ct" style="border: 1px; left: 0px; top: 0px; width: 300px; "><div id="headercontainer-1288-innerCt" class="x-box-inner " role="presentation" style="width: 217px; height: 22px; "><div id="headercontainer-1288-targetEl" style="position:absolute;width:20000px;left:0px;top:0px;height:1px"><div id="key" class="x-unselectable x-column-header-align-left x-box-item x-column-header x-unselectable-default x-column-header-sort-undefined x-column-header-sort-null x-column-header-first" style="border: 1px; width: 100px; margin: 0px; height: auto; left: 0px; top: 0px; "><div id="key-titleEl" class="x-column-header-inner" style="height: auto; padding-top: 3px; "><span id="key-textEl" class="x-column-header-text">Laufwerk</span><div id="key-triggerEl" class="x-column-header-trigger"></div></div><div id="key-clearEl" class="x-clear" role="presentation"></div></div><div id="label" class="x-unselectable x-column-header-align-left x-box-item x-column-header x-unselectable-default x-column-header-sort-undefined x-column-header-sort-ASC x-column-header-last" style="border: 1px; width: 100px; margin: 0px; height: auto; left: 100px; top: 0px; "><div id="label-titleEl" class="x-column-header-inner" style="height: auto; padding-top: 3px; "><span id="label-textEl" class="x-column-header-text">Bezeichnung</span><div id="label-triggerEl" class="x-column-header-trigger"></div></div><div id="label-clearEl" class="x-clear" role="presentation"></div></div></div></div></div></table>

Screenshot attached.

Does anybody have a hint how to fix this issue? Thanks!

scottmartin
30 Apr 2012, 11:55 AM
Do you see any errors in the console? If you use ext-all-dev, do you see any warnings that need to be corrected?

Regards,
Scott.

satollo
1 May 2012, 8:47 AM
I've the same problem...
But in my case it seems that the body of the table is detached from the header and rendered after all other fields, as you can see in the screenshot below:

34732

KimSchneider
1 May 2012, 9:36 PM
No errors or warnings at all. I did use ext-all-dev.

Looks like I am not alone :/

Any workarounds, suggestions or ideas?

satollo
4 May 2012, 2:55 AM
Currently, I solved including my grid in a FieldContainer...

KimSchneider
4 May 2012, 4:27 AM
thanks for your suggestion! adding it to a fieldcontainer results in this little boy here


<table id="fieldcontainer-1293" class="x-container x-form-item x-container-default x-anchor-form-item" style="border-width: 0px; table-layout: fixed; width: 300px; " cellpadding="0" data-errorqtip=""><tbody><tr id="fieldcontainer-1293-inputRow"><td id="fieldcontainer-1293-labelCell" style="display:none;" valign="top" halign="left" width="105" class="x-field-label-cell"><label id="fieldcontainer-1293-labelEl" class="x-form-item-label x-form-item-label-left" style="width:100px;margin-right:5px;"></label></td><td class="x-form-item-body " id="fieldcontainer-1293-bodyEl" role="presentation" colspan="3" style="width: 100%; "><table id="remotegrid-1294" class="x-panel x-grid-with-row-lines x-panel-default x-grid" style="height: 150px; width: 300px; " cellpadding="0"><div id="headercontainer-1295" class="x-grid-header-ct x-docked x-grid-header-ct-default x-docked-top x-grid-header-ct-docked-top x-grid-header-ct-default-docked-top x-box-layout-ct" style="border-width: 1px; width: 300px; left: 0px; top: 0px; "><div id="headercontainer-1295-innerCt" class="x-box-inner " role="presentation" style="width: 315px; height: 22px; "><div id="headercontainer-1295-targetEl" style="position:absolute;width:20000px;left:0px;top:0px;height:1px"><div id="key" class="x-unselectable x-column-header-align-left x-box-item x-column-header x-unselectable-default x-column-header-sort-undefined x-column-header-sort-null x-column-header-first" style="border-width: 1px; margin: 0px; height: auto; width: 149px; left: 0px; top: 0px; "><div id="key-titleEl" class="x-column-header-inner" style="height: auto; padding-top: 3px; "><span id="key-textEl" class="x-column-header-text">Laufwerk</span><div id="key-triggerEl" class="x-column-header-trigger"></div></div><div id="key-clearEl" class="x-clear" role="presentation"></div></div><div id="label" class="x-unselectable x-column-header-align-left x-box-item x-column-header x-unselectable-default x-column-header-sort-undefined x-column-header-sort-ASC x-column-header-last" style="border-width: 1px; margin: 0px; height: auto; width: 149px; left: 149px; top: 0px; "><div id="label-titleEl" class="x-column-header-inner" style="height: auto; padding-top: 3px; "><span id="label-textEl" class="x-column-header-text">Bezeichnung</span><div id="label-triggerEl" class="x-column-header-trigger"></div></div><div id="label-clearEl" class="x-clear" role="presentation"></div></div></div></div></div></table><div id="remotegrid-1294-body" class="x-panel-body x-grid-body x-panel-body-default x-panel-body-default x-layout-fit" style="width: 300px; left: 0px; height: 127px; top: 23px; "><div id="gridview-1296" class="x-grid-view x-fit-item x-grid-view-default x-unselectable" style="overflow: auto; -webkit-user-select: none; margin: 0px; width: 298px; height: 125px; " tabindex="-1"><table class="x-grid-table x-grid-table-resizer" border="0" cellspacing="0" cellpadding="0" style="width:298px;height:1px;"><tbody><tr class="x-grid-header-row"><th class="x-grid-col-resizer-key" style="width: 149px; height: 0px;"></th><th class="x-grid-col-resizer-label" style="width: 149px; height: 0px;"></th></tr></tbody></table><div class="no-data-message">remoting.internalerr</div></div></div><div id="fieldcontainer-1293-overflowPadderEl" style="font-size: 1px; width: 1px; height: 1px; display: none; "></div></td></tr></tbody></table>

34895

I am becoming more and more frustrated about Ext, because this worked using the RCs, but the RCs have some other heavy errors. It worked in 4.0.7, too, but scrolling was just awfull and so on.

Long story short, we need a fix for this!

scottmartin
4 May 2012, 5:13 AM
Please provide me with a self contained working example with a JSON file for data and I will have a better look.

Regards,
Scott.

satollo
6 May 2012, 5:14 AM
This is a little example that shows a grid inside a form as a field.
In the 4.0.x version everything worked fine, in 4.1 I need to place it inside a field container, otherwise the layout is broken.
I think the problem is the rendering of fields, layout of 'labelable' now uses a <table> element and a custom component field (which doesn't extends Ext.form.field.Base) needs more implementation detail to provide the right <tbody> content:

34935
In the zip you find the code to reproduce the example.

evant
6 May 2012, 6:54 AM
Using form.field.Base as a mixin certainly isn't a good idea. The field behaviour is provided by form.field.Field. A good example of this is the slider component.

KimSchneider
11 May 2012, 1:57 AM
Thanks for your hint evant.

I thought it would be a good wait to extend Ext.grid.Panel and use Ext.form.field.Base as a mixin, but that broke it. I changed it and extend Ext.form.field.Base and create the Grid in the onRender method which works.

Is there a better solution to do this?

andrecardoso
17 Sep 2012, 8:57 AM
Hi KimSchneider,

I'm trying to do same thing. Can you provide a sample of your solution?

Thanks.

KimSchneider
17 Sep 2012, 11:58 PM
Ext.define('ux.form.remote.Grid', { extend : 'Ext.form.field.Base',


require : [
'Ext.grid.Panel'
],


height : 150,


_grid : null,
_value : null,


initComponent : function() {
this.callParent(arguments);


this.addEvents('change');
},


_getStore : function() {
var fields = [];


var store = Ext.create('Ext.data.Store', {
fields : fields,
proxy : {
type : 'ajax',
url : 'data',
reader : {
type : 'json',
root : 'data',
messageProperty : 'message'
},
listeners : {
exception : function(proxy, res, op) {
this._exception(op.error);
},
scope : this
}
},
listeners : {
load : this._load,
scope : this
}
});

return store;
},


_getCols : function() {
var columns = [];

return columns;
},

_initGrid : function() {
this._grid = Ext.create('Ext.grid.Panel', {
renderTo : this.getInputId(),
store : this._getStore(),
columns : this._getCols(),
height : this.height,
listeners : {
selectionchange : this._selectionchange,
scope : this
}
});
},


_exception : function(error) {
if(this._grid) {
this._grid.getView().emptyText = '<div class="no-data-message">' + error + '</div>';
this._grid.getStore().removeAll();
}
},


_load : function() {
if(!this._grid) {
return;
}

var values = this._value ? this._value.split('|,|') : [];
var sm = this._grid.getSelectionModel();
sm.deselectAll();
Ext.each(values, function(v) {
var idx = this._grid.getStore().find(YOUR_VALUE_COLUMN, v);
idx > -1 && sm.select(idx, true);
}, this);
},


_selectionchange : function(m, selected) {
var vs = [];
Ext.each(selected, function(s) {
vs.push(s.get(YOUR_VALUE_COLUMN));
}, this);


this._value = vs.join('|,|');
},


onRender : function() {
this.callParent(arguments);

this._initGrid();
},


isValid : function() {
return this.allowBlank || this._value != null;
},


getValue : function() {
return this._value;
},


setValue : function(v) {
this._value = v;

this._grid && this._grid.getStore().load();
}
});

tiago.teixeira
29 Oct 2012, 10:02 AM
Hi,

I just would like to add that the solution presented will insert the grid inside an input tag (which is the default element created in field.base) and thus will be shown a textbox instead and the grid will be hidden.

To overcome this, overwrite the fieldSubTpl (http://docs.sencha.com/ext-js/4-1/#!/api/Ext.form.field.Base-cfg-fieldSubTpl) XTemplate, or a div or something.

Hope this helps.

Cheers!

Tiago Teixeira