I'm working with an ecommerce platform that lacks the ability to reorder the options of our product attribute fields. It really sucks because to insert a new option you pretty much have to delete all of the existing ones and start over. I'm trying to do it client-side instead. Here's what I'm working with (this one's for a shoe size):
These are actually the text of some <option>
s in a form. The format of the values is X Y Z
where:
X
is a whole numberY
is the string "1/2" and may not be presentZ
is a letter code which is either "D", "E", "EEE", or "EEEE", and may not be presentThe desired order of the above would be this:
I've learned a little bit about javascript's sort()
function but haven't been able to fully comprehend how the comparison function that you can pass to it works. I've got this so far:
<select>
<option>9 EE</option>
<option>9 1/2 EE</option>
<option>10 EE</option>
<option>10 1/2 EE</option>
<option>11 EE</option>
<option>11 1/2 EE</option>
<option>9 EEEE</option>
<option>9 1/2 D</option>
<option>9 1/2 EEEE</option>
<option>10 EEEE</option>
<option>10 1/2 EEEE</option>
<option>11 EEEE</option>
<option>9 D</option>
<option>11 1/2 EEEE</option>
</select>
I started with the code taken from this answer: https://stackoverflow.com/a/667198/398242
$("select").html($("option").sort(function (a, b) {
return a.text == b.text ? 0 : a.text < b.text ? -1 : 1
}));
Which sorts the items like this (doesn't work for even the first criteria):
I see that in javascript '11' > '9'
returns false
, which in no way makes sense to me.
MDN describes the compare function argument as such, and I kind of get it:
function compare(a, b) {
if (a is less than b by some ordering criterion)
return -1;
if (a is greater than b by the ordering criterion)
return 1;
// a must be equal to b
return 0;
}
...but I haven't got a clue how to adapt this to fit my requirements. I've tried a few things but I just feel like I'm shooting in the dark. I've tried to show that I've taken some time to attempt an understanding of this problem. I'm interested in learning more, but for now I'd just like to get this issue solved.
http://jsfiddle.net/DnwJ6/ Any clues?
The sort() method sorts the elements of an array in place and returns the reference to the same array, now sorted. The default sort order is ascending, built upon converting the elements into strings, then comparing their sequences of UTF-16 code units values.
The Ruby sort method works by comparing elements of a collection using their <=> operator (more about that in a second), using the quicksort algorithm. You can also pass it an optional block if you want to do some custom sorting. The block receives two parameters for you to specify how they should be compared.
sort takes an array and — you guessed it — sorts it in place. No copy of the array is created (as with map , etc.), so the array itself is altered with the sorted values. It can be used with or without a compareFunction , and when one isn't provided, it will automatically sort in ascending order.
C# is using a default comparer method to sort integers numerically. The Sort method orders the integers in ascending order, while the Reverse method in descending order. The following example sorts integers with LINQ. In LINQ, we can choose between the query syntax or the method syntax.
Since you have formatted text, one way is to normalize the text elements before comparing them.
This solution may not be that optimal, but will do the job
$("select").html($("option").sort(function (a, b) {
return nomalize(a.text) < nomalize(b.text) ? -1 : 1;
}));
function nomalize(val){
var parts = val.split(' '), op = '';
op = parts[0].length == 1 ? '0' + parts[0] : parts[0];
if(parts.length > 1){
if(/[a-z]/i.test(parts[1])){
op += '0/0' + parts[1];
} else {
op += parts[1]
}
}
op += parts.length > 2 ? parts[2] : '';
return op;
}
Demo: Fiddle
If somebody can suggest any solution to optimize it further it will be great
Put the values in an array in the order you want them:
var shoeSizes = [ '9 D','9 1/2 D','9 EE','9 1/2 EE', ...]
Use Array.protoype.indexOf (with a shim for older browsers) to get the index of the matched text in the array. Use the index for the value to compare, something like:
function(a,b) {
return shoeSizes.indexOf(a) - shoeSizes.indexOf(b);
}
If you need to deal with values that aren't in the array, test the value returned by indexOf and substitute a default if it's -1.
Alternatively you can make the sizes the names of property values in an object and assign a specific value:
var shoeSizes = { '9 D': 5, '9 1/2 D': 10, '9 EE': 15, '9 1/2 EE': 20, ...};
Then use the value in the compare:
function(a,b) {
return shoeSizes[a] - shoeSizes[b];
}
Or to allow for default values:
function(a,b) {
return (a in shoeSizes? shoeSizes[a] : 1000) - (b in shoeSizes? shoeSizes[b] : 1000);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With