I’ll admit it, I was a little afraid of AngularJS at first. I had seen other frameworks that were similar and immediately discounted this as “just another JavaScript framework” — until I used it. In those short moments I discovered that AngularJS is magical, and that I must use it for all new projects!
New projects? Right… like any of us have the time for new things, when we have these heaps of old applications we are in charge of maintaining. However, if we could use AngularJS for new work, and migrate the old, Yes! This sounded like a plan.
The Journey
And so it began. I had a legacy-ish application (written using mainly jQuery) that I wanted to update to the new hotness, so I started diving in. I learned about how Angular works, with the controllers, attaching them to the DOM, using loops, using models, services, i.e., all the JavaScript stuff you need to know to use Angular. The problem was that my app had been written in PHP to rely on jQuery, and things behaved just a little bit differently between pure jQuery and AngularJS.
The Background
The app I was migrating wasn’t super old by any means. It was a single page app utilizing jQuery calls like:
$.get();
$.post();
$("#container").load(<url>);
Replacing the .load calls were pretty easy. This is almost a direct replacement for how AngularJS binds to DOM elements. Instead of the jQuery call to the server to get the HTML for the container, AngularJS now calls home to get a JSON object that represents the data, and places it into the proper spots in the HTML template (lots of info online about how it works).
However, getting the data and replacing the $.get() and $.post() functions would prove to be a bit more difficult. AngularJS has its own flavors of these functions: $html.get() and $html.post(). While both are called in a similar manner to the jQuery equivalents, they behave much differently. Also, if you don’t use AngularJS’s functions, it kind of breaks the magic of updating the DOM. You can get around it, but why hack a good thing?
The Problem
When you use $.get() and $.post(), the data that is sent is packaged up nice and neat in GET and POST variables. PHP gladly exposes those for you to consume, and that’s how most apps are written (including my legacy app). With AngularJS, the POST variables are converted to a JSON object, and just sent over in the body — which thoroughly confuses PHP. There aren’t any POST vars, and the application endpoint expecting them fails… fails pretty hard.
At first I didn’t realize what was going on, but once I did, I found a rather clever fix (to avoid massive refactors).
The Fix
The fix is pretty straight forward if you’ve got a proper Object Oriented application. The idea is that you need to hook in somewhere above all of your calls and place a bit of code to rework things that AngularJS posts to what your application is expecting. Once you’ve found the ideal spot, plop this in:
//add support for angularJS posting of JSON
if ($_SERVER["REQUEST_METHOD"] == "POST" && empty($_POST)){
$decoded = json_decode(file_get_contents('php://input'), true);
if($decoded != null){
$_POST = $decoded;
}
}
What this code does is checks to see if the current request is a POST, and if there is no $_POST data (there won’t be with AngularJS calls), decode the message body and assign it to the $_POST variable if it decoded.
With this, you should be able to treat your legacy app as an API and start converting things over piece by piece with no fear of breaking anything.