I want to Reorder Rows in an ExtJs grid? - javascript

I am using ExtJs 4.2 and I have a Ext.grid.Panel and I have data coming in, but i want them to be ordered upon ingestion based on a boolean flag with things that have true for one field at the top, true for another field next, with false in both fields coming at the bottom. So far I have editing the sorters as prescribed below.
me.requesterListStore = new Ext.create('Ext.data.Store', {
id: 'requesterListStore',
model: 'Connex.Request.Model.RequesterModel',
buffered: true,
pageSize: 100,
leadingBufferZone: 50,
autoLoad: false,
remoteFilter: false,
purgePageCount: 5,
remoteSort: false,
sortOnLoad: true,
sorters: [
{
property: 'isSmartIndexed',
direction: 'DESC'
},
{
property: 'isAutoIndexed',
direction: 'DESC'
}
],
proxy: {
type: 'ajax',
url: $context + 'services/requester/search',
actionMethods: {
read: 'POST'
},
doRequest: function (operation, callback, scope) {
var writer = this.getWriter(),
request = this.buildRequest(operation, callback, scope);
if (operation.allowWrite()) {
request = writer.write(request);
}
Ext.apply(request, {
headers: this.headers,
timeout: this.timeout,
scope: this,
callback: this.createRequestCallback(request, operation, callback, scope),
method: this.getMethod(request),
jsonData: this.jsonData,
disableCaching: false // explicitly set it to false, ServerProxy handles caching
});
Ext.Ajax.request(request);
return request;
},
reader: {
type: 'json',
root: 'content',
totalProperty: 'total',
idProperty: 'id'
},
writer: {
writer: new Ext.data.JsonWriter({
getRecordData: function (record) {
return record.data;
}
})
}
}
});

sorters: [{
property: 'isSmartIndexed',
direction: 'DESC' // or 'ASC'
}, {
property: 'isAutoIndexed',
direction: 'DESC' // or 'ASC'
}]
Add these sorters to your store.
True is always bigger than false ;)
Keep attenction, you can't use sortingFuntions on a bufferedStore like written here:
If the store is buffered, then prefetchData is stored by index, this invalidates all of the prefetchedData.
because in your case you will order only the displayed data on the grid, and not the others that will be loaded.
Test it in this fiddle.

Related

ExtJs getTotalCount() not returning the number of records in the store

When I invoke a function from controller that loads data in the store in the following manner,
var store= new Ext.getStore('MyStore');
store.load();
The response header shows that the following JSON data is returned,
{"usrdata":[{"name":"John",
"roll":"5",
"address":"abcd"
}]
}
but the problem is when I write
console.log(store.getTotalCount());
it shows '0' (zero) on the console.
Can somebody please help me identify why is it not showing the actual count of the number of records in the store.
I feel it might be because store has not finished loading when the function is invoked (may be I am not correct).
following is the code of my store:
Ext.define('MyApp.store.MyStore', {
extend: 'Ext.data.Store',
model: 'MyApp.model.MyModel',
timeout : 60000,
proxy: {
type: 'ajax',
api: {
create: 'php/insert.php',
read: 'php/read.php',
update: 'php/update.php',
destroy: 'php/delete.php',
},
reader: {
type: 'json',
root: 'usrdata',
successProperty: 'success'
},
writer: {
type: 'json',
writeAllFields: true,
encode: true,
root: 'usrdata'
}
},
autoLoad: true,
});
Use the callback in the load method to get the record count: http://docs.sencha.com/extjs/4.2.2/#!/api/Ext.data.Store-method-load
store.load({
scope: this,
callback: function(records, operation, success) {
// the operation object
// contains all of the details of the load operation
console.log(records.length);
// Alternative
console.log(store.getTotalCount());
}
});
You need a tiny change in your store definition
Ext.define('MyApp.store.MyStore', {
extend: 'Ext.data.Store',
model: 'MyApp.model.MyModel',
timeout : 60000,
proxy: {
type: 'ajax',
api: {
create: 'php/insert.php',
read: 'php/read.php',
update: 'php/update.php',
destroy: 'php/delete.php',
},
reader: {
type: 'json',
root: 'usrdata',
totalProperty : '<the_node_of_json_response_which_holds_the_count>'
successProperty: 'success'
},
writer: {
type: 'json',
writeAllFields: true,
encode: true,
root: 'usrdata'
}
},
autoLoad: true,
});
PS - your service needs to return the count. getTotalCount() does not return how many records your store contains, it returns the number that the totalProperty of reader object holds.
So if your service is returning the data -
{
"total": 122,
"offset": 0,
"users": [
{
"id": "ed-spencer-1",
"value": 1,
"user": {
"id": 1,
"name": "Ed Spencer",
"email": "ed#sencha.com"
}
}
]
}
your reader object would look like -
reader: {
type: 'json',
root: 'usrdata',
totalProperty : 'total'
successProperty: 'success'
},
Just in case we are solving the wrong problem. Usually you would want a total counter to be always returned from the server along your data, this way pagination etc will all work automatically. See here for examples:
{
"total": 122,
"offset": 0,
"users": [
{
"id": "ed-spencer-1",
"value": 1,
"user": {
"id": 1,
"name": "Ed Spencer",
"email": "ed#sencha.com"
}
}
]
}

