Reputation: 33
I have this legacy app which is 98% PHP with a smattering of JS. I'm trying to make it a little more dynamic and user-friendly by buffing up the JS, but I'm running into issues in how JS treats the data coming from PHP. It keeps trashing the sort order and I haven't been able to figure out how to stop/repair it. My PHP data is an associative array called $events
that looks like this:
Array
(
[4972] => Array
(
[event_id] => 4972
[event_name] => Setup
[event_start_date] => 2018-02-05 08:00:00
[event_end_date] => 2018-02-16 16:00:00
[event_parent] => 4972
[event_milestone] => 0
[event_dynamic] => 1
[event_order] => 1
[root_event] => 1
[child_count] => 3
[dep_start_date] => 2018-02-16 16:00:00
[child_event_1] => 4975
[child_event_2] => 4973
[child_event_3] => 4974
)
[4975] => Array
(
[event_id] => 4975
[event_name] => Seating
[event_start_date] => 2018-02-05 08:00:00
[event_end_date] => 2018-02-09 16:00:00
[event_parent] => 4972
[event_milestone] => 0
[event_dynamic] => 0
[event_order] => 2
[root_event] =>
[child_count] => 0
[dep_start_date] => 2018-02-09 16:00:00
)
[4973] => Array
(
[event_id] => 4973
[event_name] => Stage
[event_start_date] => 2018-02-12 08:00:00
[event_end_date] => 2018-02-14 16:00:00
[event_parent] => 4972
[event_milestone] => 0
[event_dynamic] => 0
[event_order] => 3
[root_event] =>
[child_count] => 0
[dep_start_date] => 2018-02-14 16:00:00
)
[4974] => Array
(
[event_id] => 4974
[event_name] => Refreshments
[event_start_date] => 2018-02-15 08:00:00
[event_end_date] => 2018-02-16 16:00:00
[event_parent] => 4972
[event_milestone] => 0
[event_dynamic] => 0
[event_order] => 4
[root_event] =>
[child_count] => 0
[dep_start_date] => 2018-02-16 16:00:00
)
[4896] => Array
(
[event_id] => 4896
[event_name] => Week 1
[event_start_date] => 2018-02-19 08:00:00
[event_end_date] => 2018-02-23 16:00:00
[event_parent] => 4896
[event_milestone] => 0
[event_dynamic] => 1
[event_order] => 5
[root_event] => 1
[child_count] => 2
[dep_start_date] => 2018-02-23 16:00:00
[child_event_1] => 4897
[child_event_2] => 4898
)
[4897] => Array
(
[event_id] => 4897
[event_name] => Session 1
[event_start_date] => 2018-02-19 08:00:00
[event_end_date] => 2018-02-21 16:00:00
[event_parent] => 4896
[event_milestone] => 0
[event_dynamic] => 0
[event_order] => 6
[root_event] =>
[child_count] => 0
[dep_start_date] => 2018-02-21 16:00:00
)
[4898] => Array
(
[event_id] => 4898
[event_name] => Session 2
[event_start_date] => 2018-02-22 08:00:00
[event_end_date] => 2018-02-23 16:00:00
[event_parent] => 4896
[event_milestone] => 0
[event_dynamic] => 0
[event_order] => 7
[root_event] =>
[child_count] => 0
[dep_start_date] => 2018-02-23 16:00:00
)
)
The data is used for a variety of functions, but it needs to stay in order because it is used to populate a option list. I prep it for JS with json_encode
like this.
$events = json_encode($events);
Then I toss that over the wall to JS with an echo
statement and json.parse
which makes a JS object.
var events = '<?php echo $events; ?>';
events = JSON.parse(events);
When I look at the data after the echo, it's still the same as the PHP version, but the order is changed after the parse. They appear to be ordered by event_id
, which is the key for the object. (I won't take up space by posting the data again. Suffice to say "Week 1" and it's children are first with "Setup" and it's children following. I will post the data if asked.)
I know that JS objects don't really have an order, so I found several answers here that said it needed to be in an array to maintain the order, so I tried this:
var events = [<?php echo $events; ?>];
and then this:
var events = '<?php echo $events; ?>';
events = [events];
events = JSON.parse(events);
neither of which made any difference at all. The sorting was still trashed. So I tried sorting it after the parse. I added values to the event_order
field to work with. I read and tried several different versions of this ranging from the simple:
events.sort((a, b) => a.event_order - b.event_order);
to the more complex:
var sort = function (prop, arr) {
prop = prop.split('.');
var len = prop.length;
arr.sort(function (a, b) {
var i = 0;
while( i < len ) { a = a[prop[i]]; b = b[prop[i]]; i++; }
if (a < b) {
return -1;
} else if (a > b) {
return 1;
} else {
return 0;
}
});
return arr;
};
sort('events.event_order', events);
which didn't change anything either. So I tried writing it to a new, supposedly sorted, object with this:
var events_sorted = {};
Object
.keys(events).sort(function(a, b){
return events[a].event_order - events[b].event_order;
})
.forEach(function(key) {
events_sorted[key] = events[key];
});
The new object was mangled too.
I've run out of ideas and tried so many things that I'm losing track of what I did and didn't do. I feel like I'm either doing something fundamentally wrong or I'm missing some small detail that's derailing me. Hoping someone can help. Thanks.
Upvotes: 2
Views: 64
Reputation: 522076
var events = <?php echo json_encode(array_values($events)); ?>;
This is all you need.
json_encode
already produces a valid Javascript literal, just use that directly; there's no need to make that into a string which you parse again. In fact you'll get into a lot of headaches with quotes if your data contains quotes.
It's simply not possible to translate that PHP data structure into an equivalent Javascript data structure. PHP arrays are both associative and ordered, while in Javascript you can either have ordered data structures (arrays) or associative data structures (objects), but not both.
The above creates a Javascript array which preserves the order of your events. You're also not losing any information by discarding the keys, since they seem to be identical with the embedded event_id
property anyway. The only thing is that you cannot access your events by key in Javascript now (e.g. events[4972]
), but this is a fact you need to wrangle with in Javascript anyway since, again, you can't have it both ordered and keyed at the same time.
Upvotes: 2