I am sorting my data in following way. I am using knockout observable
self.myObsArray1 = ko.observableArray();
self.myObsArray2 = ko.observableArray();
var sortData = false;
self.myObsArray1 .sort(function (a, b) {
if (sortData ) {
return (a.Name() < b.Name() ? -1 : (a.Name() > b.Name() ? 1 : 0));
}
else {
return (b.Name() < a.Name() ? -1 : (b.Name() > a.Name() ? 1 : 0));
}
});
I am same type of above code in my page but with different column names like above i am using Name column for sorting.
Then i have same type of above code like above
self.myObsArray2 .sort(function (a, b) {
if (sortData ) {
return (a.Id() < b.Id() ? -1 : (a.Id() > b.Id() ? 1 : 0));
}
else {
return (b.Id() < a.Id() ? -1 : (b.Id() > a.Id() ? 1 : 0));
}
});
Can we somehow remove this redundant code?
You can use a helper function to create the sorter, thus making your code DRYer:
function createColumnSorter(column) {
return function(a, b) {
var valA = a[column]();
var valB = b[column]();
if (sortData) {
return (valA < valB ? -1 : (valA > valB ? 1 : 0));
} else {
return (valB < valA ? -1 : (valB > valA ? 1 : 0));
}
};
}
Usage:
self.myObsArray1.sort(createColumnSorter('Name'));
self.myObsArray2.sort(createColumnSorter('Id'));
Related
I'm using jQuery DataTables, trying to sort data column with 2 different date types.
I have 2 different formats month/year and day/month/year but they are not sorting correctly.
Current code:
function dateSorter(a, b) {
var datea = a.split("/");
var dateb = b.split("/");
if (datea[1] > dateb[1]) return 1;
if (datea[1] < dateb[1]) return -1;
if (datea[0] > dateb[0]) return 1;
if (datea[0] < dateb[0]) return -1;
if( datea.length == 2 )
{
if (datea[2] > dateb[2]) return 1;
if (datea[2] < dateb[2]) return -1;
}
else
{
if( datea[1] > dateb[2] ) return 1;
if( datea[2] < dateb[1] ) return -1;
}
return 0;
}
Above is current code, it works for month/year format and sorts them fine , but not mixed with both formats.
This currently sorts day/month from day/month/year format but it does not sort year correctly.
Example (current):
03/04/2016
12/04/2017
12/05/2015
01/2015
02/2015
02/2016
01/2018
...
It should be:
01/2015
02/2015
12/05/2015
02/2016
03/04/2016
12/04/2017
01/2018
$.extend( jQuery.fn.dataTableExt.oSort, {
"date-time-odd-pre": function (a){
if(/\d{1,2}\/\d{1,2}\/\d{4}/.test(a)){
return parseInt(moment(a, "DD/MM/YYYY").format("X"), 10);
}else{
return parseInt(moment(a, "MM/YYYY").format("X"), 10);
}
},
"date-time-odd-asc": function (a, b) {
return a - b;
},
"date-time-odd-desc": function (a, b) {
return b - a;
}
});
Should work, though you'll need moment available.
Hope that helps.
I am sorting a grid with knockout.js. Following is my sort function
this.sortByName = function() {
var event = arguments[1];
var targeElement = event.originalTarget;
// console.info(targeElement);
console.log(targeElement.attributes[1].nodeValue);
order = 'sorting';
configuration.data.sort(function(a, b) {
if(a.name<b.name){
order = 'sorting_desc';
return a.name > b.name ? -1 : 1;
}
else if(a.name>b.name){
order = 'sorting_asc'
return a.name < b.name ? -1 : 1;
}
});
$(targeElement).removeClass('sorting_asc sorting_desc').addClass(order);
};
The by default grid view
The Sorted image 1
The sorted image 2
As you can see the order of sorting is not correct. I have been playing around for 3 days in this issue.
Well I found a solution to this problem
this.sortByName = function() {
currentOrder = arguments[0].sortClass();
var sortColumn = arguments[0].rowText;
if(currentOrder =='sorting' || currentOrder =='sorting_desc'){
currentOrder='sorting_asc';
configuration.data.sort(function(a, b) {
if (a[sortColumn] == b[sortColumn])
return 0;
else if (a[sortColumn] < b[sortColumn])
return -1;
else
return 1;
});
}else{
currentOrder='sorting_desc';
configuration.data.sort(function(a, b) {
if (a[sortColumn] == b[sortColumn])
return 0;
else if (a[sortColumn] > b[sortColumn])
return -1;
else
return 1;
});
}
self.resetSortColumns();
arguments[0].sortClass(currentOrder);
};
I have a treeStore ('planScreenStore') which I'm accessing in the following way :
updateStore : function() {
rootNodeID = globals.GlobalModel.planList.scope._id;
var planScreenStoreRootNode = this.planScreenStore.getRootNode();
if (!(planScreenStoreRootNode === undefined)) {
planScreenStoreRootNode.removeAll();
}
if (globals.GlobalModel.planList.children.length > 0) {
planScreenStoreRootNode.appendChild(
globals.GlobalModel.planList.children);
globals.GlobalModel.planList.children = planScreenStoreRootNode;
globals.GlobalModel.planListForCreateNewPlan = planScreenStoreRootNode;
}
I have to sort the treeStore on the basis of its field 'text'.
I have been able to do so in the following two ways:
updateStore : function() {
debugger;
rootNodeID = globals.GlobalModel.planList.scope._id;
var planScreenStoreRootNode = this.planScreenStore.getRootNode();
if (!(planScreenStoreRootNode === undefined)) {
planScreenStoreRootNode.removeAll();
}
if (globals.GlobalModel.planList.children.length > 0) {
planScreenStoreRootNode.appendChild(
globals.GlobalModel.planList.children);
globals.GlobalModel.planList.children = planScreenStoreRootNode;
globals.GlobalModel.planListForCreateNewPlan = planScreenStoreRootNode;
}
this.planScreenStore.sort('text','ASC');
and the other one:
updateStore : function() {
debugger;
rootNodeID = globals.GlobalModel.planList.scope._id;
var planScreenStoreRootNode = this.planScreenStore.getRootNode();
if (!(planScreenStoreRootNode === undefined)) {
planScreenStoreRootNode.removeAll();
}
if (globals.GlobalModel.planList.children.length > 0) {
planScreenStoreRootNode.appendChild(
globals.GlobalModel.planList.children);
globals.GlobalModel.planList.children = planScreenStoreRootNode;
globals.GlobalModel.planListForCreateNewPlan = planScreenStoreRootNode;
}
planScreenStoreRootNode.sort(function(n1, n2) {
debugger ;
var v1 = n1.data['text'].toUpperCase();
var v2 = n2.data['text'].toUpperCase();
if (v1 < v2)
return -1;
else if (v1 > v2)
return 1;
return 0;
});
I get the desired result with both the methods but somehow in both the cases, my application crashes after the sorting is performed while it works entirely fine without either of the sorting applied. Is it something related to how I'm accessing the NodeInterface (planScreenRootNode). How can i resolve this?
I'm using SlickGrid with Groupings and need to sort the data within each Group but leave the Grouping (group header row) in the default order.
Sorting seems to sort the column data and then reorder the Grouping Headers per the data.
Has anyone done this or do I have a option/parameter set incorrectly?
Thanks
Here is my example of grouping+sorting. Take note that when I want to sort it does a sort against the column you are grouping by, I can't sort with any other columns unless it's the grouping by column (well not the way I coded my function anyway, though you could play with that)
<select id="slc_groupby" name="slc_groupby" onchange="groupByColumn(this.value)">
<option value="">...</option>
<option value="assy_number">Assy Number</option>
</select>
<span id="span_group_btn" style="position:absolute; display:none; margin-left:5px; margin-top:20px;">
<!-- Group sorting, I show this button only after a grouping column is chosen -->
<img src="/images/b_updownarrow2.gif" id="img_sorting" border="0" onclick="groupByColumn( $('#slc_groupby').val() )" />
</span>
and here comes the javascript function for grouping+sorting, take note that whenever you click on the sort button (the top one with html ID=img_sorting), it has the effect of regrouping and resorting through the groupByColumn() function (since I'm using the onclick event), though it happens so fast that you don't really see it makes a grouping again... but that's the way I got it working in all browser (Chrome included)
function groupByColumn(column) {
// sorting direction, if undefined just inverse the current direction of the global sortdir var (sortdir is defined as global variable in slickgrid)
sortdir = ((sortdir == 1) ? -1 : 1);
dataView1.groupBy(
column,
function (g) {
return g.value + " <span style='color:green'>(" + g.count + " items)</span>";
},
function (a, b) {
var a1 = a.value;
var b1 = b.value;
// string sorting
return sortdir * (a1 == b1 ? 0 : (a1 > b1 ? 1 : -1));
}
);
// display the button for group sorting
$('#span_group_btn').css("display", "inline");
}
Since U did not provide source, I can guess that your problem is with the sort method, which sorts only by selected column, so you must first sort by grouping column.
Let's say that you are grouping by UserName and have sortable column Title, your onSort method should look similar to this:
grid.onSort.subscribe(function (e, args) {
sortdir = args.sortAsc ? 1 : -1;
sortcol = args.sortCol.field; // Title column
var comparer = function (a, b) {
var x = a['UserName'], y = b['UserName'];
if (x != y)
{
return (x < y ? 1 : -1) * sortdir;
}
else
{
x = a[sortcol];
y = b[sortcol];
return (x == y ? 0 : (x > y ? 1 : -1));
}
};
dataView.sort(comparer, args.sortAsc);
});
Lets say you are grouping with 4 different columns - department, faculty, course, semester. While sorting, you manually compare these columns and always sort them in ascending or descending (whichever is your default order in the beginning), for rest of other columns you use sort direction by flipping the result of compare function
function comparer(a, b) {
return (x == y ? 0 : (x > y ? 1 : -1));
}
grid.onSort.subscribe(function(e, args) {
$(e.target).parents(".slick-header-columns").find(
".slick-header-column").removeClass(
"slick-header-column-sorted");
var currentCol = $(e.target).hasClass("slick-header-column") ? $(e.target): $(e.target).parents(".slick-header-column");
currentCol.addClass("slick-header-column-sorted");
currentCol.find(".slick-sort-indicator").removeClass(args.sortAsc ? "desc" : "asc").addClass(args.sortAsc ? "asc" : "desc");
var sortdir = args.sortAsc ? 1 : -1;
var sortcol = args.sortCol.field;
var items = dataView.getItems();
items.sort(function(a, b) {
var deptCompare = a.department == b.department ? 0 : (a.department < b.department ? -1 : 1);
if (deptCompare === 0) {
var facultyCompare = a.faculty == b.faculty ? 0 : (a.faculty < b.faculty ? -1 : 1);
if (facultyCompare === 0) {
var courseCompare = a.course == b.course ? 0 : (a.course < b.course ? -1 : 1);
if (courseCompare === 0) {
var semesterCompare = a.semester == b.semester ? 0 : (a.semester < b.semester ? -1 : 1);
if (semesterCompare === 0) {
var fieldCompare = comparer(a[sortcol], b[sortcol]);
return fieldCompare * sortdir;
} else {
return semesterCompare;
}
} else {
return courseCompare;
}
} else {
return facultyCompare;
}
} else {
return deptCompare;
}
});
dataView.refresh();
});
Second way to achieve the same is to user comparer in grouping level.
You define a comparer for group,
function groupComparer(a, b) {
var x = a.groupingKey
var y = b.groupingKey;
return (x == y ? 0 : (x > y ? 1 : -1));
}
dataView.setGrouping([
{
getter : "department",
collapsed : false,
formatter : function(g){
return g.value;
},
comparer : groupComparer
},{
getter : "faculty",
collapsed : false,
formatter : function(g){
return g.value;
},
comparer : groupComparer
},{
getter : "course",
collapsed : false,
formatter : function(g){
return g.value;
},
comparer : groupComparer
},{
getter : "semester",
collapsed : false,
formatter : function(g){
return g.value;
},
comparer : groupComparer
}
]);
And user regular sorting
grid.onSort.subscribe(function (e, args) {
dataView.sort(function(a,b){
var x = a[args.sortCol.field];
var y = b[args.sortCol.field];
return (x == y ? 0 : (x > y ? 1 : -1));
}, args.sortAsc);
});
I recently received some excellent advice for writing some jquery functionality. I am trying to turn it into a pluggin.
this is the code that I got from stackOverflow#micha at this link
https://stackoverflow.com/a/8820946/729820
$('#DischargeDateTimeMask').keypress(function (e) {
var regex = ["[0-1]",
"[0-2]",
":",
"[0-5]",
"[0-9]",
"(\\s)",
"(A|P)",
"M"],
string = $(this).val() + keyboard(e),
b = true;
for (var i = 0; i < string.length; i++) {
if (!new RegExp("^" + regex[i] + "$").test(string[i])) {
b = false;
}
}
return b;
});
function keyboard(a) { var b = a.charCode ? a.charCode : a.keyCode ? a.keyCode : 0; if (b == 8 || b == 9 || b == 13 || b == 35 || b == 36 || b == 37 || b == 39 || b == 46) { if ($.browser.mozilla) { if (a.charCode == 0 && a.keyCode == b) { return true } } } return String.fromCharCode(b) }
I personally attempt to turn it into a pluggin like so...
(function ($) {
$.fn.simpleTimeMask = function () {
$(this).keypress(function (e) {
debugger;
var regex = ["[0-2]",
"[0-4]",
":",
"[0-6]",
"[0-9]",
"(A|P)",
"M"],
string = $(this).val() + keyboard(e),
b = true;
for (var i = 0; i < string.length; i++) {
if (!new RegExp("^" + regex[i] + "$").test(string[i])) {
b = false;
}
}
return b;
});
}
(function ($) {
var methods = {
keyboard: function (a) {
//THIS
var b = a.charCode ? a.charCode : a.keyCode ? a.keyCode : 0; if (b == 8 || b == 9 || b == 13 || b == 35 || b == 36 || b == 37 || b == 39 || b == 46) { if ($.browser.mozilla) { if (a.charCode == 0 && a.keyCode == b) { return true } } } return String.fromCharCode(b)
}
}
});
function keyboard(a) { var b = a.charCode ? a.charCode : a.keyCode ? a.keyCode : 0; if (b == 8 || b == 9 || b == 13 || b == 35 || b == 36 || b == 37 || b == 39 || b == 46) { if ($.browser.mozilla) { if (a.charCode == 0 && a.keyCode == b) { return true } } } return String.fromCharCode(b) }
})(jQuery);
Notice how I have two functions that attempt to do the same thing. One I think would be a function that would be called by a user of this pluggin, the other would be used internally. Anyway, I got this thing all compiled and I attempted to add it to my project, but as expected, it did not work. What would be your recommendations for building this pluggin?