myol
myol

Reputation: 9828

Running PHP within angular

I am using angular to create page transitions in a wordpress site. My site loads a normal wordpress page which fires its PHP and populates the page with angular elements (the body). The angular elements then use animated transitions to change the body content with 3 separate html pages (so header and footer are unaffected.)

I have PHP in the separate html pages. I thought the PHP would trigger before each page came into view - but im guessing because the pages are being loaded by angular and not the browser, this doesn't happen?

<div id="pageone">
    <p>This is page 1.</p>
    <a href="#page2">Go to page 2 </a><br>

    <?php echo ('this php does not work'); ?>

    <p>This html is below php</p>
</div>

Although I use pages, the same concept applies to divs being brought into view. Is there anyway to fire PHP using angular after the initial page load? Is this possible at all?

Upvotes: 1

Views: 17165

Answers (2)

Nik Dow
Nik Dow

Reputation: 614

We use index.php as the starting point, with angular.json (i've omitted irrelevent bits)

"projects": {
    "angular": {
      "architect": {
        "build": {
          "options": {
            "outputPath": "dist",
            "index": "src/index.php",

Prior to ng 12 this worked fine but ng 12 started commenting out the PHP code, until we used:

"optimization": {
              "fonts": true,
              "scripts": true,
              "styles": {
                "inlineCritical": false,
                "minify": true
              }
            },

The reason we run PHP code is to preload data, based on the angular route, to save one round-trip back to the server to get the data. To explain further, normal latency in loading an angular page has these consecutive stages:

  1. load index.html (network latency)
  2. load JS files (network latency)
  3. JS loads data to display the page (network and API latency). By preloading the data, we eliminate the network latency from 3. and the API calls are processed during step 1, while loading index.php.

There is a bit more to this, our Apache Virtual Server does a URL rewrite using (I've omitted some bits to keep this simple)

RewriteCond %{DOCUMENT_ROOT}/yii2/web/angular/dist/$1 -f
RewriteRule ^/app/(.*)$ /yii2/web/angular/dist/$1 [L]
RewriteRule ^/app/(.*)$ /yii2/web/angular/dist/index.php?pathroute=$1 [L]

When index.php runs it recovers the pathroute from the queryString and uses it to set up the preloading of data. The browser URL remains unchanged (this is not a 301 redirect, it's an internal URL rewrite).

If you access this page via the angular router from elsewhere in the app, the module lazy loads and the JS runs the API calls since the data is not preloaded.

As a result we have lightening fast loading of deep links.

The preloaded data plays in with our state manager that caches data from API calls, so the application code doesn't know where the data came from. The preload looks like this:

<script type="text/javascript">
    _preload = {"params":{"accessLevel":"P","releasetag":"NDOW-BLD6BA/release20211001_BLD6BA_1","user":{"isAuthenticated":false,"updatei...

Upvotes: 1

Jeff Lambert
Jeff Lambert

Reputation: 24661

AngularJS is completely client side. You can put PHP in your HTML templates, but if you don't configure your webserver to parse HTML files as PHP then your PHP isn't even going to be parsed.

Even if it did, AngularJS caches these templates so it will only be 'run' on the server a single time. This means if the template in question is swapped out, then data changes on the server that the template makes use of and then it is swapped back in again, the updates to the data are not going to be reflected in the template because there's absolutely zero knowledge on Angular's side of these updates occurring.

A good idea like @Jonast92 says in his comment is to try not to mix client-side and server-side concerns and enforce a strict separation between them. Use Angular models in your angular application's templates. Instead of something like:

<p><?php echo $item->description; ?></p>

Use an angular model:

<p>{{ item.description }}</p>

If you need data from the server in order to do this, make an Angular service to go out and get it for you:

angular.module('app').controller('controller', [
    '$scope', 'ItemManager',
    function($scope, ItemManager) {
        $scope.item = null;

        ItemManager.getItem('item-id').then(
            function(item)  {
                $scope.item = item;
            }, function() {
                console.log('load item failed');
            }
        );
    }
]);

angular.module('app').service('ItemManager', [
    '$http', '$q',
    function($http, $q) {
        var svc = {
            getItem: getItem
        };

        return svc;

        function getItem(id) {
             var defer = $q.defer();
             $http.get('/items/' + id)
                 .success(function(data) {
                     defer.resolve(data);
                 })
                 .error(function() {
                     defer.reject();
                 })
             ;

             return defer.promise;
        }
    }
]);

Upvotes: 6

Related Questions