Reconfigure GridPanel with grouping on GroupingStore - extjs

I have a problem with a GridPanel that uses a GroupingView:
var grid1 = new Ext.grid.GridPanel({
store: new Ext.data.GroupingStore({
fields: [ ]
}),
cm: new Ext.grid.ColumnModel([ ]),
selModel: new Ext.grid.RowSelectionModel({ singleSelect: false }),
view: new Ext.grid.GroupingView({
groupTextTpl: '{text} ({[values.rs.length]} {[values.rs.length > 1 ? "' + BPS.Resource.items + '" : "' + BPS.Resource.item + '"]})'
})
});
I an event I call reconfigure that sets a new store and columnmodel. The store is a GroupingStore and I set what groupField i want to use:
// define the store
var store1 = new Ext.data.GroupingStore({
proxy: new Ext.data.HttpProxy({
url: listConfig.dataURL + '?sort=' + listConfig.defaultSortField + '&dir=' + listConfig.defaultSortDirection,
method: 'POST'
}),
autoLoad: false,
remoteSort: true,
remoteGroup: true,
groupOnSort: false,
groupField: listConfig.groupingColumn,
sortInfo: {
field: listConfig.defaultSortField,
direction: listConfig.defaultSortDirection
},
paramNames: {
start: 'skip',
limit: 'take',
sort: 'sort',
dir: 'dir'
},
reader: new Ext.data.JsonReader()
});
// reconfigure the grid
grid1.reconfigure(store1, new Ext.grid.ColumnModel(listConfig.columnDefinitions));
However, this seem to work the first time it's loaded. It sets grouping on a column, or no grouping at all if I haven't configured it. But after the user turn off grouping in the gridpanel and the same code runs in order to load the configuration it doesn't change it to be grouped.
What can I do to reconfigure the grid to use, or not use, grouping?

I was having issues with a groupingstore. When I modified a field of a record and the grouping was on that column where I modified the field from, the grid did not automatically regroup the records.
Also when adding a new row, the grouping was not correct, the record that was added did not get added in the correct group.
I solved this problem by keeping the current groupBy field in a global var and each time on update or afteredit and added events from the grid I unGrouped and then used groupBy() with the var that contains the current column where the store was grouped on.
Using only grid.getView().refresh(); didn't do the trick.
Question of course is, is this user friendly? Because each time that a field from a row is modified and the grouping is set on the column of that field that was modified, the record will get regrouped and the user might have problems finding the row he was modifying.
Better solution: Only unGroup and then use groupBy() with the var that stored the current groupBy column when the focus on the record that is being edited is lost. SO on the blur event.

I think you attach a listener to the GroupingStore's groupchange event and record the field that was chosen as the grouping field. Then when reconfiguring, you tell the store to group by that field with the groupBy() function or use the ungroup() function to remove the grouping. Then call the grid's view refresh() method.
Note that I haven't tested this so it may be complete rubbish! :-)

Related

Extjs combobox is not auto-selecting the displayField