Extjs 4.2 remote filter on combobox

I have a really strange problem with remote store wich looks like this:
store:
Ext.define('freetextOrder.store.Attachment', {
extend: 'Ext.data.Store',
model: 'freetextOrder.model.Attachment',
autoLoad: false,
proxy: {
actionMethods: {
create: "POST",
read: "POST",
update: "POST",
destroy: "POST"
},
type: 'ajax',
filterParam: 'filter',
remoteFilter: true,
autoSync: true,
api: {
read: 'ajax/Attachment/Cartarticle/Init',
update: 'ajax/Attachment/Cartarticle/Update',
create: 'ajax/Attachment/Cartarticle/Create',
destroy: 'ajax/Attachment/Cartarticle/Destroy'
},
reader: {
type: 'json',
root: 'results',
successProperty: 'success'
},
writer: {
type: 'json',
allowSingle: false
},
extraParams: {sid: config.sid}
},
listeners: {
datachanged: function (store) {
if (Ext.getCmp('attachmentGrid'))
if (store.getCount() > 0) {
Ext.getCmp('attachmentGrid').show();
} else {
Ext.getCmp('attachmentGrid').hide();
}
}
}
});
model:
Ext.define('freetextOrder.model.Attachment', {
extend: 'Ext.data.Model',
fields: [
{name: 'id', type: 'int'},
{name: 'cartarticle_id', type: 'int'},
{name: 'orig_filename', type: 'string'},
{name: 'upload_time', type: 'date'}
]
});
And my mission impossible, load the filter from the store:
{
xtype: 'combobox',
queryMode: 'local',
mode: 'local',
fieldLabel: 'template',
id: 'attachmentTemplate',
name: 'test',
store: Ext.create('freetextOrder.store.Attachment'),
valueField: 'cartarticle_id',
displayField: 'orig_filename',
lazyInit: false,
editable: true,
invalidCls: '',
listeners: {
afterrender: function () {
var combo = Ext.getCmp('attachmentTemplate')
combo.getStore().clearFilter(true);
combo.getStore().addFilter({property: 'id', value: config.options.attTemplateIds});
combo.getStore().load();
console.log(combo.getStore().getById(49));
}
}
}
The problem is the event wich i am trying to use, i tried everything to make the damn thing load the store elements, but it just wont budge.
The console.log(combo.getStore().getById(49)); returns an object so the store is loaded. but somhow it fails to load into the options of the combobox it self....
WIERD PART IS:
When i go to the page and execute the code in chrome comand prompt:
var combo = Ext.getCmp('attachmentTemplate')
combo.getStore().clearFilter(true);
combo.getStore().addFilter({property: 'id', value: config.options.attTemplateIds});
combo.getStore().load();
The options get loaded. i am on the end of my rope. i have to past the config.options.attTemplateIds to the filter. tht is the only requirement. and tht value is only available where the xtype: 'combobox', is defined.
For idiot sake i even tried the most hack option setTimeout around the elements... still nothing... really strange behavior.
There are two things or events: the first is combo's afterRender, the second is store's load;
combo.getStore().getById(49) must use after the second event; but you put it in the combo's afterRender, while the data of store might be not already!
As i stumbeld on this question after a year and wasted AGAIN 4h trying to get it to work, without succes.. and after i rememberd the workaround.. im posting it for others to use.
You can use the extra params for your filtering. Just have to do somthing like this
var store = Ext.getStore('xxxx');
store.getProxy().setExtraParam("xxx", newValue);
store.load();

