More struggling with JS: how the PHP -> JS interface is broken and why this is painful

Yesterday I was struggling with getting Vue components to do non-AJAXy things and wondering why on earth this was so difficult.

The conclusion I came to, with the help of some good people on Twitter, is that if you’re using a component-based reactive framework like Vue, you don’t want to be half-hearted about it. You need to go all in. They aren’t intended to be mashed up with traditional HTML page reloads.

So I then tried to work out how to use the Axios HTTP client library to do my delete action.

And was that easy?

Well…hmm….

The Axios/AJAX thing was actually pretty simple. I’ll give you that.

But I was then faced with the propsect of having to delete the thing from my list of things stored as data in the top-level component instance.

And the problem with this is that this data is a nested array that comes from PHP via JSON.

Now I know some people complain that PHP arrays are trying to be all things to all men, but from a developer happiness point of view they are pretty nice and I’ve got very used to their flexibility and ease of use.

But getting them from PHP into JS isn’t so simple.

In my case I have a list of things for each day of the week. But not every day needs a list. So I can have:

[
1 => [
'thing1',
'thing2'
],
3 => [
'thing3',
'thing4'
]
]

And I can have this in JavaScript too. Sort of.  JavaScript doesn’t like the gaps – note in the image below the empty slots and the length:

BUT…to get between PHP and JS we generally use JSON as a kind of intermediate format.

And JSON doesn’t have arrays with indexes. JSON arrays have no specific indices. They always start at zero and subsequent elements are indexed with the next integer.

So to get around this, PHP’s json_encode() function works out if the PHP array is compatible with JSON. If it is then it spits out a JSON array. And if it isn’t then it spits out a JSON OBJECT!

Here’s a valid JSON array – zero-indexed and all sequential keys:

> $a = [ 0 => 'a', 1 => 'b' ];
> echo json_encode( $a );
["a","b"]

Here’s a non-JSON compatible array:

> $b = [ 1 => 'a', 2 => 'b' ];
> echo json_encode( $b );
{"1":"a","2":"b"}

Fun! Now I note that you can add the JSON_FORCE_OBJECT flag to always convert PHP arrays to JSON objects, even if they are JSON-array compatible. But for the most part, you sometime get an array in JSON, and you sometimes get an object.

And my list of things, not being JSON-array compatible, was being spat out as an object.

And here’s my issue: JavaScript objects aren’t really iterable. You can’t easily loop over them. I mean, yes, you can get the keys, and you can use for...of or for...in or something. But sometimes you’ll get properties you don’t want (such as a Vue __ob__ observer property) and…well…objects just aren’t really intended to be used in this way. Objects are objects, not lists or arrays.

So what to do?

Well, I could use JSON_FORCE_OBJECT and treat ALL my arrays as objects and deal with it. That would probably be OK. But then I’m stuck using objects for lists of things in JS and that’s not right.

Or I could try to make all my PHP arrays JSON compatible. So my list would be zero-indexed and sequential, like this:

[
0 => [],
1 => [
'thing1',
'thing2'
],
2 => [],
3 => [
'thing3',
'thing4'
]
]

But enforcing this inside PHP doesn’t seem like the right thing to do.

Or I could try to find a way to convert JSON objects that only have numeric keys back into JS arrays. But that still has issues.

This, I think, is a major pain point and frustration for me.  Once my data is in the right places and in the right types of data structure, I know what I’m doing and can work quickly.

But moving data between the different parts of these multi-part systems is hard to get right. And doing it in a scalable and maintainable way is even harder.

Yesterday I also had problems with:

JavaScript scope

How how how How HOW do I pass a variable to a lexically-out-of-scope callback, like:

function deleteThingFromData( thingToDelete ) {
newData = _.mapValues( data, myOutOfScopeCallback );
data = newData;
}

function myOutOfScopeCallback( dataItem ) {
// Needs access to thingToDelete!
}

this

this is perpetually not my friend. Nothing in programming should be called this, especially when its meaning can vary so wildly.

Yesterday I got caught by the fact that this inside an arrow function is different to this with a normal function. 

#learnToLoveJs

For now, my delete now works (YAY!), and I’m still motivated to #learnToLoveJS, but gosh it’s hard work.