Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Javascript

Optimal and unobtrusive JavaScript arrangement in MVC project

5.00/5 (2 votes)
12 Jun 2011CPOL1 min read 22.4K  
Optimal and unobtrusive JavaScript arrangement in MVC project

Since I started coding in MVC3, I had to work my way in calling proper JavaScript functions in given views. Through some ideas, I came to this "pattern". I utilize jQuery to get DOM elements and bind events.


Following Douglas Crockford's tips, I encapsulate all my JavaScript functions inside a container function (for more on 'why is this better' Google 'Douglas Crockford'). Then in the document.ready event, I initialize it and the magic begins :)



So, in my scripts.js file (later minified and possibly obfuscated), I start with something like this:


JavaScript
function SiteModule(window, viewData, undefined) {
    var that = this;

    function somePrivateFunction() {
        //inside private finction
    }

    this.Home_Index = function (window, viewData, undefined) {
        //inside public function
    }

    this.About_Index = function (window, viewData, undefined) {
        //inside public function
    }

    $(".js-module").each(function () {
        var module = $(this).attr('data-module');
        try {
            return new that[module](window, viewData);
        } catch (e) {
            throw new Error('Unable to create module "' + module + '"');
        }
    });
}

var _viewData = {};
var _site = null;

$(function () {
    _site = SiteModule(window, _viewData);
});

In _Layout.cshtml (since I'm using Razor, but I guess it can be adapded to other view engines), I put:


JavaScript
<script src="@Url.Content("~/Scripts/jquery.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/scripts.js")" type="text/javascript"></script>
<script type="text/javascript">
    _viewData = {
        @RenderSection("scriptViewData", false)
        someOtherProperty: '@SomeModelValue'
    };
</script>

In the above snippet, I render the scriptViewData section which gives me the ability to pass data from the rendered view to the script, like this:


JavaScript
@section scriptViewData{
   someProperty : @ViewBag.SomePropertyIWantToPassToJS,
   someOtherProperty : @Model.SomeOtherPropertyIWantToPassToJS,
}

Notice the comma at the end of each property line? That's because this is just a part of the _viewData object, and in the _Layout view, after the RenderSection call, I add some other useful properties to keep the object valid.


And finally, in the Views (partial, non-partial), wherever I want, I add:


HTML
<span class="js-module" data-module="Home_Index"></span>

js-module is a class name used by the module to get the element. I'm using class and not some data-... attribute because jQuery's class selector is faster than the attribute selector. Also, in your CSS, you can write something like .js-module {display: none}.


And data-module is the name of the JavaScript public function defined in the SiteModule function.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)