jTable Master record Id not being sent on Child record's update request

$('#PermissionGroupGrid').jtable({
ajaxSettings: {
type: 'GET',
dataType: 'json'
},
sorting: true,
paging: true,
useBootstrap: true,
pageSize: 5,
title: 'List of Permission Group',
actions: {
listAction: '/PermissionGroup/List',
deleteAction: '/PermissionGroup/Delete',
updateAction: '/PermissionGroup/Update',
createAction: '/PermissionGroup/Create'
},
defaultSorting: 'PermissionGroupName ASC',
fields: {
Id: {
key: true,
create: false,
edit: false,
list: false
},
Permissions: {
title: 'Permissions',
width: '5%',
sorting: false,
edit: false,
create: false,
display: function (permissionData) {
var $img = $('<img src="../../Images/list_metro.png" title="Assign Permissions" />');
$img.click(function () {
console.log(permissionData);
console.table(permissionData);
$('#PermissionGroupGrid').jtable('openChildTable',
$img.closest('tr'),
{
ajaxSettings: {
type: 'GET',
dataType: 'json'
},
title: permissionData.record.PermissionGroupName + ' - Permissions',
actions: {
listAction: '/Permission/ListPermission?PermissionGroupId=1',
deleteAction: '/Demo/DeleteExam',
updateAction: '/Demo/UpdateExam',
createAction: '/Demo/CreateExam'
},
fields: {
PermissionGroupId: {
type: 'hidden',
defaultValue: permissionData.record.Id
},
Id: {
key: true,
create: false,
edit: false,
list: false
},
PermissionName: {
title: 'Permission Name'
}
}
}, function (data) {
data.childTable.jtable('load');
});
});
return $img;
}
},
PermissionGroupName: {
title: 'PermissionGroupTitle'
}
}
});
$('#PermissionGroupGrid').jtable('load');
When any of the child record is requesting for Update, child record's Id is being sent in the GET request but not the Id of the Master record. I followed the demo on jtable.org exactly. When console.log 'permissionData.record.Id' I can see the master record's Id. FTR, both Master and Child table's key column has name 'Id'.
Can some one please suggest a solution?
Based on jTable 2.4.0 debugging, defaultValue is used only on create form. If you are editting existing item record[fieldName] is used instead. In your case record["PermissionGroupId"]. That means you need to include PermissionGroupId field on your child record object to make it work.

Sencha Store proxy is not getting called

I want to load store data dynamically and don't want to use model for this. if I provide data list gets populated but if I use store's proxy it doesn't get called and url is not getting hit. Please help.
Ext.define('TrainEnquiry.view.SearchTrainResults', {
extend: 'Ext.List',
xtype: 'searchedtrainresult',
requires: 'Ext.data.proxy.JsonP',
config: {
itemId: 'searchedtrainresult',
title: 'Train Result:',
itemTpl: '<div class="myContent">'+
'<div><b>{number}</b> </div>' +
'</div>',
store: {
fields: ['number'],
/*data: [
{number: 'Cowper'},
{number: 'Everett'},
{number: 'University'},
{number: 'Forest'}
]*/
proxy: {
url: 'http://abc.amazonaws.com/search.json',
type:'jsonp',
extraParams : {
'q' : '12313'
},
reader: {
type: 'json',
},
success: function() {
debugger;
console.log('success');
},
failure: function() {
debugger;
console.log('failure');
}
}
},
onItemDisclosure: true
}
});
I think your "fields" config option needs to be a proper Ext.data.Field object, so maybe this would work:
Ext.define('TrainEnquiry.view.SearchTrainResults', {
...
config: {
...
store: {
fields: [ { name: 'number', type: 'string'} ],
proxy: {
...
}
},
...
}
});
(Reference from Sencha forums)
You could try removing the pageParam and startParam from your proxy. Just like this
Ext.create('Ext.data.Store', {
storeId:'UserStore',
autoLoad: true,
model: 'UserModel',
proxy: {
type: 'jsonp', // Because it's a cross-domain
url : 'https://api.twitter.com/1/lists/members.json?owner_screen_name=Sencha&slug=sencha-team&skip_status=true',
reader: {
type: 'json',
root: 'users' // The returned JSON will have array
// of users under a "users" property
},
// Removing pageParam and startParam
pageParam: undefined,
startParam: undefined
}
});
Here is an example http://jsfiddle.net/alexrom7/YNTuN/
Try changing the type of your proxy store to Ajax (type: 'ajax'). Just like this
Ext.create('Ext.data.Store', {
model: 'User',
proxy: {
type: 'ajax',
url: '/test.json',
reader: {
type: 'json',
}
},
autoLoad: true
});

