I am using kendo grid to display data, but while sorting(ascending or descending) it's sorting perfectly for string values. But for numeric it's not sorting properly it's taking only first character to do sorting, not taking as string values even it's in numeric. How to solve this issue ?
You can use the gird column sortable.compare property to assign your own compare function.
Then what you are looking for is a Natural sort, like the one described here: http://web.archive.org/web/20130826203933/http://my.opera.com/GreyWyvern/blog/show.dml/1671288 and implemented here: http://www.davekoelle.com/files/alphanum.js
Here is a demo using a case insensitive version of the natural sort:
https://dojo.telerik.com/eReHUReH
function AlphaNumericCaseInsensitive(a, b) {
if (!a || a.length < 1) return -1;
var anum = Number(a);
var bnum = Number(b);
if (!isNaN(anum) && !isNaN(bnum)) {
return anum - bnum;
}
function chunkify(t) {
var tz = new Array();
var x = 0, y = -1, n = 0, i, j;
while (i = (j = t.charAt(x++)).charCodeAt(0)) {
var m = (i == 46 || (i >= 48 && i <= 57));
if (m !== n) {
tz[++y] = "";
n = m;
}
tz[y] += j;
}
return tz;
}
var aa = chunkify(a ? a.toLowerCase() : "");
var bb = chunkify(b ? b.toLowerCase() : "");
for (x = 0; aa[x] && bb[x]; x++) {
if (aa[x] !== bb[x]) {
var c = Number(aa[x]), d = Number(bb[x]);
if (!isNaN(c) && !isNaN(d)) {
return c - d;
} else return (aa[x] > bb[x]) ? 1 : -1;
}
}
return aa.length - bb.length;
}
var dataSource = new kendo.data.DataSource({
data: [
{ id: 1, item: "item101" },
{ id: 2, item: "item2" },
{ id: 3, item: "item11" },
{ id: 4, item: "item1" }
]
});
$("#grid").kendoGrid({
dataSource: dataSource,
sortable: true,
columns: [{
field: "item",
sortable: {
compare: function(a, b) {
return AlphaNumericCaseInsensitive(a.item, b.item);
}
}
}]
});
Related
I have an object array. I want to get for each element in the array the difference with the others.
For example thi is my object array:
array= [{id:1, name= 'test', isAdmin: true, userMail:'test#test.com', userTel: '+12555555'},
{id:1, name= 'test', isAdmin: false, userMail:'test#test.com', userTel: '+12555555'}, {id:1,
name= 'test', isAdmin: false, userMail:'test#test.com', userTel: '+12555785444'}]
the result is :
result = [isAdmin, userMail, userTel]
I tried this solution but not working :
for (let index = 0; index < this.array.length; index++) {
const e = this.array[index];
let j = index + 1;
let t;
while (index !== j && j <= (this.array.length - 1) && t === undefined) {
t = this.difference(array);
j++;
}
let y;
if (t !== null && t !== undefined) {
Object.keys(t).forEach(key => {
if (key !== 'idTrace') {
y = key;
}
});
}
this.result.push(y);
}
difference(object, base) {
return transform(object, (result, value, key) => {
if (!isEqual(value, base[key])) {
result[key] = isObject(value) && isObject(base[key]) ?
this.difference(value, base[key]) : value;
}
});
}
Any help, thanks in advance.
you can do it like this.
Please note that this is not the most performant solution, but it is understandable (readable) solution on which you can make optimisations as needed.
const objects = [{
"id": 1,
"name": "test",
"isAdmin": true,
"userMail": "test#test.com",
"userTel": "+12555555"
},
{
"id": 1,
"name": "test",
"isAdmin": false,
"userMail": "test#test123.com",
"userTel": "+12555555"
},
{
"id": 1,
"name": "test",
"isAdmin": false,
"userMail": "test#test.com",
"userTel": "+12555785444"
}
];
// Finds all the keys that are different in two objects.
const difference = (obj1, obj2) => {
let foundKeys = [];
Object.keys(obj1).forEach(key => {
if (obj1[key] !== obj2[key]) {
foundKeys.push(key);
}
});
return foundKeys;
};
let differentKeys = [];
// Compares every object with all objects and pushes to one array all differences in keys.
for (let i = 0; i < objects.length; i++) {
for (let j = i + 1; j < objects.length; j++) {
differentKeys = differentKeys.concat(difference(objects[i], objects[j]));
}
}
// Removes duplicates.
differentKeys = differentKeys.filter(function(value, index, differentKeys) {
return differentKeys.indexOf(value) === index;
});
console.log(differentKeys);
Let me know if you have any questions.
I have a Kendo grid that I am using to display a typescript structure that looks like this.
{
companyId: string,
name: string,
inceptionDate: Date,
tags: string[]
}
I would like to be able to filter on the tags column, but I am unsure as to how this should actually work. I can quite easily filter on the name column, either with the built in grid filtering functionality or via code:
baseFilter.filters.push({ field: "name", operator: "contains", value: "myValue" });
But I don't see a way to do this against an array object. I would prefer to be able to select a tag from the a list in the grid filter option, but if that's not possible I'd be quite happy to use a multiselect and set the filter manually.
Is this something that is built in or that is relatively easy (or even just not insanely hard) to implement?
As long as you're doing the client side filtering, you can use a function for the operator field.
a simple example (in js):
baseFilter.filters.push({
field: "tags",
operator: function (tags, value) {
for (var i = 0; i < tags.length; i++) {
var tag = tags[i];
if (tag === value)
return true;
}
return false;
}});
TerminalSamurai's answer did the trick for me !
Here is my full code (with checking if there is already a filter existing)
var grid = $("#GridListeModelesDocumentPatient_#Model.PatientId").data("kendoGrid");
if (grid != null) {
var filterHandler = grid.dataSource.filter();
if (dataItem.Nom == "Tous") {
if (filterHandler != null) {
var existingFilters = filterHandler.filters;
for (var i = existingFilters.length - 1; i >= 0; i--) {
if (existingFilters[i].field == "ModelesMotifs") {
existingFilters.splice(i, 1);
}
}
grid.dataSource.filter(existingFilters);
} else {
grid.dataSource.filter({});
}
} else {
if (filterHandler != null) {
var existingFilters = filterHandler.filters;
for (var i = existingFilters.length - 1; i >= 0; i--) {
if (existingFilters[i].field == "ModelesMotifs") {
existingFilters.splice(i, 1);
}
}
var new_filter = {
field: "ModelesMotifs",
operator: function (modelesMotifs, value) {
for (var i = 0; i < modelesMotifs.length; i++) {
var modeleMotif = modelesMotifs[i];
if (modeleMotif.MotifId === value)
return true;
}
return false;
},
value: dataItem.MotifId
};
existingFilters.push(new_filter);
grid.dataSource.filter(existingFilters);
} else {
grid.dataSource.filter({
field: "ModelesMotifs",
operator: function (modelesMotifs, value) {
for (var i = 0; i < modelesMotifs.length; i++) {
var modeleMotif = modelesMotifs[i];
if (modeleMotif.MotifId === value)
return true;
}
return false;
},
value: dataItem.MotifId
});
}
}
}
I want to change the background color of the columns after sorting whether it may asc or desc. Please remember not all the columns, only sorted columns background.
Thanks in advance
$scope.gridOptions = {
.....
.....
dataBound : function(arg){
var columns = arg.sender.columns;
var sortedColumns = arg.sender.dataSource.sort();
for (var i = 0; i < sortedColumns.length; i++) {
var srtColumn = sortedColumns[i];
for (var j = 0; j < columns.length; j++) {
var column = columns[j];
if (srtColumn.field === column.field) {
column.attributes = { style : "text-align:right" };
}
}
}
},
editable: {
mode: 'popup',
},
height: 700,
columns: [
{ field: "Name", title: "Name", width: 150, editable: false},
{ field: "Address", title: "Address", width: 100, editable: false },
{ field: "Company", title: "Company", editable: false },
]
};
I achieved through databound function
$scope.gridOptions = function {
.............
dataBound: function (arg) {
var columns = arg.sender.columns;
var sortedColumns = arg.sender.dataSource.sort();
var sortedIndex = -1;
for (var i = 0; i < columns.length; i++) {
var sorted = false;
var column = columns[i];
sortedIndex = sortedIndex + 1;
for (var j = 0; j < sortedColumns.length; j++) {
var srtColumn = sortedColumns[j];
if (srtColumn.field === column.field) {
sorted = true;
break;
}
}
if (sorted) {
arg.sender.thead
.find("tr")
.find("th:eq(" + sortedIndex + ")")
.css({ background: "#6666ff" });
}
else {
arg.sender.thead
.find("tr")
.find("th:eq(" + sortedIndex + ")")
.css({ background: "#323232"});
}
},
.....
};
I have a grid in ext with some custom columns, and I want to be able to sort this column - I want to sort it by what is displayed inside of it, but really I just cannot figure out how to define a sorter for a column that will not be based on the dataIndex - I tried using a custom model, but I could not get that to work.
{
text: 'Parent',
dataIndex: 'Parent',
renderer: function(value, meta, record) {
var ret = record.raw.Parent;
if (ret) {
return ret.Name;
} else {
meta.tdCls = 'invisible';
return record.data.Name;
}
},
sortable: true
},
You should be able to override the doSort method of the column. Here's the gist of it. I also created a working fiddle (http://jsfiddle.net/cfarmerga/LG5uA/). The fiddle uses the string length of a field as the property to sort on, but of course you could apply your own custom sort logic.
var grid = Ext.create('Ext.grid.Panel',{
//...
columns: [
{ text: 'name', dataIndex: 'name', sortable: true },
{
text: 'Custom',
sortable : true,
dataIndex: 'customsort',
doSort: function(state) {
var ds = this.up('grid').getStore();
var field = this.getSortParam();
ds.sort({
property: field,
direction: state,
sorterFn: function(v1, v2){
v1 = v1.get(field);
v2 = v2.get(field);
return v1.length > v2.length ? 1 : (v1.length < v2.length ? -1 : 0);
}
});
}
}
]
//....
});
For Ext JS version 5, it looks like doSort was taken out, so I couldn't override that. Instead, I went the route of listening to the sortchange event, and from there, I used the Ext.data.Store.setSorters method. The code is a bit custom, and overly complex because of the data that I'm using, so keep that in mind (Fiddle here):
// grid class
initComponent: function() {
...
this.on('sortchange', this.onSortChange, this);
},
onSortChange: function(container, column, direction, eOpts) {
// check for dayColumnIndex
if (column && column.dayColumnIndex !== undefined) {
this.sortColumnByIndex(column.dayColumnIndex, direction);
}
},
sortColumnByIndex: function(columnIndex, direction) {
var store = this.getStore();
if (store) {
var sorterFn = function(rec1, rec2) {
var sortValue = false;
if (rec1 && rec2) {
var day1;
var daysStore1 = rec1.getDaysStore();
if (daysStore1) {
day1 = daysStore1.getAt(columnIndex);
}
var day2;
var daysStore2 = rec2.getDaysStore();
if (daysStore2) {
day2 = daysStore2.getAt(columnIndex);
}
if (day1 && day2) {
var val1 = day1.get('value');
var val2 = day2.get('value');
sortValue = val1 > val2 ? 1 : val1 === val2 ? 0 : -1;
}
}
return sortValue;
};
if (direction !== 'ASC') {
sorterFn = function(rec1, rec2) {
var sortValue = false;
if (rec1 && rec2) {
var day1;
var daysStore1 = rec1.getDaysStore();
if (daysStore1) {
day1 = daysStore1.getAt(columnIndex);
}
var day2;
var daysStore2 = rec2.getDaysStore();
if (daysStore2) {
day2 = daysStore2.getAt(columnIndex);
}
if (day1 && day2) {
var val1 = day1.get('value');
var val2 = day2.get('value');
sortValue = val1 < val2 ? 1 : val1 === val2 ? 0 : -1;
}
}
return sortValue;
};
}
store.setSorters([{
sorterFn: sorterFn
}]);
}
}
There is a convert method on the Ext.data.Model class that allows you to convert the data before it's being used. Then you can just specify this 'dataIndex' in your column and do a normal sort. The column will be sorted by that converted value. Here is the a sample model with just one field (Parent) and with it's corresponding conversion:
Ext.define('MyModel', {
extend: 'Ext.data.Model',
fields: [
{name: 'Parent', type: 'string', convert: sortParent},
// other fields...
],
sortParent: function(value, record) {
var ret = record.raw.Parent;
if (ret) {
return ret.Name;
} else {
meta.tdCls = 'invisible';
return record.data.Name;
}
}
});
Im using the date-euro plugin to sort the date column properly. the sort is working, but the pagination is going to broken on init when I add the sType parameter. when i click the numberofelement dropdown or on the next button, the pagination works. The prettydaterender function converts the date from 2012-10-24 14:00 to 24/10/2012 14:00
Could you help me please?
$.extend( $.fn.dataTableExt.oSort, {
"date-euro-pre": function ( a ) {
if ($.trim(a) != '') {
var frDatea = $.trim(a).split(' ');
var frTimea = frDatea[1].split(':');
var frDatea2 = frDatea[0].split('/');
var x = (frDatea2[2] + frDatea2[1] + frDatea2[0] + frTimea[0] + frTimea[1] + frTimea[2]) * 1;
} else {
var x = 10000000000000; // = l'an 1000 ...
}
return x;
},
"date-euro-asc": function ( a, b ) {
return a - b;
},
"date-euro-desc": function ( a, b ) {
return b - a;
}
} );
table.dataTable({
"sDom": "<'row'<'span6'l><'span6'f>r>t<'row'<'span6'i><'span6'p>>",
'aaSorting': [[3, 'desc']],
'aoColumns': [null,null,null,{
// 14:43 24/10/2012
'fnRender': prettyDateRender,
'sType': 'date-euro-desc'
}]
});