John the Painter
John the Painter

Reputation: 2615

AJAX and head/foot updates best practice

A standard setup for me is to have a head.inc and a foot.inc and then everything in-between is updated via AJAX calls with some transition. Getting a bit boring but that's currently how it is. The issue I have is most of the time the main site nav/menu, which is in the head.inc, is contextual and will change based on the page being view. This can cause a lot of duplication of code as 1) I write it with PW in PHP so if the page is visited directly it is reflected and 2) I also have to do the same in JS if the page is visited via an AJAX call. You see the dilemma.

What I've started to do recently is build a PHP array in an include file for the menu, and also json_encode it so I have an array, of the same code, one for PHP to use and one for the JS to use. Something like the below...

$menuArray = array();

$menuLeft = $pages->find("template=work|news, sort=sort");
$menuRight = $pages->find("template=clients|about, sort=sort");

if ($page->id !== 1) {
    $menuLeft->filter("id={$page->id}");
    $menuRight->filter("id={$page->id}");
}

foreach ($menuLeft as $item) {

    $menuArray['left'][] = array(
        'id' => $item->id,
        'name' => $item->name,
        'url' => $item->url,
        'title' => $item->title,
        'x' => '100%'
    );

    // If current page then prepend 'Close'
    if ($page->template->name == $item->name) {
        array_push($menuArray['left'], array(
            'name' => 'close',
            'url' => $pages->get(1)->url,
            'title' => 'Close',
            'x' => '100%'
        ));
    }

}

foreach ($menuRight as $item) {

    $menuArray['right'][] = array(
        'id' => $item->id,
        'name' => $item->name,
        'url' => $item->url,
        'title' => $item->title,
        'x' => '100%'
    );

    // If current page then append 'Close'
    if ($page->template->name == $item->name) {
        array_unshift($menuArray['right'], array(
            'name' => 'close',
            'url' => $pages->get(1)->url,
            'title' => 'Close',
            'x' => '100%'
        ));
    }

}

// Return JSON for JS (PHP can grab $menuArray directly)
$menuJSON = json_encode($menuArray);

if ($config->ajax) {
    echo '<script id="menuJSON">';
        echo "menuJSON = {$menuJSON}";
    echo '</script>';
}

Then in the head.inc loop through $menuArray and in the JS loop through, on AJAX changes, menuJSON.

updateMenu: function(e) {

    var $header = document.querySelector('header.main'),
        headerContent = '';

    for (var menu in menuJSON) {
        headerContent += '<ul class="menu --' + menu + '">';
        menuJSON[menu].forEach(function(item) {
            headerContent += '<li data-template-name="' + item.name + '"><a data-ajax data-x="' + item.x + '>" href="' + item.url + '">' + item.title + '</a></li>';
        });
        headerContent += '</ul>';
    }
    $header.innerHTML = headerContent;

}

The issue I'm having is I have no idea if this is the best way to work with something like this and wondered if anyone had any input?

It also feels weird echo'ing out script tag with PHP then relying on the JS finding it in the DOM. You know?

Anyway... I'll put this out there and see what happens 🙂

Upvotes: 7

Views: 226

Answers (2)

RMorrisey
RMorrisey

Reputation: 7739

I would say that modern best practice is to render JSON data from the server, then use a single-page app (SPA) or templating framework to update the page.

For example, implementing this type of solution using an SPA framework has the following advantages:

  • Eliminate security (injection/XSS) vulnerabilities that come from adding HTML strings together [https://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project]
  • Use built-in features to loop over data and generate HTML with little code
  • Reduce "flashing" reload behavior on the page
  • Replace sections of the page using a router, and make the page bookmarkable
  • Unit test everything
  • Build reusable UI components

I personally recommend Angular: [https://angular.io/]

If you don't like Angular in particular, there are numerous other UI frameworks out there with similar features. If you're working on a project that has reusable parts like you described, it's worth taking the time to learn about software libraries that can help you.

I don't know if this is the type of answer you're looking for, but I hope you find it useful and interesting.

Upvotes: 0

hatirlatici
hatirlatici

Reputation: 1695

Not sure what exactly you mean when you say "dynamic content" I would definitely go for RESTFull methods. If you give more details for types (like textual statics, video or images, etc.) I'd think of more details. Let's assume that you have dynamic content of a page which has only texts.

Let's assume a user visits the page which it's url is "/page/1" and a user logged in with some kind of authentication.

You could have another restful api end point and it will take two parameters( can have more than that, for the sake of simplicity I hold it to 2) to populate your head and footer include files with what ever you wanted to return. Let's call your api end point for this time "/populateHeadAndFooter". You can pass "1" for page, "{{token}}" for token parameters. It's possible to whatever you do with those parameter to evaluate the situation and prepare the response. If you need more details for the page "1", like user inputs or whatever an action will be taken, you can have a mechanism to pass it as parameter, directly or after converting it to other formats (hashing, encoding, etc.). After that you could have AJAX to refresh your actual page.

Upvotes: 3

Related Questions