Remote Filtering with ListFilter in ExtJS Grid Column Header

I am using ListFilter plugin to filter results on a Grid panel. The column definition is.
{
header: 'Provider',
filter: {
type: 'list',
store: Ext.getStore('MyApp.store.Provider'),
dataIndex: 'provider_id',
labelField: 'name'
}
}
MyApp.store.Provider is created as
Ext.create('Ext.data.Store', {
storeId: 'MyApp.store.Provider',
autoDestroy: true,
autoLoad: {start: 0, limit: 50},
autoSync: true,
model: 'MyApp.model.Provider',
pageSize: 50,
proxy: {
type: 'ajax',
api: {
create: 'proxy/provider/create',
read: 'proxy/provider/read',
update: 'proxy/provider/update',
destroy: 'proxy/provider/destroy'
},
reader: {
type: 'json',
root: 'data',
successProperty: 'success',
messageProperty: 'message',
totalProperty: 'total'
},
writer: {
allowSingle: false,
type: 'json',
writeAllFields: false,
root: 'data'
}
}
});
And lastly model MyApp.model.Provider is defined as
Ext.define('MyApp.model.Provider', {
extend: 'Ext.data.Model',
fields: [
{ name: 'provider_id', type: 'int'},
'name',
{ name: 'create_time', type: 'date', dateFormat: appDateFormat },
{ name: 'status', type: 'int'}
],
idProperty: 'provider_id',
displayProperty: 'name' // A custom property used for dynamically use the property to display
})
Now this code does not show any sub-menu in the filter menu. It just shows loading. See the image.
Update
I have solved it using following filter config. This actually populates options config manually. So no store is used here.
{
type: 'list',
labelField: 'name',
options: (function () {
var opts = [];
fS.load(function (records, operation, success) {
for (var i = 0; i < records.length; i++) {
var ar = {
id: records[i].get('provider_id'),
name: records[i].get('name')
};
opts.push(ar);
}
});
return opts;
})(),
single: true
}
It seems 'id' is hard-coded. id: records[i].get('provider_id'), does not look good. Though it works.
But I am still looking for a proper way to do it.
Note: The expected behavior can be found on ExtJS 4.1.1. See this jsfiddle. I have reproduced it. But this very same thing does not work on ExtJS 4.0.7
I didn't tried this myself but you need to set the ID manually with the idField property [new to ExtJS4.1.3] which is per default set to id. So I guess this will work:
{
header: 'Provider',
filter: {
type: 'list',
idField: 'provider_id',
store: Ext.getStore('MyApp.store.Provider'),
dataIndex: 'provider_id',
labelField: 'name'
}
}
Update
OK, I looked at the source and I can now tell you that this is the answer. So will have to either live with your workarround until 4.2 is out or you can apply the following changes to your Ext.ux.grid.menu.ListMenu to make it run:
add the idField with a default value.
look within the constructor for this lines
case 'object': options.push([value.id, value[this.labelField]]); break;
// some more lines
fields: ['id', this.labelField],
and replace it with
case 'object': options.push([value[me.idField], value[me.labelField]]); break;
// some more lines
fields: [me.idField, me.labelField],
and within the onLoad function look for
itemValue = records[i].get('id');
and replace it with
itemValue = records[i].get(me.idField);
and that pretty much is it.

Categories