-1

let array = [{"id":248439,"name":"Cross Creek Ranch/Creek Cove","surveyStatus":{"territoryName":"Fulshear","subdivisionName":"Cross Creek Ranch/Creek Cove","subdivisionId":248439,"dateTimeAdded":null,"surveyStatus":"0"}},{"id":248545,"name":"Lakes of Bella Terra/Via Verdone","surveyStatus":{"territoryName":"Fulshear","subdivisionName":"Lakes of Bella Terra/Via Verdone","subdivisionId":248545,"dateTimeAdded":null,"surveyStatus":"0"}},{"id":248546,"name":"Lakes of Bella Terra/Via Moderna","surveyStatus":{"territoryName":"Fulshear","dateTimeAdded":"2017-03-13 14:24:24.312","lng":-95.78459389953542,"userId":"6e77831f-9be5-41a4-8135-d961a94ef917","subdivisionId":"248546","surveyStatus":"2","territoryId":"4921","userName":"Michelle Artis","marketId":"13","subdivisionName":"Lakes of Bella Terra/Via Moderna","dateTimeUploaded":"2017-03-13 14:24:24.316","lat":29.68844027643332}},{"id":248547,"name":"Lakes of Bella Terra/Via Privato","surveyStatus":{"territoryName":"Fulshear","subdivisionName":"Lakes of Bella Terra/Via Privato","subdivisionId":248547,"dateTimeAdded":null,"surveyStatus":"0"}},{"id":248548,"name":"Lakes of Bella Terra/Mirandola","surveyStatus":{"territoryName":"Fulshear","subdivisionName":"Lakes of Bella Terra/Mirandola","subdivisionId":248548,"dateTimeAdded":null,"surveyStatus":"0"}},{"id":248549,"name":"Lakes of Bella Terra/La Bella Cortile","surveyStatus":{"territoryName":"Fulshear","dateTimeAdded":"2017-03-13 14:38:22.958","lng":-95.78834879221002,"userId":"6e77831f-9be5-41a4-8135-d961a94ef917","subdivisionId":"248549","surveyStatus":"2","territoryId":"4921","userName":"Michelle Artis","marketId":"13","subdivisionName":"Lakes of Bella Terra/La Bella Cortile","dateTimeUploaded":"2017-03-13 14:38:22.964","lat":29.69532227612072}},{"id":248838,"name":"Cross Creek Ranch/Pond","surveyStatus":{"territoryName":"Fulshear","dateTimeAdded":"2017-03-14 12:12:20.408","lng":-95.8761960827707,"userId":"6e77831f-9be5-41a4-8135-d961a94ef917","subdivisionId":"248838","surveyStatus":"1","territoryId":"4921","userName":"Michelle Artis","marketId":"13","subdivisionName":"Cross Creek Ranch/Pond","dateTimeUploaded":"2017-03-14 12:12:20.416","lat":29.70182981810505}},{"id":249626,"name":"Cross Creek Ranch/Legacy-Herons Lake","surveyStatus":{"territoryName":"Fulshear","dateTimeAdded":"2017-03-14 13:11:24.276","lng":-95.8625899069904,"userId":"6e77831f-9be5-41a4-8135-d961a94ef917","subdivisionId":"249626","surveyStatus":"2","territoryId":"4921","userName":"Michelle Artis","marketId":"13","subdivisionName":"Cross Creek Ranch/Legacy-Herons Lake","dateTimeUploaded":"2017-03-14 13:11:24.282","lat":29.70904039221789}},{"id":249727,"name":"Fulshear Run","surveyStatus":{"territoryName":"Fulshear","dateTimeAdded":"2017-03-14 11:49:22.765","lng":-95.8850889467596,"userId":"6e77831f-9be5-41a4-8135-d961a94ef917","subdivisionId":"249727","surveyStatus":"2","territoryId":"4921","userName":"Michelle Artis","marketId":"13","subdivisionName":"Fulshear Run","dateTimeUploaded":"2017-03-14 11:49:22.772","lat":29.6824066434332}},{"id":249739,"name":"Lakes of Bella Terra/Cittanova","surveyStatus":{"territoryName":"Fulshear","dateTimeAdded":"2017-03-13 15:56:25.460","lng":-95.78473585666696,"userId":"6e77831f-9be5-41a4-8135-d961a94ef917","subdivisionId":"249739","surveyStatus":"2","territoryId":"4921","userName":"Michelle Artis","marketId":"13","subdivisionName":"Lakes of Bella Terra/Cittanova","dateTimeUploaded":"2017-03-13 15:56:25.467","lat":29.69387132677221}},{"id":249883,"name":"Lakes of Bella Terra/Vita Bella","surveyStatus":{"territoryName":"Fulshear","dateTimeAdded":"2017-03-13 15:54:04.856","lng":-95.78164947228113,"userId":"6e77831f-9be5-41a4-8135-d961a94ef917","subdivisionId":"249883","surveyStatus":"1","territoryId":"4921","userName":"Michelle Artis","marketId":"13","subdivisionName":"Lakes of Bella Terra/Vita Bella","dateTimeUploaded":"2017-03-13 15:54:04.864","lat":29.69463965392643}},{"id":249884,"name":"Lakes of Bella Terra/Valencia","surveyStatus":{"territoryName":"Fulshear","dateTimeAdded":"2017-03-13 14:32:35.471","lng":-95.78839095318297,"userId":"6e77831f-9be5-41a4-8135-d961a94ef917","subdivisionId":"249884","surveyStatus":"2","territoryId":"4921","userName":"Michelle Artis","marketId":"13","subdivisionName":"Lakes of Bella Terra/Valencia","dateTimeUploaded":"2017-03-13 14:32:35.477","lat":29.69075137286418}},{"id":249885,"name":"Lakes of Bella Terra/Porte Toscana","surveyStatus":{"territoryName":"Fulshear","dateTimeAdded":"2017-03-13 14:10:33.875","lng":-95.79300477178376,"userId":"6e77831f-9be5-41a4-8135-d961a94ef917","subdivisionId":"249885","surveyStatus":"1","territoryId":"4921","userName":"Michelle Artis","marketId":"13","subdivisionName":"Lakes of Bella Terra/Porte Toscana","dateTimeUploaded":"2017-03-13 14:10:33.882","lat":29.68849873638683}},{"id":249920,"name":"Cross Creek Ranch/The Falls","surveyStatus":{"territoryName":"Fulshear","dateTimeAdded":"2017-03-14 15:07:57.054","lng":-95.86257892669724,"userId":"6e77831f-9be5-41a4-8135-d961a94ef917","subdivisionId":"249920","surveyStatus":"2","territoryId":"4921","userName":"Michelle Artis","marketId":"13","subdivisionName":"Cross Creek Ranch/The Falls","dateTimeUploaded":"2017-03-14 15:07:57.060","lat":29.73065241708395}},{"id":249941,"name":"Cross Creek Ranch/Heights","surveyStatus":{"territoryName":"Fulshear","dateTimeAdded":"2017-03-14 13:38:52.380","lng":-95.85420054392503,"userId":"6e77831f-9be5-41a4-8135-d961a94ef917","subdivisionId":"249941","surveyStatus":"2","territoryId":"4921","userName":"Michelle Artis","marketId":"13","subdivisionName":"Cross Creek Ranch/Heights","dateTimeUploaded":"2017-03-14 13:38:52.385","lat":29.71784273165252}}]


