Is there obvious reason why this Slickgrid example shouldn't work. Basically it doesn't sort on clicking columns.
var grid;
var columns = [
{id:"title", name:"Title", field:"title", sortable: true},
{id:"duration", name:"Duration", field:"duration", sortable: true},
{id:"%", name:"% Complete", field:"percentComplete", sortable: true},
{id:"start", name:"Start", field:"start", sortable: true},
{id:"finish", name:"Finish", field:"finish", sortable: true},
{id:"effort-driven", name:"Effort Driven", field:"effortDriven", sortable: true}
];
var options = {
enableCellNavigation: true,
enableColumnReorder: false
};
$(function() {
var data = [];
for (var i = 0; i < 500; i++) {
data[i] = {
id: i,
title: "Task " + i,
duration: "5 days",
percentComplete: Math.round(Math.random() * 100),
start: "01/01/2009",
finish: "01/05/2009",
effortDriven: (i % 5 == 0)
};
}
var dataView = new Slick.Data.DataView();
grid = new Slick.Grid("#myGrid", dataView, columns, options);
function comparer(a,b) {
var x = a[sortcol], y = b[sortcol];
return (x == y ? 0 : (x > y ? 1 : -1));
}
var sortcol = "json_number";
var sortdir = 1;
grid.onSort.subscribe(function(e, args) {
sortdir = args.sortAsc ? 1 : -1;
sortcol = args.sortCol.field;
// using native sort with comparer
// preferred method but can be very slow in IE with huge datasets
dataView.sort(comparer, args.sortAsc);
});
dataView.beginUpdate();
dataView.setItems(data);
dataView.endUpdate();
grid.invalidate();
grid.render();
$("#myGrid").show();
})
Try adding this listener, which re-renders the grid when rows get shuffled around:
dataView.onRowsChanged.subscribe(function(e,args) {
grid.invalidateRows(args.rows);
grid.render();
});
Original example here: http://mleibman.github.com/SlickGrid/examples/example4-model.html
Even though there already is an accepted answer which surely solved the initial question, I wanted to point out a common mistake on stackoverflow while handling Slickgrid's subscribe method.
Let us imagine our grid is in the variable called 'grid', like in most other examples.
This occurs in most of the accepted and/or upvoted answers:
dataView.onRowsChanged.subscribe(function(e,args) {
grid.invalidateRows(args.rows);
grid.render();
});
or
grid.onSort.subscribe(function(e, args){
var cols = args.sortCols;
data.sort(function(dataRow1, dataRow2){
for (var i = 0, l = cols.length; i < l; i++){
var field = cols[i].sortCol.field;
var sign = cols[i].sortAsc ? 1 : -1;
var value1 = dataRow1[field], value2 = dataRow2[field];
var result = (value1 == value2 ? 0 : (value1 > value2 ? 1 : -1)) * sign;
if (result != 0) return result
}
return 0;
})
grid.invalidate()
grid.render()
})
Do this examples work as intended? Yes, they do.. under certain circumstances.
Let us imagine a function which adds a Slickgrid to a list of Slickgrids:
var m_grids = []
function anyName(){
var grid;
//..run code
//..run subscribe
m_grids.push(grid)
}
So what happends now when we are trying to call any subscribe function, while the subscribe function contains the variable grid? It merely affects the last assigned grid, no matter on which one the subscribe got executed on.
The correct way to subscribe those functions is by the args parameter:
dataView.onRowsChanged.subscribe(function(e,args) {
args.grid.invalidateRows(args.rows);
args.grid.render();
});
or
grid.onSort.subscribe(function(e, args){
var cols = args.sortCols;
args.grid.getData().sort(function(dataRow1, dataRow2){
for (var i = 0, l = cols.length; i < l; i++){
var field = cols[i].sortCol.field;
var sign = cols[i].sortAsc ? 1 : -1;
var value1 = dataRow1[field], value2 = dataRow2[field];
var result = (value1 == value2 ? 0 : (value1 > value2 ? 1 : -1)) * sign;
if (result != 0) return result
}
return 0;
})
args.grid.invalidate()
args.grid.render()
})
This might be a minor case since it requires usually more than one Slickgrid on the same page, yet why make it wrong when we could do it correct very easily :)
Related
I have to do a binary search for a names directory in typescript, if the name is in the array the code works properly but if the name it's not in the array it became in an infinite loop.
Can somebody help me? Please!
This is the code:
var initialArray = ['Diego', 'David','Mauricio']
var sortedArray = initialArray.sort()
function search(find) {
var leftLimit = initialArray[0]
var leftLimitIndex = initialArray.indexOf(leftLimit)
var rightLimit = initialArray[initialArray.length - 1]
var rightLimitIndex = initialArray.indexOf(rightLimit)
var pivotIndex = 0
var index = -1
while (compare(leftLimit, rightLimit)) {
pivotIndex = Math.floor((leftLimitIndex + rightLimitIndex)/2)
console.log(pivotIndex)
if (initialArray[pivotIndex] == find) {
index = pivotIndex
break
}
else {
if (compare(initialArray[pivotIndex], find)) {
leftLimitIndex = pivotIndex + 1
}
else {
rightLimitIndex = pivotIndex - 1
}
}
console.log(initialArray[pivotIndex])
}
console.log("Result: "+initialArray[index])
return initialArray[index]
}
function compare(leftLimit, rightLimit) {
var r = (leftLimit < rightLimit ? -1 : 1)
if (r < 0) {
return true
}
else {
return false
}
}
Youare not taking in account the limits index which change and at the end you dont know if you have not more options to search or if the findTerm doesnt exits at all.
You only need to change the follow line
while (compare(leftLimit, rightLimit) && leftLimitIndex <= rightLimitIndex) {
Regards,
I want to havesimple slickgrid column sort. however I might not understand the basic idea.
what I have done is like this.
Make column sortable
{id: "score", name: "number", field: "score",sortable: true},
Make function for sort calculation.
function sortfn(o1, o2) {
if (o1[column.field] > o2[column.field]) {
return 1;
} else if (o1[column.field] < o2[column.field]) {
return -1;
}
return 0;
}
then subsclibe to onSort.
grid.onSort.subscribe(function (e, args) {
grid.invalidateAllRows();
grid.render();
});
then next,,,,
I guess I should put sortfn somewhere though, but how??
where should I put sortfn??
Check out the examples here. There is no default sorting in the grid - this is left to the datasource to manage.
This example uses the native javascript sort property of the source data array to sort the rows:
grid = new Slick.Grid("#myGrid", data, columns, options);
grid.onSort.subscribe(function (e, args) {
var cols = args.sortCols;
data.sort(function (dataRow1, dataRow2) {
for (var i = 0, l = cols.length; i < l; i++) {
var field = cols[i].sortCol.field;
var sign = cols[i].sortAsc ? 1 : -1;
var value1 = dataRow1[field], value2 = dataRow2[field];
var result = (value1 == value2 ? 0 : (value1 > value2 ? 1 : -1)) * sign;
if (result != 0) {
return result;
}
}
return 0;
});
grid.invalidate();
grid.render();
});
This example outsources the sorting to the DataView object which is the grid's datasource.
grid.onSort.subscribe(function (e, args) {
sortdir = args.sortAsc ? 1 : -1;
sortcol = args.sortCol.field;
if (isIEPreVer9()) {
// using temporary Object.prototype.toString override
// more limited and does lexicographic sort only by default, but can be much faster
var percentCompleteValueFn = function () {
var val = this["percentComplete"];
if (val < 10) {
return "00" + val;
} else if (val < 100) {
return "0" + val;
} else {
return val;
}
};
// use numeric sort of % and lexicographic for everything else
dataView.fastSort((sortcol == "percentComplete") ? percentCompleteValueFn : sortcol, args.sortAsc);
} else {
// using native sort with comparer
// preferred method but can be very slow in IE with huge datasets
dataView.sort(comparer, args.sortAsc);
}
});
I need to sort data consisting of numbers and letters, this has been working very well for me.
function comparer(a, b) {
var collator = new Intl.Collator(undefined, {
numeric: true,
sensitivity: "base",
});
var x = a[sortcol];
var y = b[sortcol];
return collator.compare(x, y);
}
// add event listener to sort the grid
grid.onSort.subscribe(function (e, args) {
dataView.sort(comparer, args.sortAsc);
});
I'm working with some code I've adapted from and there's something I don't quite understand the best way to do. I'm trying to streamline a bit of code with different sorting functions that are applying sorts for specific values to an array of list items.
At the moment the function does a compare based on a specific factor and then returns the values to sort.
I want to pass two additional variables with this array/sort call but I can't seem to work out the way to write this. At the moment I'm doing it in a nasty way by having global variables on the window, but I'd rather pass the variables directly.
Based on the code below, any ways to tighten & clean it up would be appreciated:
arr = [];
sort_func = $j(this).children(':selected').val();
$j('li.collectionItem').each(function(){
arr.push(this);
});
if (sort_func == "a_z")
{
window.dataType = 'alpha';
window.bigFirst = false;
arr.sort(sort_products);
}
else if (sort_func == "z_a")
{
window.dataType = 'alpha';
window.bigFirst = true;
arr.sort(sort_products);
}
// custom sort functions
function sort_products(a, b)
{
dataType = window.dataType;
bigFirst = window.bigFirst;
var compA = $j(a).data(dataType);
var compB = $j(b).data(dataType);
if (bigFirst == true)
{
return (compA > compB) ? -1 : (compA < compB ) ? 1 : 0;
}
else
{
return (compA < compB) ? -1 : (compA > compB ) ? 1 : 0;
}
}
You can wrap original sort_products in another function, like this:
function sort_products(dataType, bigFirst)
{
return function (a, b)
{
var compA = $j(a).data(dataType);
var compB = $j(b).data(dataType);
if (bigFirst == true)
{
return (compA > compB) ? -1 : (compA < compB ) ? 1 : 0;
}
else
{
return (compA < compB) ? -1 : (compA > compB ) ? 1 : 0;
}
}
}
And then you can use it like this:
if (sort_func == "a_z")
{
arr.sort(sort_products('alpha', false));
}
else if (sort_func == "z_a")
{
arr.sort(sort_products('alpha', true));
}
I don't know how many elements you have, but it'd speed things up if you'd avoid making those jQuery (assuming that's what $j is) calls inside the comparator function.
var arr = []; // You really need to declare your variables!
var sort_func = $j(this).children(':selected').val();
var sortInfo = {
'a_z': {type: 'alpha', ascending: true},
'z_a': {type: 'alpha', ascending: false},
// ... whatever the other types are
}[sort_func];
$j('li.collectionItem').each(function(){
arr.push({ elem: this, key: $j(this).data(sortInfo.type) });
});
arr.sort(function(a, b) {
return (sortInfo.ascending ? 1 : -1) *
a.key > b.key ? 1 : a.key < b.key ? -1 : 0;
});
// transform the array into an array of just the DOM nodes
for (var i = 0; i < arr.length; ++i)
arr[i] = arr[i].elem;
EDIT**
In a game I am creating I use the next question button to move onto other questions in the grid if the user is having trouble with the current one. At the moment I have had real problems with it as it keeps on crashing my program, and not giving any console errors. The last problem I had with it was that it said "too much recursion". Since then I thought I had sorted the problem, but I have just done a few tests and it crashes every time.
This is the click event for the button...
//Next question click event
$('.next-question').bind("click", function() {
$('td').removeClass('highlight-problem');
shuffleEqually(listOfWords);
shuffleEqually(nextWordIndexes);
var rndWord = nextWordIndexes[Math.floor(Math.random())];
var rndWord = nextWordIndexes[2];
//Adds and removes nesesary classes
$('td[data-word="' + listOfWords[rndWord].name + '"]').addClass('highlight-problem');
$('td[data-word=' + word + ']').removeClass('wrong-letter').removeClass('wrong-word').removeClass('right-letter');
var spellSpace = $('td[data-word="' + listOfWords[rndWord].name + '"]').hasClass('right-word');
if (spellSpace) {
$('.next-question').trigger('click');
} else {
$("#hintSound").attr('src', listOfWords[rndWord].audio);
hintSound.play();
$("#hintPic").attr('src', listOfWords[rndWord].pic);
$('#hintPicTitle').attr('title', listOfWords[rndWord].hint);
}
});
I think it may have something to do with the if statement, but have tried changing it to this..
if (spellSpace == false) {
$("#hintSound").attr('src', listOfWords[rndWord].audio);
hintSound.play();
$("#hintPic").attr('src', listOfWords[rndWord].pic);
$('#hintPicTitle').attr('title', listOfWords[rndWord].hint);
}
and it makes it even worse
ShuffleEqually:
//Shuffles words to randomize
shuffleEqually(nextWordIndexes);
var shuffledWords = [];
shuffledWords = chosenWords.sort(function () {
return 0.5 - Math.random();
});
function shuffleEqually(a1, a2) {
var arrays = [];
if (typeof a1 === 'object' && a1.length > 0) {
arrays.push(a1);
}
if (typeof a2 === 'object' && a2.length > 0) {
arrays.push(a2);
}
var minLength = arrays[0].length;
jQuery.each(arrays, function (i, a) {
minLength = a.length < minLength ? a.length : minLength;
});
var randoms = [];
for (i = 0; i < minLength; i++) {
randoms.push(Math.random());
}
jQuery.each(arrays, function (i, a) {
var i = minLength;
while (i--) {
var p = parseInt(randoms[i] * minLength);
var t = a[i];
a[i] = a[p];
a[p] = t;
}
});
};
Hint sound:
var hintSound = $("#hintSound")[0];
Your issue is an infinite loop, plain and simple.
$('.next-question').bind("click", function() {
// binds click...
...
if (spellSpace) {
$('.next-question').trigger('click');
// triggers click ON THE SAME ELEMENT COLLECTION (same selector)
You want to refine this. I assume you want the trigger to work on the next question, so I suggest changing the second statement to:
$(".next-question").eq(($(".next-question").index($(this)) + 1) % $(".next-question").length).trigger("click");
You have a second infinite loop in shuffleEqually:
jQuery.each(arrays, function (i, a) {
var i = minLength;
while (i--) {
var p = parseInt(randoms[i] * minLength);
var t = a[i];
a[i] = a[p];
a[p] = t;
}
Change the while condition to have a limiting value, or it will loop endlessly (as a decrement operation always succeeds).
I have an array of objects gAllMedicalFilesClaimantsArray with 2 properties (UserID & UserInfo)
For example:
gAllMedicalFilesClaimantsArray[0].UserID = "111";
gAllMedicalFilesClaimantsArray[0].UserInfo = "AAA-111";
gAllMedicalFilesClaimantsArray[1].UserID = "222";
gAllMedicalFilesClaimantsArray[1].UserInfo = "BDD-478333";
What is the fastest way to check whether a specific UserID exists in the array using Jquery or Javascript because gAllMedicalFilesClaimantsArray has got 8000 records?
Thanks
var match = '222';
var matches = $.grep(myArray, function(el, index) {
return (el.UserID === match);
});
You can fasten the search process by using Binary Search algorithm if the array is sorted (e.g with respect to UserId).
function binarySearch(array, userid) {
var low = 0, high = array.length - 1,
i, comparison;
while (low <= high) {
i = parseInt((low + high) / 2, 10);
if (array[i].UserId < userid) { low = i + 1; continue; };
if (array[i].UserId > userid) { high = i - 1; continue; };
return array[i];
}
return null;
};
You can find the user of which ID is 12 by using the function:
var result = binarySearch(gAllMedicalFilesClaimantsArray, 12);
Something like this, I believe:
function exists(uid) {
var k = gAllMedicalFilesClaimantsArray.length;
uid = uid.toString(); // ensure the arg is a str (this can be omitted)
while (k--) {
if (gAllMedicalFilesClaimantsArray[k].UserID === uid) {
return true;
}
}
return false;
}
Is the array sorted by the UserID? If so, it can be improved either further by using a binary search; that would change this from O(n) to O(log n). Your example suggests it is. I found a good implementation of a binary search in JavaScript on the web, here. Here is the code if the site ever dies:
function binarySearch(items, value){
var startIndex = 0,
stopIndex = items.length - 1,
middle = Math.floor((stopIndex + startIndex)/2);
while(items[middle] != value && startIndex < stopIndex){
//adjust search area
if (value < items[middle]){
stopIndex = middle - 1;
} else if (value > items[middle]){
startIndex = middle + 1;
}
//recalculate middle
middle = Math.floor((stopIndex + startIndex)/2);
}
//make sure it's the right value
return (items[middle] != value) ? -1 : middle;
}
ExistsInArray(value, array){
for(var item in array){
if(item.UserId == value){
return true;
}
}
return false;
}
You can either prototype Array object, like this:
Array.prototype.exists = function(value, prop){
var i = null;
for (i in this)
if (this[i][prop] && this[i][prop] == value)
return true;
return false;
}
gAllMedicalFilesClaimantsArray.exists('222', 'UserID');