2

In my company we have a survey framework to help stakeholders create surveys, I'm trying to create a re-usable object which will allow a team member to easily set the width of a particular question for a survey - they can sometimes be a bit squished depending on the length of the answers. I'm trying to use a combination of the module and constructor pattern but not sure if I pulled it off correctly. Is there a better way to write my code?

        var WidthIncreaser = (function(){
            return function (element, words, width) {

                var element = $(element);
                var re = new RegExp(words, 'gi');

                return {
                    init: function() {
                        if (element.text().match(re)) {
                            element.width(width);
                        }
                    }
                };
            };
        })();

        var tr = new WidthIncreaser('td.choicev-question:first', 'Applicable from the', 400);
        tr.init();

The idea is, somebody can create a new instance of WidthIncreaser and pass in an element, a string which matches the question's text so it's the right question being targeted and the size to set width of the question to.

Thanks for the advice in advance!

3 Answers 3

1

You are double wrapping stuff. Anyways, the common module pattern I see is just a function that returns an object with closure.

No need for the new keyword nor an immediate function. Immediate functions are usually used when only one object is made and assigned directly to one variable. In your case, you wanted to make "instances".

var WidthIncreaser = function(element, words, width) {

    var element = $(element),
        re = new RegExp(words, 'gi');

    return {
        init: function() {
            if (element.text().match(re)) {
                element.width(width);
            }
        }
    };
};

var tr = WidthIncreaser('td.choicev-question:first', 'Applicable from the', 400);

tr.init();​
Sign up to request clarification or add additional context in comments.

Comments

0

The module pattern I use usually looks like this:

var myModule = (function () {
    var myPrivateVar = 'foo';
    var myPrivateFunc = function () {
        console.log('bar');
    };

    return {
        myPublicFunc: function () {
            console.log(myPrivateVar);
        }
    };
}) ();

Then it would be used like this:

myModule.myPublicFunc();

Comments

0

I don't think you actually need "the module pattern" here. You can just take advantages of closures and that's all:

function WidthIncreaser(element, words, width) {
    element = $(element);
    var re = new RegExp(words, 'gi');

    this.init = function () {
        if (element.text().match(re)) {
            element.width(width);
        }
    }
}

var tr = new WidthIncreaser('td.choicev-question:first', 'Applicable from the', 400);

tr.init();

Of course you don't need necessary init in that case, because you could put everything in the ctor, but I assume it's just an example and maybe you need lazy initialization.

In that way you can keep your prototype chains, and you statements like:

tr instanceof WidthIncreaser // true

will works.

In addition, you can also populate the prototype with methods that doesn't need to access to the scoped variables, at least not directly:

WidthIncreaser.prototype.doSomething = function() { /* .. */ }

For instance, if you can't use getter and setter because cross browsing restriction, you could have a function like that:

function WidthIncreaser(element, words, width) {
    element = $(element);
    var re = new RegExp(words, 'gi');

    this.element = function() { return element };

    this.init = function () {
        if (element.text().match(re)) {
            element.width(width);
        }
    }
}

WidthIncreaser.prototype.reset = function () {
    this.element().text("")
}

So basically you can retrieve the element from outside, but it's read-only, the WidthIncreaser can set elements only during the instantiation.

Edit: I copied and pasted init that of course it didn't work for a dependency with re, so it was a bad example to illustrate the approach.

2 Comments

I don't see why you'd protect element in this way. Much better idea to just set this.element = $(element). Much simpler.
All the question was about "protect" so that's why. Of course you can always overwrite the public methods to provide something different, but you don't have a direct access to the variable. I personally prefer works with modern browsers that give you more flexibility about that with ES5. Otherwise there is no need to have this such approach and a public property is fine.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.