Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

In my job I write a lot of small JS/jQuery "snippets" for changing the default behaviour in the base product according to what the customer wants.

I tend to organize it so that I have one .js file per view (we use ASP.NET MVC) and in this view-specific file I put all modifications relevant to that view. This is often code that is very tight-coupled to the HTML of the view. I tend to group similar "actions" into their own anonymous functions which are self-executable and then write a comment about what this portion of code does so that I don't have this huge blob of a file which I cannot navigate.

Sample:

(function ($, viewData, undefined) {
    // Setup some config and some function and do something on DOM ready.

    var someConfig = {
        something: viewData.something,
        somethingElse: viewData.somethingElse
    };

    function someFunction() {
        return someConfig.something && someConfig.somethingElse;
    }

    $(function () {
        if (someFunction())
            $('#something').css('background-color', 'red');
    });

})(jQuery, viewData);

(function ($, undefined) {
    // Hide stuff on click maybe, no preparation.

    $(function () {
        $('body').delegate('.hide', 'click', function () {
            var that = $(this);
            that.hide();
        });
    });

})(jQuery);

http://jsfiddle.net/vikekh/9Rfs6/

If something is reusable I break it out into a global plugin/module, accessible via window.myModule or extend jQuery with my own selectors or chaining functions.

Feel very free to comment on my approach, pros and cons and so on. I'm not very keen on pushing for module frameworks such as RequireJS as other JS developers here may not be interested in using these frameworks. Also, feel free to comment about any other errors in my code -- JS is difficult to write correctly in my opinion.

share|improve this question
1  
Honestly, there is not a lot to review with sample code, your pattern is pretty standard. It is how you use it that reveals potential trouble. Would it be possible to put actual code here ? –  konijn May 12 '14 at 13:52
    
I am merely looking for pointers or alternatives for doing and structuring these kinds of simple event bindings and what not in a clean and readable fashion. I get told what to do when a user clicks on this and that and in the past I have locked myself down in complex structures/designs based on the current requirements, but the next day those requirements have changed and I have to do a rewrite... Am I right in that these script-like snippets should not be modularized into libs? I get so tired with JavaScript as there is no real OOP and I tend to jump from one pattern to another... –  Viktor May 12 '14 at 19:08

1 Answer 1

JavaScript is most definitely Object Oriented. I also feel your pain. In the last half decade or so I've gravitated towards a pattern where a "class" in JavaScript is responsible for all user interaction starting at a root node on down in the document tree. The class gets instantiated with a root element and some run time configurable options, allowing the "module" to be fully encapsulated. I also ended up creating an Event Delegation library called Oxydizr so I didn't have to repeatedly write click handlers, and such. You could look into that sort of pattern.

To take some of your show/hide functionality:

First, I'd create a base JavaScript class:

function BaseModule() {
    this.options = {};
}

BaseModule.prototype = {

    document: null,

    element: null,

    $element: null,

    options: null,

    window: null,

    constructor: BaseModule,

    init: function(element, options) {
        if (element) {
            this.setElement(element);
        }

        if (options) {
            this.setOptions(options);
        }
    },

    setElement: function(element) {
        this.element = typeof element === "string"
                     ? document.getElementById(element)
                     : element;
        this.document = this.element.ownerDocument;
        this.window = this.document.defaultView;
        this.$element = this.window.jQuery(this.element);
    },

    setOptions: function(options) {
        for (var key in options) {
            if (options.hasOwnProperty(key)) {
                this.options[key] = options[key];
            }
        }
    }
};

Then create your concrete class to show/hide stuff:

function ShowHideModule() {
    BaseModule.call(this);

    this.setOptions({
        hiddenClass: "hide",
        selector: ".showHide"
    });
}

ShowHideModule.prototype = Object.create(BaseModule.prototype);

ShowHideModule.prototype.controllerId = "showHide";

ShowHideModule.prototype.toggle = function click(event, element, params) {
    event.preventDefault();
    var $element = $(element);

    if ($element.hasClass(this.options.hiddenClass)) {
        $element.closest(this.options.selector).removeClass(this.options.hiddenClass);
    }
    else if (!params.confirm || this.window.confirm(params.confirm)) {
        $element.closest(this.options.selector).addClass(this.options.hiddenClass);
    }
};

Now some JavaScript using Oxydizr as a "front controller" for event delegation:

var frontController = new Oxydizr.FrontContoller().init(document.documentElement),
    showHideModule = new ShowHideModule().init(document.documentElement);

frontController.registerController(showHideModule);

With this, you can have as many show/hide triggers on the page as you want:

<body>
    <div class="showHide">
        <h2 data-actions="showHide.toggle">Foo</h2>
        <div>
            ...
        </div>
    </div>

    <div class="showHide">
        <h2 data-actions="showHide.toggle"
            data-action-params='{"confirm": "Are you sure you want to hide this?"}'
        >Bar</h2>
        <div>
            ...
        </div>
    </div>

It's a little boilerplate code to begin with, but it allows you to write very modular and reusable code. Each module is completely encapsulated, right down to the document and window objects. Since these classes are encapsulated, it becomes easy to inject mocks and stubs to enable unit testing, plus using something like Oxydizr decouples the markup from the behavior, giving you even more flexibility.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.