-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

17
  • 1
    Please update your question with a runnable minimal reproducible example using Stack Snippets (the [<>] toolbar button), so that the full content of the question is here, on-site. Commented Mar 19, 2017 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. Commented Mar 19, 2017 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 Commented Mar 19, 2017 at 21:26
  • sort by date ok, but you mean sort or filter by status? Commented Mar 19, 2017 at 21:32
  • 1
    @T.J.Crowder ok now I know! will make sure to do that. Commented Mar 19, 2017 at 21:48

2 Answers 2

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;
}

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

Comments

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.

Comments

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.