Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preserve JSON arrays while sorting

I have two JSON arrays coming from an external website. I sort and merge the two arrays, decode them and then sort them from highest to lowest by ID.

Currently, when the option 'alphabetical' is clicked, ?sort=alphabetical is added onto the end of the URL and when the page has finished reloading, the JSON arrays are once again decoded and merged.

This is not my desired outcome: I do not want the JSON arrays to be decoded and merged again when the option is clicked - I simply want the already decoded and merged JSON arrays to be sorted alphabetically.


Arrays:

$homepage = array();  

$homepage[]= '{  
   "info":{  
      "collection":[  
         {  
            "Name":"Charlie",
            "ID":"7"
         },
         {  
            "Name":"Emma",
            "ID":"9"
         }
      ]
   }
}';  

$homepage[] = '{  
   "info":{  
      "collection":[  
         {  
            "Name":"Bob",
            "ID":"5"
         }
      ]
   }
}';

Sorting:

$data = array();
foreach ($homepage as $homepage2) {
    $tmp=json_decode($homepage2, false);
    $data = array_merge($data,$tmp->info->collection);
}

if(!empty($_GET['sort']) && $_GET['sort'] == 'alphabetical') {
    usort($data, function ($a, $b) {
        return strcmp($a->Name, $b->Name);
    });
}else{
    usort($data, function ($a, $b) {
        return $b->ID - $a->ID;
    });
}

echo'
<select onchange="location.href = this.value;">
    <option value="example.php?sort=alphabetical">Alphabetical</option>
</select>
';

foreach($data as $key) {
    echo'
    <a href="test.com">
    <p>'.$key->ID.'</p>
    <p>'.$key->Name.'</p>
    </a>
    ';
}  
like image 960
The Codesee Avatar asked Jun 16 '16 15:06

The Codesee


Video Answer


1 Answers

You could use JavaScript for doing the sorting on click, and use PHP only for passing the JSON to it.

After you provided the HTML structure you want to display the list in, I updated this answer to use div elements for the records and p elements for the fields.

We could replace the select list, for selecting the sort order, by two buttons.

Here is the PHP code:

<?php

$homepage = array();  

$homepage[]= '{  
   "info":{  
      "collection":[  
         {  
            "Name":"Charlie",
            "ID":"13"
         },
         {  
            "Name":"Emma",
            "ID":"9"
         }
      ]
   }
}';  

$homepage[] = '{  
   "info":{  
      "collection":[  
         {  
            "Name":"Bob",
            "ID":"10"
         }
      ]
   }
}';

$data = array();
foreach ($homepage as $homepage2) {
    $tmp=json_decode($homepage2, false);
    $data = array_merge($data,$tmp->info->collection);
}

?>

<div id="container"></div>

<button id="sort1">Alphabetical</button>
<button id="sort2">High to Low</button>

<script>
    var collection = <?=json_encode($data)?>;

    function populate(compareFunc) {
        collection.sort(compareFunc);
        var container = document.getElementById('container');
        container.innerHTML = '';
        collection.forEach(function (key) {
            var div = document.createElement("div");
            div.className = "inventory";
            var span = document.createElement("span");
            span.textContent = key.ID;
            div.appendChild(span);
            span = document.createElement("span");
            span.textContent = key.Name;
            div.appendChild(span);
            container.appendChild(div);
        });
    }

    var populateById = populate.bind(null, function (a, b) {
        return a.ID - b.ID;
    });

    var populateByName = populate.bind(null, function (a, b) {
        return a.Name.localeCompare(b.Name);
    });

    document.getElementById("sort1").addEventListener('click', populateByName);
    document.getElementById("sort2").addEventListener('click', populateById);
    document.addEventListener('DOMContentLoaded', populateById);

</script>

For the sample data this will result in the following JavaScript/HTML, which you can test here:

var collection = [{"Name":"Charlie","ID":"13"},{"Name":"Emma","ID":"9"},{"Name":"Bob","ID":"10"}];

function populate(compareFunc) {
    collection.sort(compareFunc);
    var container = document.getElementById('container');
    container.innerHTML = '';
    collection.forEach(function (key) {
        var div = document.createElement("div");
        div.className = "inventory";
        var span = document.createElement("span");
        span.textContent = key.ID;
        div.appendChild(span);
        span = document.createElement("span");
        span.textContent = key.Name;
        div.appendChild(span);
        container.appendChild(div);
    });
}

var populateById = populate.bind(null, function (a, b) {
    return a.ID - b.ID;
});

var populateByName = populate.bind(null, function (a, b) {
    return a.Name.localeCompare(b.Name);
});

document.getElementById("sort1").addEventListener('click', populateByName);
document.getElementById("sort2").addEventListener('click', populateById);
document.addEventListener('DOMContentLoaded', populateById);
span { margin-left: 5px }
div.inventory { border-bottom: 1px solid gray }
<div id="container"></div>

<button id="sort1">Alphabetical</button>
<button id="sort2">High to Low</button>

Note that I gave the three items different ID values than in your question, since otherwise the sort order would be the same for both ID and Name.

Using tables: alternative

There are nice JavaScript libraries which give much more features to represent data sets. Here is an example using jQuery with DataTables:

var collection = [{"Name":"Charlie","ID":"13"},{"Name":"Emma","ID":"9"},{"Name":"Bob","ID":"5"}];

function populate() {
  var tbody = $('#collection>tbody');
  collection.forEach(function (key) {
    var row = $('<tr>');
    row.append($('<td>').text(key.ID));
    row.append($('<td>').text(key.Name));
    tbody.append(row);
  });
}

$(document).ready(function(){
  populate();
  $('#collection').DataTable();
});
<script src="http://code.jquery.com/jquery-1.12.3.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.12/css/jquery.dataTables.min.css">
<script src="https://cdn.datatables.net/1.10.12/js/jquery.dataTables.min.js"></script>

<table id="collection">
    <thead>
        <tr><th>ID</th><th>Name</th></tr>
    </thead>
    <tbody/>
</table>

The actual code is even smaller (not counting the included library) than a pure JavaScript solution would be with a basic table. But this has sorting up and down, filtering, pagination, nice styles, ...

like image 90
trincot Avatar answered Sep 24 '22 16:09

trincot