Dynamic JavaScript in MODX II

Creating JavaScript in PHP and injecting it into a page


In this short series of articles, we're looking at some ways to use dynamic JavaScript in MODX. See the previous article for a discussion of what we mean by "dynamic JavaScript. In this one, we'll see a better method that involves dynamically creating the JavaScript (JS) code in a snippet.

MODX logo

Review

As we said in the last article, the need for Dynamic JavaScript arises from the fact that the JavaScript code is executing locally on the user's browser (client-side) and the MODX snippet or plugin is executing on the server (server-side). At run-time, there's no way for the two to communicate without creating and handling an Ajax call to a processor that provides the information the JS code needs. Out use case here is fixing a bug in the MessageManager Extra. MessageManager provides the same services as the messaging system in the MODX Manager, but in the front end.

The MessageManager JavaScript code contained this line in an Ajax call to a connector resource that calls various processors:

url: "mm-ajax.html",

This code is part of a JS function that launches a resource with the alias, mm-ajax, containing a snippet that serves as a connector to perform various actions by calling one of several MODX built-in processors and return their results. Depending on the action specified in the JS call, the snippet returns a list of user messages, a list of users, or a list of user groups. It also handles creating new messages, marking messages as read or unread, and deleting single messages or groups of messages.

The problem is with the .html part. One of the users of MessageManager changed the HTML Content Type so that the "file extensions" field was / instead of .html. The URL in the JS code was no long valid and the page containing the connector snippet was not found.

Obviously, the URL in the JS function needed to change based on the file_extensions field of the HTML Content Type, but how? The JavaScript code has no direct access to the information held on the server. We could use Ajax to call another processor first that returned the correct location of the mm-ajax resource, but that's ridiculously inefficient.


Detecting the File Extension

As we did in the previous article, we put a snippet on the MessageManager page that inserts the appropriate JavaScript code into the head section of the page. In the previous article, we had two separate JS files. In this version, there is no JS file at all. Instead, we create the JavaScript ourselves in the snippet and insert its code into the page.

Our snippet tag now looks like this (no need for properties since we're doing all the work in the snippet):

The first step in the snippet is to get the file extension:

/* Get the Content Type object */
$contentType = $modx->getObject('modContentType', array('mime_type' => 'text/html'));

/* Get the file extension */
$extension = $contentType->get('file_extensions');

The next step is to create the JS code. The actual code is much longer. I'm only showing the part that's relevant to this solution. Here's the original code:

function mmAjax(id, action, dataIn) {
    dataIn = dataIn || {};
    dataIn['id'] = id;
    dataIn['action'] = action;

    /* Ajax call to action; calls MODX resource pseudo-connector */
    return $.ajax({
        type: "POST",
        url: "mm-ajax.html",
        data: dataIn,
        dataType: "json"

    }).done(function () {
        mmSpinner.stop();
    }).fail(function (jqXHR, textStatus) {
        mmSpinner.stop();
        pop.setText(action + ' failed on message ' + id + ' ' + textStatus);
        pop.load(40);
    });
}

Here's the code as it appears in our snippet using the heredoc syntax we saw in earlier articles:

$script = <<<EOT
<script type="text/javascript">
function mmAjax(id, action, dataIn) {
    dataIn = dataIn || {};
    dataIn['id'] = id;
    dataIn['action'] = action;

    /* Ajax call to action; calls MODX resource pseudo-connector */
    return $.ajax({
        type: "POST",
        url: "mm-ajax{$extension}",
        data: dataIn,
        dataType: "json"

    }).done(function () {
        mmSpinner.stop();
    }).fail(function (jqXHR, textStatus) {
        mmSpinner.stop();
        pop.setText(action + ' failed on message ' + id + ' ' + textStatus);
        pop.load(40);
    });
}
</script>
EOT;

$modx->regClientStartupScript($script);

Notice that the only line we've changed is the one with the URL. It now uses the $extension variable to specify the extension.


Evaluation

This is definitely an improvement over the solutions in the previous article. It uses the actual content-type suffix for the extension, and it puts all our JavaScript in one place. One drawback, though, is that you need to edit the snippet to make any changes to the JS code, and introducing a PHP syntax error can break, not just the JavaScript, but the whole snippet. If the JS code is extensive, it will also make your snippet code quite long, making it more difficult to maintain. In the next article, we'll look at a method that solves both those problems.


Coming Up

In the next article, we'll solve the problem in another, slightly more elegant way, by putting the JavaScript code in a chunk.


Looking for high-quality, MODX-friendly hosting? As of May 2016, Bob's Guides is hosted at A2 hosting. (More information in the box below.)



Comments (0)


Please login to comment.

  (Login)