Search code examples
javascriptdesign-patternsmediator

JavaScript Mediator pattern; Component name is undefined


In the following implementation of the mediator pattern why this.name in the initialize method always undefined? As I was expecting it to be TestObject. How can I achieve this?

Also how can I create new instances of TestObject?

Mediator = function() {

        var debug = function() {
            // console.log or air.trace as desired
        };

        var components = {};

        var broadcast = function(event, args, source) {
            var e = event || false;
            var a = args || [];
            if (!e) {
                return;
            }
            //debug(["Mediator received", e, a].join(' '));
            for (var c in components) {
                if (typeof components[c]["on" + e] == "function") {
                    try {
                        //debug("Mediator calling " + e + " on " + c);
                        var s = source || components[c];
                        components[c]["on" + e].apply(s, a);
                    } catch (err) {
                        debug(["Mediator error.", e, a, s, err].join(' '));
                    }
                }
            }
        };

        var addComponent = function(name, component, replaceDuplicate) {
            if (name in components) {
                if (replaceDuplicate) {
                    removeComponent(name);
                } else {
                    throw new Error('Mediator name conflict: ' + name);
                }
            }
            components[name] = component;
        };

        var removeComponent = function(name) {
            if (name in components) {
                delete components[name];
            }
        };

        var getComponent = function(name) {
            return components[name] || false;
        };

        var contains = function(name) {
            return (name in components);
        };

        return {
            name      : "Mediator",
            broadcast : broadcast,
            add       : addComponent,
            rem       : removeComponent,
            get       : getComponent,
            has       : contains
        };
    }();


    // Components    
    Mediator.add('TestObject', function() {

        var someNumber = 0; // sample variable
        var someString = 'another sample variable';

        return {
            onInitialize: function() {
                // this.name is automatically assigned by the Mediator
                alert(this.name + " initialized.");
            },
            onFakeEvent: function() {
                someNumber++;
                alert("Handled " + someNumber + " times!");
            },
            onSetString: function(str) {
                someString = str;
                alert('Assigned ' + someString);
            }
        }
    }());

    Mediator.broadcast("Initialize");                 
    Mediator.broadcast('FakeEvent');                  
    Mediator.broadcast('SetString', ['test string']); 
    Mediator.broadcast('FakeEvent');                  
    Mediator.broadcast('SessionStart');

Solution

  • It's because in the function bloc you're returning, this represents the bloc itself, not the mediator object (you can try a console.log(this); in onInitialize to see that).

    EDIT:

    To add a name component to your callback, you could do something like that

    var addComponent = function(varName, component, replaceDuplicate) {
        if (varName in components) {
            if (replaceDuplicate) {
                removeComponent(varName);
            } else {
                throw new Error('Mediator name conflict: ' + varName);
            }
        }
        components[varName] = component;
        components[varName].name = varName;
    };
    

    There were a lot of name, so i changed the local name to varName