2
\$\begingroup\$

Purpose:

I wanted a way to improve event clarity and event code organization. I observed that every single event flow went through the following steps:

  • Trigger -> UI Change -> (Async) Action -> UI Change

Here is a JSFiddle.

Notes & Concerns

  • Something about the name of the class seems bad, but I can't come up with something better.
  • Are there ways to make the usage more clear to someone who didn't write the class?
  • Is there a way to make it where the user doesn't have to call the callback function in preAction and action and not have them fire before the user's function has completed?

Class Definition: UIEvent

// PURPOSE: 
//  I wanted a way to improve event clarity and event code organization.
//  I observed that every single event flow went through the following steps:
//      Trigger -> UI Change -> (Async) Action -> UI Change
// EXAMPLES:
//  Add button Click -> Disable add button -> Add new row -> Enable add button
//  Save button click -> Disable save button -> Save row -> Replace row
//  Edit button click -> Change button visibility -> Enable Controls -> Do Nothing.
// PARAMETERS:
//  This function takes an object of settings with the following fields.
//  'eventElement': 
//      A function for selecting the element that will trigger the event from the container element provided to the Initialize() function.
//      e.g. (container) => container.querySelector(".some-class")
//  'eventType':
//      The event triggered by the element above.
//      e.g. "click", "change", etc.
//  'preAction': 
//      A function that is fired when the event in triggered.
//      Has the parameters (e, callback) where e is the eventArgs from the original event and callback is the function to be called when this function has completed.
//      Remember to call the 'callback' when done or the 'action' and 'postAction' won't be called.
//  'action': 
//      A function that is fired after the preAction has completed.
//      Has the parameters (e, callback) where e is the eventArgs from the original event and callback is the function to be called when this function has completed.
//      Remember to call the 'callback' when done or the 'postAction' won't be called.
//  'postAction': 
//      A function that is fired after the action has completed.
//      Has the parameter (e) which is the eventArgs of the original event.
// INITIALIZTION:
//  The Initialize(container) function sets up the event listener on the 'eventElement' given a container.
//  If no container is provided, it will default to document.
function UIEvent(settings) {

    var thisUIEvent = this;

    this.GetElement = (container) => settings.eventElement(container);
    this.EventType = settings.eventType;

    // Executed before the 'Action'.
    // If you provide your own event handler you must call the 'callback' function when done.
    this.PreAction = function (e) {

        if (settings.preAction) {
            settings.preAction(e, thisUIEvent.Action)
        } else {
            thisUIEvent.Action(e);
        }

    };

    // Executed after the 'PreAction'.
    // If you provide your own event handler you must call the 'callback' function when done.
    this.Action = function (e) {

        if (settings.action) {
            settings.action(e, thisUIEvent.PostAction);
        } else {
            thisUIEvent.PostAction(e);
        }

    };

    // Executed after the 'Action'.
    this.PostAction = function (e) {

        if (settings.postAction) {
            settings.postAction(e);
        }

    };

    // Must be called to create the event listener.
    this.Initialize = (container) => {

        var element = thisUIEvent.GetElement(container || document);
        if (element === null) { return; }

        element.addEventListener(thisUIEvent.EventType, function (e) {
            thisUIEvent.PreAction(e);
        });

    };

}

Example Usage: Add Row Button

var AddRowEvent = new UIEvent({
    eventType: "click",
    eventElement: (container) => container.querySelector(".add-new-row"),
    preAction: (e, callback) => {
        document.querySelector(".add-new-row").setAttribute("disabled", "disabled");
        if (callback) {
            callback(e);
        }
    },
    action: (e, callback) => {

        var defaultOrder = { Messages: [{ Text: "This is a new row", Color: "green" }, { Text: "This is a new row", Color: "green" }], DeliveryDate: new Date().toLocaleDateString() };

        var newRowHtml = Render.Once("row-template", defaultOrder);
        var row = Grid.InsertRowBeforeIndex(advanceOrdersTableSelector, newRowHtml);
        initializeRow(row);
        toggleCanEditRow(row, true);

        if (callback) {
            callback(e);
        }

    },
    postAction: (e) => {
        document.querySelector(".add-new-row").removeAttribute("disabled")
    }
});
AddRowEvent.Initialize(); // Same as AddRowEvent.Initialize(document) thanks to defaults.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.