const sortSurveyStatusDate = (option, array) => {
  switch (option) {
    case 'dateTimeAdded':
      array.sort((a, b) => {
        a = new Date(a.surveyStatus.dateTimeAdded)
        b = new Date(b.surveyStatus.dateTimeAdded)
        return a > b ? -1 : a < b ? 1 : 0
      })
      break
    case '-dateTimeAdded':
      array.sort((a, b) => {
        a = new Date(a.surveyStatus.dateTimeAdded)
        b = new Date(b.surveyStatus.dateTimeAdded)
        return a < b ? -1 : a > b ? 1 : 0
      })
      break
  }
  return array
}

const sortSurveyStatus = (option, array) => {
  switch (option) {
    case 'complete':
      array.sort((a, b) => {
        return b.surveyStatus.surveyStatus > a.surveyStatus.surveyStatus
      })
      break
    case 'inProgress':
      array.sort((a, b) => {
        return a.surveyStatus.surveyStatus > b.surveyStatus.surveyStatus
      })
      break
    case 'notStarted':
      array.sort((a) => {
        return a.surveyStatus.surveyStatus === '0'
      })
      break
  }
  return array
}

const dateDesc = '-dateTimeAdded'
const dateAsc = 'dateTimeAdded'

const status_1 = '1'
const status_2 = '2'
const status_3 = '3'


