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:
function SiteModule(window, viewData, undefined) {
var that = this;
function somePrivateFunction() {
}
this.Home_Index = function (window, viewData, undefined) {
}
this.About_Index = function (window, viewData, undefined) {
}
$(".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:
<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:
@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:
<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.