Dynamic JavaScript in MODX III

Putting JavaScript in a chunk with placeholders


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 putting the JavaScript code in a chunk.

MODX logo

Review

As we said in the previous articles, 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 build-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 needs 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.


Using a Chunk for JavaScript Code

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 put the JS code into the snippet itself. In this version, we're going to put the JavaScript in a chunk and have the snippet retrieve it and insert its code into the page. Instead of a PHP variable, we'll use a placeholder to hold the URL.

Our snippet tag on the MessageManager page looks like it did in the previous article, but with a property to specify the name of the chunk holding the JS code:

[[!MessageManagerJS? &jsChunk=`mmAjaxJs`]]

The Chunk

Here's the content of our chunk (we'll call it mmAjaxJs):

<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[[+html_file_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>

Notice the html_file_extension placeholder we'll use to set the extension at run-time.


$modx->getChunk()

If you call $modx->getChunk('chunkName'), you get the content of the chunk. If you call it with an associative array as the second argument, though, MODX will return the chunk with any placeholders specified in the second argument replaced by their values:

$fields = array(
    'placeholder1' => 'value 1',
    'placeholder2' => 'value 2',
);
$chunk = $modx->getChunk('SomeChunk', $fields);

In the code above, MODX will replace the two placeholders, [[+placeholder1]] and [[+placeholder2]], with the values on the right in the $fields array.

We'll use that method to set the extension on the value of the url variable in the JS code.


The MessageManagerJS Snippet

The first step in the snippet, getting the file extension is the same as it was in the previous article:

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

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

Next, we get the JS code and inject it into the page:

/* Create the array of fields for the placeholder */

$fields = array(
    'html_file_extension' => $extension,
);

/* Get the name of the chunk holding the JS code */
$jsChunk = $modx->getOption('jsChunk', $scriptProperties, 'mmAjaxJs', true);

/* Get the JS code with the placeholder replaced */
$jsCode = $modx->getChunk($jsChunk, $fields);

/* Inject the JS code into the page */
$modx->regClientStartupScript($jsCode);
return '';

The two parts above are the entire snippet. It's much more compact and easier to maintain than the one in the previous article.


Evaluation

I prefer this method over the one in the previous article. It still uses that actual content-type suffix for the extension, and it still puts all our JavaScript in one place. Unlike the previous solution, though, it separates the PHP code and the JS code, making both of them much easier to maintain.

There's still a problem, though, and I'm sure some of you have thought of it (and the best solution for it). It will break if the mm-ajax page is a container and the extension for containers is different than the HTML extension, or if the user is using friendly alias paths. We'll see the solution in the next (and final) article in this series.


Coming Up

In the next article, we'll ask MODX for the actual URL of the mm-ajax page and use that in our JS code.


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)