UPDATE -
I HAVE ALSO MADE A MOCK IN JSFIDDLE http://jsfiddle.net/mAgfU/371/
AND WITH A FORM PANEL : http://jsfiddle.net/kA6mD/2/
I have the bellow comboox.
When I use the following code to set the form values:
this.form.loadRecord(data);
the entire form is acting ok except from the combo.
instead of giving me the displayField, I get the valueField in the display.
As you can see in the image above, the combo should show the word "Walla" (displayField) instead of "1" (valueField)
Ext.define('App.view.ForeignCombo', {
extend: 'Ext.form.ComboBox',
alias: 'widget.foreigncombo',
queryMode: 'local',
displayField: 'Name',
valueField: 'Id',
editable: false,
matchFieldWidth: false,
constructor: function(config) {
Ext.apply(this, config);
Ext.define('BrnadComboModel', {
extend: 'Ext.data.Model',
fields: ['Id', 'Name']
});
this.store = Ext.create('Ext.data.Store', {
model: 'BrnadComboModel',
autoLoad: true,
proxy: {
type: 'ajax',
url: '/api/Brand/',
reader: {
type: 'json',
root: 'Results'
}
},
pageSize: 50,
});
this.callParent();
}
}
);
this is how I use it:
{
"xtype": 'foreigncombo'
, "name": 'Brand.Id'
, "fieldLabel": 'Brand.Id'
}
There is no race bewtween the form display and the combo ajax request, the combo store is autoLoad:true, meaning I see that it has already been loaded...
Thanks
I used your fiddle a an example. Place a breakpoint in line 87 (Ext.ComponentQuery.query('comobobox')....), in this fiddle http://jsfiddle.net/kA6mD/9/, and set a watch to Ext.ComponentQuery.query('combobox')[0].store.data.. you'll notice the store has no data. This may be linked to what I mentioned in the comment.
I know there must be a better way of doing this, but what I usually use as a workaround is either load the store at some point before in the app or use a synchronous Ext.Ajax.request and load each record at a time in the store.
As this is a combo for brands I suppose you could load the store before (i.e. app load) and lookup for the store instead of creating a new one each time you create a foreigncombo component, so the first solution should work.
As for the second workaround it should also work, it takes a little bit more coding but its actually pretty easy. It should look something like this...
Ext.Ajax.request({
url:'your/url/',
async:false,
.....
success:function(response){
var records = Ext.JSON.decode(response.responseText);
for(var m=0; m<records.length; m++){
var record = Ext.create('YourBrandModel',{
abbr:records[m].abbr,
name:records[m].name
});
store.add(record);
}
}
})
You should do this as few times as possible as it may slow down the user experience if it gets called everytime you create a "foreigncombo", so checking if this store exists before creating one might be a good idea.
Please take in cosideration that I have not tested this code, so you may have to tweak it a little in order for it to work. But it should get you on tracks.

Moving rows up and down in an EditorGridPanel

