I'm trying to reverse this sort on click using ReactJS:
if (this.state.Prz==3) {
this.props.files.sort(function(a,b){
return a.lastModified < b.lastModified ? 1 : -1;
});
}
I tried many tricks searching on Google but I'm still stuck.
You can change the direction of sort (since you seem to be sorting by Date) by swapping 1 and -1:
this.props.files.sort(function(a,b){
return a.lastModified < b.lastModified ? -1 : 1;
});
Or you can reverse the array, assuming it was sorted before doing that (concat() is for making a copy of the array, keeping things "immutable"):
this.props.files.concat().reverse();
You can reverse an array simply by calling reverse
this.props.files.reverse()
Beware though that this will mutate the original array.
Here finally how I did. I add a condition.
if (this.state.activePrz==3) {
this.props.files.sort(function(a,b){
var asc = a.lastModified < b.lastModified;
var desc = a.lastModified > b.lastModified;
if(asc == true){
return asc;
}else{
return desc;
}
})
}
And it works.
I couldn't :
this.props.files.reverse();
or
this.props.files.concat().reverse();
The error message was :
Cannot read property 'files' of undefined
Many thanks for your help.
Related
I am not a coder, I am messing around with some JavaScript as part of modding a game, so bear with me. This game supports es5/everything Chromium 28 supported.
I had code which pushed a string to an array from a variable, and when the variable was undefined a fixed string was pushed instead:
slotsArray.push({
landing_policy: ai.landing_policy || 'no_restriction'
});
The setup changed such that where ai.landing_policy was set it would contain multiple values, so it become an array. When it wasn't set only a single entry was required.
The same code does not appear to work where an array is in place:
for (var i = 0; i < count; i++) {
slotsArray.push({
landing_policy: ai.landing_policy[i] || 'no_restriction'
});
}
An error is produced because it's trying to check a value from a variable that hasn't been defined. I expected that to cause it to use the fixed value, but apparently that's not what happens, it just fails.
I've changed my approach to the code seen below in full:
if (Array.isArray(ai.landing_policy)) {
for (var i = 0; i < count; i++) {
slotsArray.push({
landing_policy: ai.landing_policy[i]
});
}
}
else {
slotsArray.push({
landing_policy: ai.landing_policy || 'no_restriction'
});
}
This code works, but what I'm looking to understand is whether this was the best solution? The old method felt elegant, while the new one looks a little clumsy.
You can use the ternary operator(? :).
It will return the second value if the first is true, and the third otherwise.
I've used array instanceof Array instead of Array.isArray(array) to support ES5.
var isArray = ai.landing_policy instanceof Array
for (var i = 0; i < (isArray ? count : 1); i++) {
slotsArray.push({
landing_policy: isArray ? ai.landing_policy[i] : ai.landing_policy || 'no_restriction'
});
}
Elegant solution not always converse to the most readable/desirable. I would probably do something like:
const formattedPolicy = ai.landing_policy.map(policy => policy || 'no_restriction');
slotsArray = [...formattedPolicy ];
Course this has to imply that the ai.landing_policy is always an array. If you need to double check first you could also do:
const formattedPollicy = ai.landing_policy.constructor === Array
? ai.landing_policy.map(policy => policy || 'no_restriction');
: [ai.landing_policy]
Looks like an elegant or short imho but your code is way more readable.
I have search through quite a lot of questions here, but havent found one that i think fits my bill, so if you know of one please link to it.
I have an array that i want to search through for a specific number and if that number is in the array, i then want to take an action and if not then another action.
I have something like this
var Array = ["1","8","17","14","11","20","2","6"];
for(x=0;x<=Array.length;x++)
{
if(Array[x]==8)
then change picture.src to srcpicture1
else
then change picture.src to srcpicture2
}
but this will run the lenght of the array and end up checking the last element of the array and since the last element is not 8 then it will change the picture to picture2.
Now i can see why this happens, i just dont have any ideas as to how to go about checking if an array contains a specific number.
Thanks in advance.
What you can do is write yourself a function to check if an element belongs to an array:
function inArray(array, value) {
for (var i = 0; i < array.length; i++) {
if (array[i] == value) return true;
}
return false;
}
And the just do:
var arr = ["1","8","17","14","11","20","2","6"];
if (inArray(arr, 8)) {
// change picture.src to srcpicture1
} else {
// change picture.src to srcpicture2
}
It's a lot more readable to me.
For extra points you can add the function to the array prototype like so:
Array.prototype.has = function (value) {
for (var i = 0; i < this.length; i++) {
if (this[i] === value) return true;
}
return false;
};
And then the call would be
if (arr.has(8)) // ...
Pushing this even further, you can check for indexOf() method on array and use it - if not - replace it with the code above.
P.S. Try not to use Array for a variable name, since it's reserved for the actual array type.
use this
http://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Objects/Array/IndexOf
ie version
https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Objects/Array/IndexOf#Compatibility
Why don't just you abort the loop when you find the right number :
for(x=0;x<=Array.length;x++)
{
if(Array[x]==8) {
//change picture.src to srcpicture1
break;
}
}
You could sort the array first then check the array only up to the point at which a number would be in the array, were it to exist.
If you have unique keys and a faster retrieval is what you care about a lot, you can consider using a map instead of an array (if there's a hard-bound case of using an array, then it won't work of course). If using a map, you just check "if( num in arr ) ".
I can sort my data using Knockout's .sort(). But, when I try to sort dynamically on a user's click, the sort goes haywire. Here's my code:
var patientReport = [{"first_name":"Lyle","last_name":"Erickson","patient_id":1000},{"first_name":"Janna","last_name":"Barr","patient_id":1001},{"first_name":"Shelly","last_name":"Delacruz","patient_id":1002},{"first_name":"Nissim","last_name":"Wong","patient_id":1003},{"first_name":"Yvonne","last_name":"Rocha","patient_id":1004},{"first_name":"Leo","last_name":"Holland","patient_id":1005},{"first_name":"Melinda","last_name":"Curtis","patient_id":1006},{"first_name":"Orlando","last_name":"Peters","patient_id":1007},{"first_name":"Miriam","last_name":"Bates","patient_id":1008},{"first_name":"Otto","last_name":"Hurley","patient_id":1009},{"first_name":"Doris","last_name":"Byrd","patient_id":1010}];
var myObservableArray = ko.observableArray(patientReport);
$('.sort_header').on('click', function() {
var data = $(this).data('header');
sortRows(data);
});
function sortRows(row) {
myObservableArray.sort(
function(left, right) {
return left.row == right.row ? 0 : (left.row < right.row ? -1 : 1);
}
);
}
Any ideas what is going wrong?
You need to use left[row] rather than left.row (and the same for right). The way you have it you are trying to sort by a property actually called "row". Using the square bracket syntax lets you use the property with the name specified by the variable row.
function sortRows(row) {
myObservableArray.sort(
function(left, right) {
return left[row] == right[row] ? 0 : (left[row] < right[row] ? -1 : 1);
}
);
}
I just started testing out Slickgrid for a project I'm working on and I'm very impressed with its performance. One requirement I have is sorting on multiple columns. I don't fully have my head wrapped around the Dataview in Slickgrid, so maybe I'm missing something obvious, but is there a way to sort a grid on multiple columns? Even if the UI can't handle sorting by more than one, I would like to be able to call a function with the columns in order, plus ascending or descending. I was able to do this with Datatables, but it doesn't have grouping (another requirement for the project).
In the worst case, I will resort to doing the sorting on the server and serving the content back to the client statically sorted.
I got it working for dataView with multi-column sort in the way. Was the easiest one to understand too. This is from the example in github, except that I've to pass one more parameter for dataView.sort(). It can always be true, and you can take care of the sort direction in your function.
grid.onSort.subscribe(function (e, args) {
gridSorter(args.sortCols, dataView);
});
function gridSorter(sortCols, dataview) {
dataview.sort(function (row1, row2) {
for (var i = 0, l = sortCols.length; i < l; i++) {
var field = sortCols[i].sortCol.field;
var sign = sortCols[i].sortAsc ? 1 : -1;
var x = row1[field], y = row2[field];
var result = (x < y ? -1 : (x > y ? 1 : 0)) * sign;
if (result != 0) {
return result;
}
}
return 0;
}, true);
}
Just in case it helps someone.
You can chain sort comparers to do multiple column sorting. Instead of doing
function comparerOnCol1(a, b) {
return a["col1"] - b["col1"];
}
function comparerOnCol2(a, b) {
return a["col2"] - b["col2"];
}
you can do
// sort by col1, then col2
function combinedComparer(a, b) {
return comparerOnCol1(a, b) || comparerOnCol2(a, b); // etc.
}
or just implement it inline.
As far as reflecting the sort order in the UI, while you can't do directly, you can apply the sort indicators by setting "headerCssClass" on the column definitions you're sorting by and having them display the arrows (or however else you're indicating sort columns).
There's an example here that uses the 'multiColumnSort' option.
http://mleibman.github.com/SlickGrid/examples/example-multi-column-sort.html
I don't think it works though, because args.sortCols is always an array of 1.
[Edit]
In order for it work, I need to hold shift before clicking on a column header (not very intuitive IMHO)
See also: https://github.com/mleibman/SlickGrid/pull/276
I spent a while trying to solve this with dataview (without shift key shenanigans) and I think I found the way to do it.
Use single column sort {multiColumnSort: false} and store the sort arguments in a closure. Defer to the previous comparitor if fields are equal.
var currentSortCmp = null;
grid.onSort.subscribe(function (e, args) {
// declarations for closure
var field = args.sortCol.field;
var sign = args.sortAsc ? 1 : -1;
var prevSortCmp = currentSortCmp;
// store closure in global
currentSortCmp = function (dataRow1, dataRow2) {
var value1 = dataRow1[field], value2 = dataRow2[field];
//if equal then sort in previous closure (recurs)
if (value1 == value2 && prevSortCmp)
return prevSortCmp(dataRow1, dataRow2);
return (value1 == value2 ? 0 : (value1 > value2 ? 1 : -1)) * sign;
};
dataView.sort(currentSortCmp);
grid.invalidate();
grid.render();
});
remembers all previous orders. just works. works as expected.
I have a line in a javascript function that sort an array of objects based on the order of another array of strings. This is working in firefox but not in IE and i don't know why. Here's what my data looks like going into the sort call, in IE7. (I'm using an array of three items just to illustrate the point here).
//cherry first then the rest in alphabetical order
originalData = ['cherry','apple','banana','clementine','nectarine','plum']
//data before sorting - note how clementine is second item - we wan to to to be after apple and banana
csub = [
{"value":"cherry","data":["cherry"],"result":"cherry"},
{"value":"clementine","data":["clementine"],"result":"clementine"},
{"value":"apple","data":["apple"],"result":"apple"},
{"value":"banana","data":["banana"],"result":"banana"},
{"value":"nectarine","data":["nectarine"],"result":"nectarine"},
{"value":"plum","data":["plum"],"result":"plum"}
]
//after sorting, csub has been rearranged but still isn't right: clementine is before banana. in FF it's in the right place.
csubSorted = [
{"value":"cherry","data":["cherry"],"result":"cherry"},
{"value":"apple","data":["apple"],"result":"apple"},
{"value":"clementine","data":["clementine"],"result":"clementine"},
{"value":"banana","data":["banana"],"result":"banana"},
{"value":"nectarine","data":["nectarine"],"result":"nectarine"},
{"value":"plum","data":["plum"],"result":"plum"}
]
Here's the actual sort code:
csubSorted = csub.sort(function(a,b){ return (originalData.indexOf(a.value) > originalData.indexOf(b.value)); });
Can anyone see why this wouldn't work? Is the basic javascript sort function not cross-browser compatible? Can i do this a different way (eg with jquery) that would be cross-browser?
grateful for any advice - max
EDIT - this also fails to work in safari and chrome - in other words, it only seems to work in firefox.
SOLVED - thanks to Tim Down.
I'd actually made my code simpler because i realised that the order that i needed was always "the first item in the returned array followed by the rest of the array sorted using .value". So, i changed my code thus:
first = csub.shift();
csubSorted = csub.sort(function(a,b){
return (a.value > b.value);
});
csubSorted.unshift(first);
But, it still wasn't working. Then Tim (below) pointed out that sort expects to get a -1, 0 or 1 back from the function, NOT true or false which is what my code was returning. Obviously firefox lets you get away with this, but the other browsers don't. All that was required was to 'translate' true or false into 1 and -1 (i don't worry about the case where both strings are the samae, effectively that will get returned as -1 which wouldn't make any difference to the sort order anyway):
first = csub.shift();
csubSorted = csub.sort(function(a,b){
return (a.value > b.value ? 1 : -1);
});
csubSorted.unshift(first);
Tim also told me that array.indexOf() isn't supported in IE which is annoying as even though i'm not using it here any more i am using it in other bits of code. Goddamit. Is there an API page somewhere which definitively lists only the cross-browser compatible javscript API?
First, there's no indexOfmethod of Array in IE <= 8. You'll need to write your own. Second, the comparison function passed to the sort() method of an Array should return a number rather than a Boolean.
var indexOf = (typeof Array.prototype.indexOf == "function") ?
function(arr, val) {
return arr.indexOf(val);
} :
function(arr, val) {
for (var i = 0, len = arr.length; i < len; ++i) {
if (typeof arr[i] != "undefined" && arr[i] === val) {
return i;
}
}
return -1;
};
csubSorted = csub.sort(function(a,b){
return indexOf(originalData, a.value) - indexOf(originalData, b.value);
});