Updating Manager Pages in a Plugin III

Using onClick vs addEventListener to make screen buttons execute JavaScript functions

This is the third in a series of articles on dealing with issues created by operations performed in plugins that work on the Create/Edit Resource Panel in the MODX Manager. In the previous article, we saw how to place extra buttons on the Create/Edit Resource panel, but the buttons didn't do anything. In this one, we'll look at how to provide an action that is performed when a button is clicked.

MODX logo

Alternate Methods

To providing an action for the buttons, we need to add a JavaScript function to perform the action and connect it to the button click. There are a number of ways to do this. We'll look at a couple of common ones. The use of these two techniques is hotly debated and we'll discuss some of the issues involved. First, we'll look at the method I used in StageCoach: adding an onClick() statement to the button tag. Next, we'll look at another method that many people feel should always be used: registering the a click event listener with JavaScript's addEventListener() method. We'll discuss the merits of the two methods at the end of the article.

Using onclick()

The first method is the simplest. You just add onClick="functionName()" to the HTML code of the button, and provide a matching JavaScript function. When the button is clicked, the function executes. This is the same code from the previous article, with the addition of the two onClick() functions:

$scId = $resource->getTVValue('StagedResourceId');

$button_script = <<<SCSCRIPT
Ext.onReady(function () {
    var buttonDiv = document.getElementById('modx-action-buttons');
    var buttonRows = hostdiv.getElementsByClassName("x-toolbar-left-row");

    /* Inject Edit Draft button */
    var row = buttonRows[0];
    var deleteDraftButton = row.insertCell(0);

    /* Inject Edit Draft button */
    var row = buttonRows[0];
    var editDraftButton = row.insertCell(0);
    editDraftButton.innerHtml =
        '<span id="stagecoach_edit_draft_button" class="x-btn x-btn-small stagecoach-link">
            <button onclick="stagecoachEditDraft()">Edit Draft</button>

    /* Inject Delete Draft button */
    row = buttonRows[0];
    var deleteDraftButton = row.insertCell(0);
    deleteDraftButton.innerHtml =
        '<span id="stagecoach_delete_draft_button" class="x-btn x-btn-small stagecoach-link">
            <button onclick="stagecoachDeleteDraft()">Edit Draft</button>


function stagecoachEditDraft() {
    alert("Delete Draft Button was clicked");

function stagecoachDeleteDraft() {
    alert("Delete Draft Button was clicked");


Note that this code is incomplete for our use case because we need to pass information to the functions so they know where to send the user and which resource to delete. They will work, however, to display a popup indicating which button was clicked. This is a good technique for development because it's no use trying to make the functions work if they're not being called correctly and testing them in this form is much simpler.

Where Does the Code Go?

The code above goes in a plugin attached to OnDocFormRender inside a section like this:

switch($modx->event->name) {
    case 'OnDocFormRender':
      /* Code above */

Using addEventListener

Many purists argue that you should never add an onClick() function (often referred to as an "inline event") to your HTML code. You can examine the various arguments here, though I'll discuss some of the issues later in this article. For now, we'll look at how to make our buttons work without an onClick() in the HTML. The trick is to use JavaScript's addEventListener() in the JavaScript code. This will bind a function to the event of an element.

To use addEventListener, you'd go back to our original code (without the onclick() )) and do something like this in the JS code:

document.getElementById("stagecoach_edit_draft_button").addEventListener("click", function(){
    alert("Edit draft button was clicked");

The code above tells JavaScript to find the element with the ID stagecoach_edit_draft_button and add an event listener to it that will execute the function, which will execute whenever the element is clicked on. Notice that the function itself is actually the second argument to addEventListener().

Which Technique to Use

Using addEventListener has several advantages. For one thing, you can attach a number of different event listeners to a single button, though it can be a little tricky to make sure they execute in the correct order. Many people consider using addEventListener to be a "cleaner" method, though I don't agree. Using addEventListener allows you to control whether the event is triggered during the "capture" or "bubbling" phase of JS execution (a discussion far beyond the scope of this article), and it also allows you to separate the HTML structure of the document from the logic of the JavaScript code.

For our use case, we'll never attach another event to any of our buttons. We won't worry about separating structure and logic because we're already mixing HTML, PHP, and JavaScript in order to alter a Manager page. The most important reason to use onClick here, though, is that we need to pass dynamic variables to each function. The JavaScript functions that delete a resource or forward the user to another page will perform very different actions depending on what resource you're editing. If we click on the Delete Draft button, the function needs to delete the draft for the current page. It won't know which page that is unless we send it the information.

In theory, since we're creating all the JS code in the plugin, we could inject the variable values into the functions themselves, but it would be quite ugly (much uglier than using onClick, and it would make our code almost impossible to follow for people reading it (including me). More than once, I've spent a fair amount of time trying to figure out how my own code works when updating an extra I haven't looked at for several years. I've learned that making your code easy to follow is often more important than making it theoretically correct. With addEventListener, looking at the button code tells you nothing about what happens when it's clicked or what information it uses to perform its action. It just a regular HTML button as far as the HTML code indicates. It could take a fair amount of searching to find the code that adds the event listener to that particular button. If there's an inline onClick function, though, looking at its HTML code tells you the name of the JavaScript function being called, and lets you see the arguments being passed to that function.

Coming Up

The code above, placed in a plugin attached to OnDocFormRender will add the buttons to the Create/Edit Resource panel and popup an alert when they're clicked, but the buttons don't actually do anything useful. We'll look at how to make them functional in the next few articles.

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.