Does anyone have/know of a working example of a moving rows within an EditorGridPanel (or know why it's not working for me)?
I've found few examples, and the ones I've found use this approach:
// calculate the new index, then remove the record from the store, and re-insert it at the new index
grid.getStore().remove(record);
grid.getStore().insert(index, record);
In my case this fails. It looks good in the grid, but 2 DELETE http requests actually get sent to the server, and no PUT. This becomes evident when I reload the page - the moved row has actually been deleted.
He're the basic config of my store:
var remoteJsonStore = new Ext.data.JsonStore({
storeId: 'colStore',
autoDestroy: false,
autoSave: true,
proxy: new Ext.data.HttpProxy({url:'/exercises/collect/data_rows'}),
restful: true,
format: 'json',
disableCaching: false,
autoLoad: true,
writer: new Ext.data.JsonWriter({
encode: false
}),
root: 'data',
idProperty: 'data_row_id',
fields: recordFields,
baseParams:{section_id:GridUtils.properties[gridId]['section_id']},
listeners:{
exception:function(misc){
// stuff....
},
beforewrite:function(store, action, rs, options, arg){
this.baseParams["position"]=rs.rowIndex;
},
beforesave:function(store, data){
// stuff.... }
}
}
});
I had a similar problem when implementing a DnD reordering view. The problem is that the store marks every remove()d record for delete, even if you re-insert it.
Reading the source of Ext.data.Store's remove() method, I found a solution:
remove: function(records, /* private */ isMove) {
See? We can pass a second boolean agument to tell the store we are just moving the record! But being marked as private and not documented, we should take care when upgrading to a new version of the framework.
So the final solution is:
grid.getStore().remove(record, true); // just moving
grid.getStore().insert(index, record);
ExtJS version: 4.1

ExtJS : How to set combobox id?

I have a little problem. At my application Im always building two linked combobox - country and towns(then country are selected - towns began to load). So i thinked - mbe write a constructor and minimized my code? Ok i did it. But i got a problem: i have 2-3 couple of this linked comboboxes on page and when i selected at second combo country, the data (towns) loads at first combo, because it has the same id. Ok - now im trying take a param id to constructor and it didnt work. How set id of combobox then i create an object?
Country combo
comboCountryClass = Ext.extend(Ext.form.ComboBox, {
fieldLabel: 'country',
anchor: '95%',
lazyRender:true,
store:new Ext.data.Store({
proxy: new Ext.data.HttpProxy(
{url: '../lib/getRFB.php?rfb_type=countrys',
method: 'GET'}
),
reader: countryReader,
autoLoad: true
}),
displayField:'country_name',
valueField:'country_id',
triggerAction:'all',
mode:'local',
listeners:{
select:{
fn:function(combo, value) {
var modelCmp = Ext.getCmp(this.town_name_id);
alert(this.town_name_id);
modelCmp.setValue('');
modelCmp.getStore().proxy.setUrl('../lib/getRFB.php');
modelCmp.store.reload({
params: { 'country_id': this.getValue(),rfb_type: 'towns' }
});
}
}
},
hiddenName:'country_id',
initComponent: function() {comboCountryClass.superclass.initComponent.call(this);}})
And town combo
comboTownClass = Ext.extend(Ext.form.ComboBox, {
fieldLabel:'town',
displayField:'town_name',
valueField:'town_id',
hiddenName:'town_id',
anchor: '95%',
id:this.town_name_id || 'youuuu',
store: new Ext.data.Store({
proxy: new Ext.data.HttpProxy(
{url: 'lib/handlers/orgHandler.php?action=read&towns=true',
method: 'GET'}
),
reader: townReader
}),
triggerAction:'all',
mode:'local',
initComponent: function() {comboTownClass.superclass.initComponent.call(this);}})
new comboTownClass({town_name_id:'townFormSearch'})
new comboCountryClass({town_name_id:'townFormSearch'})
You can set the id of the component by doing the following:
new comboTownClass({id:'townComboId'});
new comboCountryClass({id:'countryComboId'});
You can specify a default id, and when you pass an id in the config param it will overwrite the default value.
Although I agree with #Upper Stage you should try to limit the amount of hard-coded id values you have in the form - you can instead grab form elements using the form name instead.
I live by the rule: "never use hardcoded IDs." You can retrieve a unique ID from Ext JS using
Ext.id( null, 'someTextString' )
You will incur more bookkeeping when you use unique IDs, but you will not run into the problem about which you write above.
Sometimes I store unique IDs locally in an object and then reference that instance variable where necessary.
this.idForCombo = Ext.id( null, 'someTextString' );
var myCmp = new SomeConstructor({
id: this.idForCombo,
...more stuff });
myCombobox.id = yourId;

Extjs Dynamic Grid

I'm trying to create a dynamic grid using ExtJS. The grid is built and displayed when a click event is fired then an ajax request is sent to the server to fetch the columns, records and records definition a.k.a store fields.
Each node could have different grid structure and that depends on the level of the node in the tree.
The only way I came up with so far is :
function showGrid(response, request) {
var jsonData = Ext.util.JSON.decode(response.responseText);
var grid = Ext.getCmp('contentGrid' + request.params.owner);
if (grid) {
grid.destroy();
}
var store = new Ext.data.ArrayStore({
id: 'arrayStore',
fields: jsonData.recordFields,
autoDestroy: true
});
grid = new Ext.grid.GridPanel({
defaults: {
sortable: true
},
id: 'contentGrid' + request.params.owner,
store: store,
columns: jsonData.columns,
//width:540,
//height:200,
loadMask: true
});
store.loadData(jsonData.records);
if (Ext.getCmp('tab-' + request.params.owner)) {
Ext.getCmp('tab-' + request.params.owner).show();
} else {
grid.render('grid-div');
Ext.getCmp('card-tabs-panel').add({
id: 'tab-' + request.params.owner,
title: request.params.text,
iconCls: 'silk-tab',
html: Ext.getDom('grid-div').innerHTML,
closable: true
}).show();
}
}
The function above is called when a click event is fired
'click': function(node) {
Ext.Ajax.request({
url: 'showCtn',
success: function(response, request) {
alert('Success');
showGrid(response, request);
},
failure: function(results, request) {
alert('Error');
},
params: Ext.urlDecode(node.attributes.options);
}
});
}
The problem I'm getting with this code is that a new grid is displayed each time the showGrid function is called. The end user sees the old grids and the new one. To mitigate this problem, I tried destroying the grid and also removing the grid element on each request, and that seems to solve the problem only that records never get displayed this time.
if (grid) {
grid.destroy(true);
}
The behaviour I'm looking for is to display the result of a grid within a tab and if that tab exists replaced the old grid.
Any help is appreciated.
When you are trying to add your grid to the tab like this:
html:Ext.getDom('grid-div').innerHTML,
Ext is not aware of it being a valid grid component. Instead, you are simply adding HTML markup that just happens to look like a grid, but the TabPanel will not be aware that it is a grid component.
Instead you should add the grid itself as the tab (a GridPanel is a Panel and does not need to be nested into a parent panel). You can do so and also apply the needed tab configs like this:
Ext.getCmp('card-tabs-panel').add({
Ext.apply(grid, {
id: 'tab-' + request.params.owner,
title: request.params.text,
iconCls: 'silk-tab',
closable: true
});
}).show();
BTW, constantly creating and destroying grids is not an ideal strategy if you can avoid it. It might be better to simply hide and re-show grids (and reload their data) based on which type of grid is needed if that's possible (assuming the set of grid types is finite).
A potential option is to use the metaData field on the JsonStore that allows dynamic reconfiguring of the grid columns as per new datasets.
From
One of the most helpful blog posts about this that Ive found is this one:
http://blog.nextlogic.net/2009/04/dynamic-columns-in-ext-js-grid.html and the original info is well documented at http://docs.sencha.com/ext-js/3-4/#!/api/Ext.data.JsonReader

ExtJs checkboxselectionmodel

I am using GridPanel w/CheckboxSelectionModel for item selection.
In the edit mode, where some options were already picked, I am trying to pre-select the rows when loading the form.
...
store.load();
//curSelections is an array containing the some ForeingKey IDs of the selected records.
...
for (var i = 0; i < curSelections.length; i++) {
console.log('found personel ' + curSelections[i] + ' at ',
store.findExact('Id', curSelections[i]));
selectedRecords.push(store.findExact('Id', curSelections[i]));
}
//everything is fine according to console log.
checkGrid.getSelectionModel().selectRecords(selectedRecords, true);
formWin.show();
this does not work.
I try to call" selectRecords" also on some other page/form events, but none of those even fires.
grid.addListener('show',
grid.on('show',
formWin.on('activate',
formWin.on('show',....
some of the grid code
var sm = new Ext.grid.CheckboxSelectionModel({
singleSelect: false,
sortable: false,
checkOnly: true
});
checkGrid = new Ext.grid.GridPanel({
xtype: 'grid',
store: obPersonelStore,
loadMask: true,
layout: 'fit',
height: 120,
id: 'grdIsBirimiPersonelListesi',
columns: [
sm,
{
I am missing something simple, but dont know what it is.
Any kind of help is greatly appreciated.
Store.findExact returns a numeric index. SelectionModel.selectRecords expects an array of Record objects. Have you tried selectRows instead? Either that, or use store.getAt to retrieve records by index to pass to selectRecords().
try:
var store = new Ext.data.Store({
...
});
var grid = new Ext.grid.GridPanel({
store: store,
...
});
store.on('load', function() {
grid.getSelectionModel().selectFirstRow();
});
store.load();
I'm not 100% certain what you want to achieve. You said:
I find the selected rows of the entire list
Do you mean you want to select every row? In that case you can use the selectAll() method of the CheckboxSelectionModel.
If you only want to select some of the rows then I'd need to see the code you're using to get those rows in the first place but it could be that you want to use selectRecords() rather than selectRows().

Resources