// array = sortSurveyStatusDate(dateDesc, array)
// array = sortSurveyStatusDate(dateAsc, array)

// array = sortSurveyStatus(status_1, array)
// array = sortSurveyStatus(status_2, array)
// array = sortSurveyStatus(status_3, array)

   var html = "<table border='1|1'>";
    for (var i = 0; i < array.length; i++) {
        html+="<tr>";
        html+="<td>"+array[i].surveyStatus.subdivisionName+"</td>";
        html+="<td>"+array[i].surveyStatus.dateTimeAdded+"</td>";
        html+="<td>"+array[i].surveyStatus.surveyStatus+"</td>";
        
        html+="</tr>";

    }
    html+="</table>";
document.getElementById("box").innerHTML = html;
<div id= "box"></div>

I have an array of objects that I need to sort. There is two select boxes, one to sort by a Date(asc/desc) property and the other to sort by a "surveyStatus" property.

The date has the possible value of null or a dateTime stamp.

SurveyStatus has 3 possible values, 0,1,2.

The default sort order for the Survey Status is 1,2,0

texas697
  • 5,609
  • 16
  • 65
  • 131
  • 1
    Please update your question with a **runnable** [mcve] using Stack Snippets (the `[<>]` toolbar button), so that the full content of the question is here, on-site. – T.J. Crowder Mar 19 '17 at 21:22
  • In the code in the question, you have several `sort` callbacks returning booleans. `sort` expects its callback to return a negative number, zero, or a positive number -- as you do in `sortSurveyStatusDate`, but not in `sortSurveyStatus`. – T.J. Crowder Mar 19 '17 at 21:23
  • yes, I know it isnt correct I was just trying everything to see what I could understand is happening. I have never sorted an array by 3 possible values – texas697 Mar 19 '17 at 21:26
  • sort by date ok, but you mean sort or **filter** by status? – caub Mar 19 '17 at 21:32
  • sort, I want all the data to be on the screen – texas697 Mar 19 '17 at 21:33
  • what does it mean to sort by status 2? all with 2, then all 1, then all 3? – caub Mar 19 '17 at 21:34
  • Can I suggest, again, a **runnable** example with Stack Snippets? – T.J. Crowder Mar 19 '17 at 21:35
  • What is your question? What is the problem, what does not work? – Bergi Mar 19 '17 at 21:36
  • yes, sorry. 1 stands for "Complete". 2 stands for "In Progress" and "0" stands for "Not Started" – texas697 Mar 19 '17 at 21:36
  • Your [comparison functions are wrong](http://stackoverflow.com/q/24080785/1048572) – Bergi Mar 19 '17 at 21:36
  • @texas697I know, but how do you sort them?, how do you sort bananas, apple and oranges? – caub Mar 19 '17 at 21:37
  • @T.J.Crowder I have a runnable Fiddle? I also updated the post with the json and the code from the fiddle – texas697 Mar 19 '17 at 21:37
  • @caub ok my bad. by default the order would be Complete, InProgress, Not Started. When changing the order by status I havent really thought about the order in which it would change after the selected sort option. Doesnt really matter for now – texas697 Mar 19 '17 at 21:40
  • @texas697: Stack Overflow has its own runnable examples mechanism: Stack Snippets (the `[<>]` toolbar button). By making your runnable example **here, on-site**, you make it easier for people to see your problem and help you with it. The problem with off-site resources like jsFiddle, CodePen, etc., is that -- aside from being off-site and potentially disappearing -- people inevitably include information **only** in the off-site location. Stack Snippets are easily copied from question to answer to be modified to show how the answer works, etc. – T.J. Crowder Mar 19 '17 at 21:46
  • 1
    @T.J.Crowder ok now I know! will make sure to do that. – texas697 Mar 19 '17 at 21:48
  • I did that https://jsfiddle.net/crl/pupe0tfk/9/ – caub Mar 19 '17 at 21:56
  • @caub put in a answer! thanks – texas697 Mar 19 '17 at 21:58

2 Answers2

1

In general, sorting by multiple criteria is done like this:

theArray.sort(function(left, right) {
    var result = /*...compare first criterion*/;
    if (result == 0) {
        result = /*...compare second criterion*/;
        if (result == 0) {
            result = /*...compare third criterion*/;
            // ...and so on...
        }
    }
    return result;
});

...where "compare X criterion" results in a negative number if left should come before right, 0 if they're the same for that criterion, and a positive number if right should come before left.

That works because we only need to evaluate our second criterion if the entries are "the same" according to the first, only need to look at the third if the first and second are "the same," etc.

That's for a hardcoded series. It can easily be adapted for a series defined by an array of comparisons to make (using a loop that breaks when result is not 0).

Simple example of the hardcoded version:

var array = [
  {a: 4, b: 3, c: 5},
  {a: 1, b: 2, c: 7},
  {a: 4, b: 4, c: 4},
  {a: 4, b: 4, c: 2},
  {a: 4, b: 4, c: 6},
  {a: 2, b: 8, c: 9},
  {a: 2, b: 9, c: 8}
];
show("Unsorted", array);
array.sort(function(left, right) {
  var result = left.a - right.a;
  if (result == 0) {
    result = left.b - right.b;
    if (result == 0) {
      result = left.c - right.c;
    }
  }
  return result;
});
show("Sorted", array);

function show(label, a) {
  console.log(
    label,
    a.map(function(entry) {
      return "a:" + entry.a +
             ",b:" + entry.b +
             ",c:" + entry.c;
    })
  );
}
.as-console-wrapper {
  max-height: 100% !important;
}
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
1

You could define your compare functions in a separate object, and reference the one your need when you call sort:

Here is a snippet that does that:

const array = [{"id":248439,"name":"Cross Creek Ranch/Creek Cove","surveyStatus":{"territoryName":"Fulshear","subdivisionName":"Cross Creek Ranch/Creek Cove","subdivisionId":248439,"dateTimeAdded":null,"surveyStatus":"0"}},{"id":248545,"name":"Lakes of Bella Terra/Via Verdone","surveyStatus":{"territoryName":"Fulshear","subdivisionName":"Lakes of Bella Terra/Via Verdone","subdivisionId":248545,"dateTimeAdded":null,"surveyStatus":"0"}},{"id":248546,"name":"Lakes of Bella Terra/Via Moderna","surveyStatus":{"territoryName":"Fulshear","dateTimeAdded":"2017-03-13 14:24:24.312","lng":-95.78459389953542,"userId":"6e77831f-9be5-41a4-8135-d961a94ef917","subdivisionId":"248546","surveyStatus":"2","territoryId":"4921","userName":"Michelle Artis","marketId":"13","subdivisionName":"Lakes of Bella Terra/Via Moderna","dateTimeUploaded":"2017-03-13 14:24:24.316","lat":29.68844027643332}},{"id":248547,"name":"Lakes of Bella Terra/Via Privato","surveyStatus":{"territoryName":"Fulshear","subdivisionName":"Lakes of Bella Terra/Via Privato","subdivisionId":248547,"dateTimeAdded":null,"surveyStatus":"0"}},{"id":248548,"name":"Lakes of Bella Terra/Mirandola","surveyStatus":{"territoryName":"Fulshear","subdivisionName":"Lakes of Bella Terra/Mirandola","subdivisionId":248548,"dateTimeAdded":null,"surveyStatus":"0"}},{"id":248549,"name":"Lakes of Bella Terra/La Bella Cortile","surveyStatus":{"territoryName":"Fulshear","dateTimeAdded":"2017-03-13 14:38:22.958","lng":-95.78834879221002,"userId":"6e77831f-9be5-41a4-8135-d961a94ef917","subdivisionId":"248549","surveyStatus":"2","territoryId":"4921","userName":"Michelle Artis","marketId":"13","subdivisionName":"Lakes of Bella Terra/La Bella Cortile","dateTimeUploaded":"2017-03-13 14:38:22.964","lat":29.69532227612072}},{"id":248838,"name":"Cross Creek Ranch/Pond","surveyStatus":{"territoryName":"Fulshear","dateTimeAdded":"2017-03-14 12:12:20.408","lng":-95.8761960827707,"userId":"6e77831f-9be5-41a4-8135-d961a94ef917","subdivisionId":"248838","surveyStatus":"1","territoryId":"4921","userName":"Michelle Artis","marketId":"13","subdivisionName":"Cross Creek Ranch/Pond","dateTimeUploaded":"2017-03-14 12:12:20.416","lat":29.70182981810505}},{"id":249626,"name":"Cross Creek Ranch/Legacy-Herons Lake","surveyStatus":{"territoryName":"Fulshear","dateTimeAdded":"2017-03-14 13:11:24.276","lng":-95.8625899069904,"userId":"6e77831f-9be5-41a4-8135-d961a94ef917","subdivisionId":"249626","surveyStatus":"2","territoryId":"4921","userName":"Michelle Artis","marketId":"13","subdivisionName":"Cross Creek Ranch/Legacy-Herons Lake","dateTimeUploaded":"2017-03-14 13:11:24.282","lat":29.70904039221789}},{"id":249727,"name":"Fulshear Run","surveyStatus":{"territoryName":"Fulshear","dateTimeAdded":"2017-03-14 11:49:22.765","lng":-95.8850889467596,"userId":"6e77831f-9be5-41a4-8135-d961a94ef917","subdivisionId":"249727","surveyStatus":"2","territoryId":"4921","userName":"Michelle Artis","marketId":"13","subdivisionName":"Fulshear Run","dateTimeUploaded":"2017-03-14 11:49:22.772","lat":29.6824066434332}},{"id":249739,"name":"Lakes of Bella Terra/Cittanova","surveyStatus":{"territoryName":"Fulshear","dateTimeAdded":"2017-03-13 15:56:25.460","lng":-95.78473585666696,"userId":"6e77831f-9be5-41a4-8135-d961a94ef917","subdivisionId":"249739","surveyStatus":"2","territoryId":"4921","userName":"Michelle Artis","marketId":"13","subdivisionName":"Lakes of Bella Terra/Cittanova","dateTimeUploaded":"2017-03-13 15:56:25.467","lat":29.69387132677221}},{"id":249883,"name":"Lakes of Bella Terra/Vita Bella","surveyStatus":{"territoryName":"Fulshear","dateTimeAdded":"2017-03-13 15:54:04.856","lng":-95.78164947228113,"userId":"6e77831f-9be5-41a4-8135-d961a94ef917","subdivisionId":"249883","surveyStatus":"1","territoryId":"4921","userName":"Michelle Artis","marketId":"13","subdivisionName":"Lakes of Bella Terra/Vita Bella","dateTimeUploaded":"2017-03-13 15:54:04.864","lat":29.69463965392643}},{"id":249884,"name":"Lakes of Bella Terra/Valencia","surveyStatus":{"territoryName":"Fulshear","dateTimeAdded":"2017-03-13 14:32:35.471","lng":-95.78839095318297,"userId":"6e77831f-9be5-41a4-8135-d961a94ef917","subdivisionId":"249884","surveyStatus":"2","territoryId":"4921","userName":"Michelle Artis","marketId":"13","subdivisionName":"Lakes of Bella Terra/Valencia","dateTimeUploaded":"2017-03-13 14:32:35.477","lat":29.69075137286418}},{"id":249885,"name":"Lakes of Bella Terra/Porte Toscana","surveyStatus":{"territoryName":"Fulshear","dateTimeAdded":"2017-03-13 14:10:33.875","lng":-95.79300477178376,"userId":"6e77831f-9be5-41a4-8135-d961a94ef917","subdivisionId":"249885","surveyStatus":"1","territoryId":"4921","userName":"Michelle Artis","marketId":"13","subdivisionName":"Lakes of Bella Terra/Porte Toscana","dateTimeUploaded":"2017-03-13 14:10:33.882","lat":29.68849873638683}},{"id":249920,"name":"Cross Creek Ranch/The Falls","surveyStatus":{"territoryName":"Fulshear","dateTimeAdded":"2017-03-14 15:07:57.054","lng":-95.86257892669724,"userId":"6e77831f-9be5-41a4-8135-d961a94ef917","subdivisionId":"249920","surveyStatus":"2","territoryId":"4921","userName":"Michelle Artis","marketId":"13","subdivisionName":"Cross Creek Ranch/The Falls","dateTimeUploaded":"2017-03-14 15:07:57.060","lat":29.73065241708395}},{"id":249941,"name":"Cross Creek Ranch/Heights","surveyStatus":{"territoryName":"Fulshear","dateTimeAdded":"2017-03-14 13:38:52.380","lng":-95.85420054392503,"userId":"6e77831f-9be5-41a4-8135-d961a94ef917","subdivisionId":"249941","surveyStatus":"2","territoryId":"4921","userName":"Michelle Artis","marketId":"13","subdivisionName":"Cross Creek Ranch/Heights","dateTimeUploaded":"2017-03-14 13:38:52.385","lat":29.71784273165252}}];

const populate = (array) => {
    const rows = [];
    for (let i = 0; i < array.length; i++) {
        rows.push("<tr>",
                  "<td>",array[i].surveyStatus.subdivisionName,"</td>",
                  "<td>",array[i].surveyStatus.dateTimeAdded,"</td>",
                  "<td>",array[i].surveyStatus.surveyStatus,"</td>",
                  "</tr>");
    }
    document.getElementById("box").innerHTML = "<table border='1|1'>" +
        rows.join("") + "</table>";
}

const compare = {
    dateTimeAdded: (a, b) => // keep null at the end
        (Date.parse(a.surveyStatus.dateTimeAdded) || Infinity) - 
        (Date.parse(b.surveyStatus.dateTimeAdded) || Infinity),
    "-dateTimeAdded": (a, b) => // keep null at the end
        (Date.parse(b.surveyStatus.dateTimeAdded) || 0) - 
        (Date.parse(a.surveyStatus.dateTimeAdded) || 0),
    inProgress: (a, b) => b.surveyStatus.surveyStatus - a.surveyStatus.surveyStatus,
    notStarted: (a, b) => a.surveyStatus.surveyStatus - b.surveyStatus.surveyStatus,
    complete: (a, b) => // Give precedence to status 1
        (b.surveyStatus.surveyStatus + 1) % 3 - (a.surveyStatus.surveyStatus + 1) % 3,
};

const sortTable = (option, array) => populate(array.sort(compare[option]));

const sort = document.getElementById('sort');
sort.addEventListener('change', e => sortTable(sort.value, array) );
sortTable(sort.value, array); // sort table at page load
<select id="sort">
    <option value="complete">Sort Completed First</option>
    <option value="inProgress">Sort In-Progress First</option>
    <option value="notStarted">Sort Not-Started First</option>
    <option value="dateTimeAdded">Sort Added Asc</option>
    <option value="-dateTimeAdded">Sort Added Desc</option>
</select>
<div id= "box"></div>

Note that sort provides a stable sort in most browsers, meaning that if you first sort by date, and then by a status, the records will still be sorted by date within the same status group.

trincot
  • 317,000
  • 35
  • 244
  • 286