Reputation: 310
I apologize there are similar threads but I can't solve this issue. I have a JSON object that contains keys and values (representing file IDs and file names). Since a JS object cannot be sorted, I need to convert to an array, sort by value (i.e., file name) NOT by key (i.e., file ID). I can accomplish all this except when converting to array, I am losing my keys/file IDs (e.g., 110, 111, 112) and they are replaced with the default array keys (0,1,2, etc.).
// Assign object to a var
$obj_win_top_get_files = window.top.<?php echo $_GET['files']; ?>;
Looking at the object via console.log,
console.log('checked_boxes', $obj_win_top_get_files);
I see:
Object {110: "013_904_general.docx", 111: "013_902_info.docx", 112: "013_120_list.docx"}
// Sort JSON object by file name ("value") rather than by id ("key")
// Create an array first since JS object is NOT sortable
arr_ids_filenames = new Array();
// Loop thru JS object to populate new array so it can be subsequently sorted
$.each($obj_win_top_get_files, function (key, value) {
console.log(key, value);
// Populate array
arr_ids_filenames[key] = value;
});
// Sort array by values
arr_ids_filenames.sort();
// THIS IS WHERE I AM LOSING THE FILE IDs (keys)
$.each(arr_ids_filenames, function (key, value) {
// Array may contain keys/IDs with no values/file names so make sure there is a value
if(value){
console.log(key, value);
$the_ul.append('<li id="chk_file_' + key + '">' + value + '</li>');
}
});
Everything works except they keys are not the file IDs (110,111,112), they are the default array keys (0,1,2). It is something in the $.each() that I am not doing correctly. I am close, but have not been able to solve this one. Any recommendations will be greatly appreciated.
Upvotes: 1
Views: 1376
Reputation: 2706
UPDATED SOLUTION:
The original solution I provided does not work in IE11. Console was returning a "SCRIPT1003" error which, upon further research, led me to this SO question: JavaScript in IE11 giving me script error 1003
IE11 doesn't support ES6 key-pair shorthand. Taking this into account, the updated code should look like this:
var arr_ids_filenames = [];
// convert your file list into an array of objects
$.each($obj_win_top_get_files, function(key, name) {
// use key:pair format
arr_ids_filenames.push({
key: key,
name: name
});
});
// sort by file name (and not by key/id)
arr_ids_filenames.sort(function(a, b) {
return ((a.name < b.name) ? -1 : ((a.name > b.name) ? 1 : 0));
});
// add items to list
$.each(arr_ids_filenames, function(index, file) {
$the_ul.append('<li id="chk_file_' + file.key + '">' + file.name + '</li>')
});
See the code in action: https://jsfiddle.net/7y7qps88/53/
Upvotes: 0
Reputation: 13409
Create an array of arrays with 2 items in the array. The key and the object. Now you have an array like:
[
[originalKey, obj],
[originalKey, obj],
[originalKey, obj]
]
then use a custom sort function:
arr_ids_filenames.sort(function(a,b){ return a[1] - b[1] });
(NOTE: I'm assuming your objects are just integers, if not do this for sorting)
arr_ids_filenames.sort(function(a, b) {
a = a[1]; // now a points to object 1
b = b[1]; // now b points to object 2
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;
});
all together:
// Sort JSON object by file name ("value") rather than by id ("key")
// Create an array first since JS object is NOT sortable
arr_ids_filenames = new Array();
// Loop thru JS object to populate new array so it can be subsequently sorted
var i = 0;
$.each($obj_win_top_get_files, function (key, value) {
console.log(key, value);
// Populate array
arr_ids_filenames[i++] = [key,value];
});
// Sort array by values
arr_ids_filenames.sort(function(a,b){ return a[1] - b[1] });
// THIS IS WHERE I AM LOSING THE FILE IDs (keys)
$.each(arr_ids_filenames, function (i, v) {
// Array may contain keys/IDs with no values/file names so make sure there is a value
if(v[0]){
var key = v[0];
var value = v[1];
$the_ul.append('<li id="chk_file_' + key + '">' + value + '</li>');
}
});
Upvotes: 2
Reputation: 35481
By adding an object to an array at an index greater than the length of the array (which is what you are doing with arr_ids_filenames[key] = value
) all previous (before that index) uninitialized elements get initialized to undefined
.
For instance, doing this to an empty array:
arr_ids_filenames[110] = 'ANYSTRING'
You get:
arr_ids_filenames[0] = undefined;
arr_ids_filenames[1] = undefined;
// ...
arr_ids_filenames[110] = 'ANYSTRING';
Now after you sort, since:
'ANYSTRING' > undefined // is false
'ANYSTRING' < undefined // is false
Your value is the smallest value and thus gets stored at index 0
with all undefined
s after it. All your next storage attempts follow this pattern.
Therefore, you end up with an array of 112 elements, with your strings at the first 3 positions. One way to solve this is to create an object:
var file = {
id: '',
name: ''
};
And then, for each file, insert that object into a new array:
// Loop thru JS object to populate new array so it can be subsequently sorted
$.each($obj_win_top_get_files, function (key, value) {
console.log(key, value);
// Populate array
var file = {
id: key,
name: value
};
arr_ids_filenames.push(file);
});
Sort the array by file name (by using a comparator):
arr_ids_filenames.sort(function(a, b) { return a.name < b.name; });
And finally insert them in the DOM:
$.each(arr_ids_filenames, function(idx, file) {
// Array may contain keys/IDs with no values/file names so make sure there is a value
if (file.name) {
var key = file.id;
var value = file.name;
$the_ul.append('<li id="chk_file_' + key + '">' + value + '</li>');
}
});
Here's a running example:
var $obj_win_top_get_files = {
110: "013_904_general.docx",
111: "013_902_info.docx",
112: "013_120_list.docx"
}
var arr_ids_filenames = [];
// Loop thru JS object to populate new array so it can be subsequently sorted
$.each($obj_win_top_get_files, function(key, value) {
// Populate array
arr_ids_filenames.push({
id: key,
name: value
});
});
// Sort the array by file name (by using a comparator):
arr_ids_filenames.sort(function(a, b) {
return a.name < b.name;
});
console.log('sort: ' + JSON.stringify(arr_ids_filenames));
// And finally insert them in the DOM:
var $the_ul = $('ul');
$.each(arr_ids_filenames, function(idx, file) {
if (file.name) {
var key = file.id;
var value = file.name;
console.log('here');
$the_ul.append('<li id="chk_file_' + key + '">' + value + '</li>');
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul></ul>
Upvotes: 0