I am new to extjs framework and looking for a way to add a custom sorting function to a column in a panel. I went through some of the post, and it seems that this functionality has been changed a few times over time.
In 5.0.1 documentation I found sortType configuration that can be used to convert the data to a comparable value.
But in my case, converting all the data to a value and then sorting could be a time consuming process and I was looking to use a function like the one used in doSort configuration earlier similar to this example; by basically configuring a function like this:
function customSorter(state){
var ds = this.up('grid').getStore();
var field = this.getSortParam();
ds.sort({
property: field,
direction: state,
sorterFn: function(v1,v2){
//some custom logic
}
});
}
EDIT 1: I am looking to use this function for only one column, the other columns are standard data types and sorting works fine by default for those.
Any ideas how to do this in 5.0.1?
Thanks in advance..
You can pass an array of Ext.util.Sorter to the sort method of your store. The Ext.util.Sorter class has an sorterFn config.
references:
https://docs.sencha.com/extjs/5.0.1/api/Ext.util.Sorter.html
https://docs.sencha.com/extjs/5.0.1/api/Ext.data.Store.html#method-sort
If you want to have a custom sort for a specific colum you can use the sortType config on the field corresponding to the column, see https://docs.sencha.com/extjs/5.0.1/api/Ext.data.field.Field.html#cfg-sortType
Related
as far as I understand there is only the callback dataFiltered, which is used for the whole table. It is triggered by all filters indifferently.
Is it possible to get a callback for a specific single header filter?
So that I can call a function as soon as a certain header filter becomes active?
I imagine it to be something like this:
{title:"Name", field:"name", headerFilter:true, headerdataFiltered:function()}
Is there possibly a workaround?
Thanks a lot!
(I would be especially grateful for non-jquery solutions)
Thanks also for this realy wonderful tool Tabulator.
Thanks for your kind words, it is always great to hear that Tabulator is appreciated.
The reason it is called when any filter is applied is because multiple filters can be applied at once, with Complex Filtering a complex and/or filter set can be applied so it would be hard to isolate down to specific columns in all cases.
The dataFiltered callback does get passed a list of all currently active filters so you can see if your affected column is in that:
var table = new Tabulator("#example-table", {
dataFiltering:function(filters){
//filters - array of filters currently applied
},
});
If you need to see if the column has just been filtered you can store a copy of the previous value of this object outside the callback and then compare the old and new values on the next call.
The other option would be to use a custom editor in the header filter then you could manually decide when the success function is called that initiates the filter and then reference an external function from there
I am working with DataTables plug-in in JavaScript.
Usually, if I need to update a cell value, I use the cell().data(set) method followed by .draw().
However, I do not want to use this way because my table contains heavy DOM object. So, when I need to update a cell, I just call some jQuery like $("#cell").attr("myattr", 50) for example, and then I managed to never have to use draw(). This prevents the object to be rebuilt each time, but unfortunately it also means that the DataTable is not aware of these changes (cell().data() returns the unchanged object).
This is a problem when I want my table to be sorted. In fact, the sorting is performed on the data that the datatable known, data which is not changed.
So I thought I could use the columns.render option, implementing a function like this:
function(data, type, row, meta) {
if (type === "sort") {
return $("#cell").attr("myattr");
}
return data;
}
This does not work and I think this is because of the fact that DataTable caches the data. So, as I never update cells data, cache never need to be updated, and sorting is done using this cache, which does not correspond the cell myattr attribute.
I am looking for a workaround which can allow me to sort a DataTable even if cells values are not changed internally but from outside.
Play with this JSFiddle, clicking the "CHANGE VALUES" button and trying to sort the column, you can see that the values are not correctly ordered.
There are couple solutions:
SOLUTION #1
Use cell().invalidate() API method to invalidate data in cache as shown below:
$('#example').DataTable().cell($("#a").closest('td')).invalidate('dom').draw(false);
DEMO
See this jsFiddle for code and demonstration.
SOLUTION #2
You can use columns.orderDataType to specify name of custom ordering plug-in, see Custom data source sorting. These plug-ins can access live DOM content.
Please note that there are no plug-ins built into DataTables, they must be added separately.
You can use dom-text plug-in as a base and write your own function to access the data for sorting.
DEMO
See this jsFiddle for code and demonstration.
I'm using dgrid with the column reorder extension. I have two questions here -
I see that after reordering columns, the columns are present in the new order in the subRows attrinute of grid (note that I'm not referring to subRow here). Is that the best way to get the column order or are there any alternate/better ways to do it?
I understand that I will need to take care of saving the column order (or any other property for that matter) and restoring it. When I'm creating the grid with a saved order, what is the best way to do it? Should I create the columns in the saved order or can I create them in the standard order and then re-order them as per my saved order? If the latter is possible, how do I do it?
Thanks,
Yes, subRows is likely the most consistent way to get the column order.
Regarding saving/restoring, I could fathom doing something like the following. Note that for simplicity's sake, I'm making some assumptions here:
You only have a single sub-row (the same approach could be used for multiple, I figure, but you'd need outer loops)
Each column references a unique field
You are targeting only ES5+ environments (since I use ES5 Array methods below)
When saving the sub-rows, save just the field that each column references (which will make it trivial to serialize):
var persistedSubRow = grid.subRows[0].map(function (column) {
return column.field;
}
Then, when creating the grid, have an object hash of your columns in the default order (which you can use to set columns if there are no persisted settings), but if persisted settings exist, use that to determine the order by mapping it back against the hash:
var columns = {
field1: ...,
field2: ...,
...
}
if (persistedSubRow) {
persistedSubRow = persistedColumns.map(function (field) {
var column = columns[field];
// Normally when an object hash is specified for columns,
// field is autodetected from the key. Converting to array will
// lose that, so set it within the object.
column.field = field;
return column;
});
}
var grid = new Grid({
// grid.columns accepts either an object or array as input
columns: persistedSubRow || columns,
...
});
Let me know if you run into trouble; I'm shooting from the hip here, and haven't tested the above.
I am developing a web app using SlickGrid.
Our application has many grids in different tabs/pages and for that reason I am wondering if I can refactor some code so that I am not writing the same functions over and over for seperate grids.
An example:
I need a custom Formatter since we have multiple tree grids (the formatter to implement the tree structure is identical for each grid.):
function PercentCompleteFormatter(row, cell, value, columnDef, dataContext)
Given that I cannot pass the grid or a dataview as an arguement (assuming the signature above must be used for all custom formatter.), I basically have to have the same formatter code inside each code block where I am creating the grid.
Is there a way I can create one "generic" formatter and apply it to ALL grids?
The same question applies to things like sorting, filtering, etc... but I hope the above explaination covers what I'm trying to ask.
Thanks!
You can use jQuery's .proxy() helper (or similar) to bind a function to a particular context.
For example:
function MyFormatter(row, cell, value) {
var grid = this; // the grid will be the executing scope
// ...
}
var myFormatterForGridA = $.proxy(MyFormatter, gridA);
var myFormatterForGridB = $.proxy(MyFormatter, gridB);
I have a set of data like the following example and i would like to load it into the grid. However, i'm not sure how since the data doesn't have an name.
[[48803,"DSK1","","02200220","OPEN"],[48769,"APPR","","77733337","ENTERED"]]
What you need is just use the following localReader
localReader: {
repeatitems: true,
cell: "",
id: 0
}
I made for you the demo which shows live how it works.
UPDATED: How I could find out the reality is not so good as the documentation. The usage of localReader could help you to fill the grid contain with data from data parameter with the custom structure, but another parts of jqGrid: local sorting and searching don't work correct with this structure of data parameter. I interpret it as a bug. As a pragmatical solution I would recommend you to convert your custom data to array of named objects like
[{id:48803,col2:"DSK1",col3:"",col4:"02200220",col5:"OPEN"},
{id:48769,col2:"APPR",col3:"",col4:"77733337",col5:"ENTERED"}]
with the names corresponds to the column names in the colModel. If you will use data parameter in the form, everything will work perfect in jqGrid.
UPDATED 2: Look at the source of the fixed example and it will be clear what I mean. In your case conversion of the data can be about the following
var myNewData = [];
for (var i=0,l=mydata.length; i<l; i++) {
var d = mydata[i];
myNewData.push({id:d[0],col2:d[1],col3:d[2],col4:d[3],col5:d[4]});
}
The solution is not so elegant like with localReader, but it work without any restrictions.
Well, I'm not very familiar with jqgrid, but you could simply assign your data to an associative array and then load it.
Example here:
http://jsfiddle.net/QWcrT/