4

Using PHP, I scan a directory and list all of the .xml files. Each XML file contains both a "name" element and a "date" element. The "name" element for each XML file is listed as an option in the select list. This works perfectly fine, however, the "date" element in each XML file is different and contains a date format like this: mm/dd/yyyy. What I am trying to figure out how to do is sort the items according to the date, with the earliest date being first one the list and the most recent at the end.

Now say each of those items has a different value for the "date" element. I need to sort those items with the earliest date being first. I'm not sure how I can store the "date" element data somewhere so that it can be handled by JavaScript. I'm sorry if this is a very vague description, it's been baffling me for a while and it's a been confusing to try and explain.

UPDATED

So right now this is what I have working:

<select name="sel_id" onchange="this.form.submit()" size="20">
<option value="item1">Item 1</option>
<option value="item2">Item 2</option>
<option value="item3">Item 3</option>
<option value="item4">Item 4</option>
</select>

I guess one thing that would majorly help is knowing if there's a way to store the date somewhere in the tags besides the value attribute seeing how it's already being used. The date itself isn't a concern, I have that much figured it, it's just a matter of storing it somewhere so that it can be called client side.

0

4 Answers 4

7

Updated

You need to:

  • use a custom attribute for the dates
  • use sort() function's custom compare function parameter
  • convert to array to make sorting possible
  • convert the dates for string comparison (mm/dd/yyyy -> yyyy-mm-dd)

See it in action

[Tested on: IE 5.5+, FF 2+, Chrome 4+, Safari 4+, Opera 9.6+]

HTML:

<select name="sel_id" id="sel_id" size="4">
  <option value="item2" date="02-01-2009">Item 2</option>
  <option value="item3" date="01-05-2010">Item 3</option>
  <option value="item1" date="10-06-2007">Item 1</option>
  <option value="item4" date="04-05-2011">Item 4</option>
</select>

Javascript:

// array functions are not working
// on nodeLists on IE, we need to
// to convert them to array
function toArray( obj ) {
  var i, arr = [];
  for ( i = obj.length; i--; ){
    arr[i] = obj[i];
  }
  return arr;
}

// custom compare function for sorting
// by the hidden date element
function sortByDate( el1, el2 ) {
  var a = convertToDate( el1.getAttribute("date") ),
      b = convertToDate( el2.getAttribute("date") );
  if ( a < b ) return -1;
  else if( a > b ) return 1;
  else return 0;
}

// convert date for string comparison
function convertToDate( date ) {
  date = date.split("-");
  return date[2] + "-" + date[0] + "-" + date[1];
}

// select the elements to be ordered
var itemsId = document.getElementById("sel_id"),
    items   = itemsId.getElementsByTagName("option"),
    len     = items.length;

// convert to array, to make sorting possible
items = toArray( items );

// do the item sorting by their date
items = items.sort( sortByDate );

// append them back to the parent in order
for ( var i = 0; i < len; i++ ) {
  itemsId.appendChild( items[i] );
}

​ ​

Sign up to request clarification or add additional context in comments.

5 Comments

This isn't exactly a select element.
it wasn't a about <select> in the question when i answered. I reorganize my answer. But be more specific next time..
Thank you, works great. Sorry for the delayed replies. One last question. I easily turned this into a function so that I can call it from a link and it works fine, but I also tried implementing a function to sort the options back to alphabetical order. I've tried several different ways to do this and it works at first, sorting them by date works, then by name, but after that, neither sorting options work.
I've made a new revision for your needs: jsbin.com/oraxi4/9/edit. Have Fun!
HTML5-style, shouldn't that custom attribute be 'data-date="02-01-2009"'? Primo answer tho, very nice!
2

Short and sweet. This version also accounts for dates being in mm-dd-yyyy format as per the OP's request.

<form>
  <select id="myList">
    <option value="07-01-2010">Item 2</option>
    <option value="09-21-2009">Item 1</option>
    <option value="08-22-2010">Item 3</option>
  </select>
</form>
<script>
  var list    = document.forms[0].myList,
      opts    = list.options,
      len     = opts.length,
      sorted  = [].slice.call(opts).sort(function(a,b){
        return fixDate(a.value) < fixDate(b.value) ? -1 : 1;
      });

  for (var i=0; i<len; i++) {
    list.appendChild(sorted[i]);
  }

  // convert m-d-y to y-m-d
  function fixDate (d) {
    var a=d.split('-');
    a.unshift(a.pop()); 
    return a.join('-');
  }

</script>

Comments

0

I would take the answer from galambalazs above but use the data attribute instead of a date attribute. as "data-date" is considered standards compliant while "date" is just a custom attribute.

Comments

-1

You can represent the dates as option values, or use a data attribute to store them with an option.

<option value="2010-07-05">..</option>

or

<option data-date="2010-07-05">..</option>

Assuming your select list looks like this:

<select id="myList">
    <option value="2010-07-01">Item 1</option>
    <option value="2010-06-21">Item 1</option>
    <option value="2010-08-22">Item 1</option>
    ..
</select>

Use the inbuilt Array.sort function with a custom comparator to sort the nodes, and once sorted re-insert them into the select list. See an example here.

/**
 * Sorts option elements by value attribute which holds a date
 *
 * @param {HTMLOptionElement} a first option
 * @param {HTMLOptionElement} b second option
 *
 * @returns {Integer}
 */
var sortByDate = function(a, b) {
    return new Date(a.value) - new Date(b.value);
}

var list = document.getElementById("myList");
var options = list.getElementsByTagName("option");
// NodeList that we get in previous step is an array-like
// object but not actually an array. Some call it a fuck-up,
// but regardless we need to convert it to an array.
var optionsArray = Array.prototype.slice.call(options);

// Now that we have an array, we can use the sort method (in-place sorting)
optionsArray.sort(sortByDate);

// re-insert the sorted nodes
for(var i = 0; i < optionsArray.length; i++) {
    list.appendChild(optionsArray[i]);
}
​

9 Comments

Not gonna work. You can't create a date from a string like that, and you forgot to clear the options before putting the "sorted" ones in.
Well you can create a date from a string like "yyyy-mm-dd". Works on Chrome and Firefox. If some browsers complain, manually compose the date or use a date library such as Datejs, but that is not the main point of the question. I purposely removed the code to clear the options array first as that is not needed. See DOM specs for appendChild - "Adds the node newChild to the end of the list of children of this node. If the newChild is already in the tree, it is first removed."
You're right, I stand corrected on both counts. Although if the date strings are formatted like that, there's no reason to convert to a date... a string comparison should suffice. The thing you pointed out about appendChild is very interesting, thanks. (edit: on reviewing the OP, I see that his dates are formatted mm/dd/yyyy, so it looks like we have more work to do after all ;)
@no - mm/dd/yyyy is kinda problematic, but I think converting to date is going to helpful, as string comparisons are done lexicographically, so things like "10" < "2" evaluate to true. I realized the code could have been shorted after seeing the appendChild specs, and who doesn't like lesser code :)
use the data attributes? <option data-date="2010-07-05">..</option>
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.