Dispatcher

Example for functional programming in JavaScript: a dispatcher that executes arbitrary callbacks when corresponding predicate functions return true

by Patrick Hund

HTML

<div class="container">
    <div class="row">
        <div class="col-md-12">
             <h1>Dispatcher</h1>

            <p>Executes callback functions as soon as a predicate function returns true by executing the predicate every 100 ms.</p>
            <p>You can provide as many predicate/callback pairs as you like, they all run in the same loop, since the dispatcher is implemented as a singleton and keeps an array of predicates and callbacks in its function scope.</p>
            <p>The callbacks in this example simply write log statements to the black console window below, but you can, of course, have them do anything.</p>
            <p>So instead of using a keyup event listener on the input field that triggers each time the user types, we simply specify a predicate function that returns true if the input field has a value.</p>
            <p>The advantage over event listeners: you can listen to things that there are no events for, like an element becoming visible (the blue buttons trigger these).</p>
        </div>
    </div>
    <div class="row">
        <div class="col-md-2">
            <div class="form-group">
                <input id="input1" type="text" class="form-control" placeholder="Input 1">
            </div>
        </div>
        <div class="col-md-1">
            <div id="toggle-input1" class="form-group">
                <button type="button" class="btn btn-primary form-control visible-md">Toggle</button>
                <button type="button" class="btn btn-primary form-control hidden-md"> <span class="glyphicon glyphicon-eye-open left"></span>
Toggle</button>
            </div>
        </div>
        <div class="col-md-2"></div>
        <div class="col-md-2">
            <div class="checkbox">
                <label>
                    <input id="checkbox1" type="checkbox">Checkbox 1</label>
            </div>
        </div>
        <div class="col-md-1">
            <div id="toggle-checkbox1" class="form-group">
                <button...

CSS

#console {
    background-color: #000000;
    width: 100%;
    height: 200px;
    overflow: scroll;
    padding: 10px;
    border-radius: 15px;
}
#console p {
    margin: 0;
    color: green;
}
#console p.new {
    color: lime;
}

JavaScript

(function () {
    "use strict";

    var dispatcher;

    function log(msg) {
        var $console = $("#console");
        $console.find("p").first().removeClass("new");
        $console.prepend("<p class=\"new\">" + msg + "</p>");
    }

    function elementOrSelector(elors) {
        return function (func) {
            return func.apply(typeof elors === "string" ? $(elors) : elors);
        };
    }

    function cull(arr) {
        return function (predf) {
            var i;
            for (i = arr.length - 1; i >= 0; i--) {
                if (predf.apply(arr[i])) {
                    arr.splice(i, 1);
                }
            }
        };
    }

    dispatcher = (function () {
        var instance, dispatches = [];

        function createInstance() {
            (function dispatch() {
                cull(dispatches)(function () {
                    if (this.predf.apply(null, this.additionalArgs)) {
                        this.deferred.resolve.apply(null, this.additionalArgs);
                        return true;
                    }
                    return false;
                });
                window.setTimeout(dispatch, 100);
            }());

            return {
                register: function () {
                    var predf, additionalArgs, deferred;

                    if (!arguments.length) {
                        throw "'when' function expects at least one argument (the predicate function";
                    }
                    predf = arguments[0];
                    if (typeof predf !== "function") {
                        throw "first argument passed to 'when' function is not a function";
                    }
                    additionalArgs = Array.prototype.slice.apply(arguments, [1]);
                    deferred = $.Deferred();
                    dispatches.push({
                        predf: predf,
                        additionalArgs: additionalArgs,
                        deferred: deferred
  ...