I have tried many different ways to organize the JavaScript that is specific for each View now, but I have not found any way that I feel comfortable with. It seems messy anyway. Probably (and hopefully) that is because I haven't been working with JavaScript very long, and there is a good way of doing this.
Currently what I'm doing is this:
In my Layout file, I have the a RenderSection for scripts in addition to RenderBody. This section contains all JavaScript relevant for each single view. The global script is tucked away in it's own file.
Inside this sections there is a lot of different part of JavaScript (for my biggest View currently there is about 600 lines of JavaScript):
The things I don't like here are mainly two things:
@Url.Action('...')
to link it to the correct action method to be sure that my script will continue to work even if I change my routing.
I also use the Model to decide if some elements should start out hidden or not like this (is this an ok way to make it start out hidden, or is there a better way? It seems kind of hacky even if I can't put my finger on it).:code
@if( Model.SomeBoolValue ){
@:$("#DOMelementID").hide();
}
Some pointers to get me in the right direction would be highly appreciated. I need to get this better structured before I lose control over my own code.
I would recommend you taking a look at jQuery plugin authoring and organize your javascript code in terms of plugins that you will attach to your DOM elements.
As far as the @Url.Action('...')
problem is concerned there are many ways to solve this issue and externalize your scripts into separate files. For example let's suppose that you are AJAXifying an existing form or ActionLink which already contains the url:
$('#myAnchor').click(function() {
// use this.href to fetch the url
$.post(this.href, function(result) {
});
return false;
});
Now if you simply wanted to send an AJAX request when a user clicks on a div for example, you could always use HTML5 data-* attributes (the same way ASP.NET MVC 3 unobtrusive AJAX and validation works) to define this url on the DOM element:
<div id="mydiv" data-url="@Url.Action("Some Action")">click me</div>
and now in a separate file
$('#mydiv').click(function() {
var url = $(this).data('url');
$.post(url, function(result) {
});
});
and if you follow my first advice about writing a jQuery plugin your code will look like this:
$('#mydiv').myplugin();
Now let's consider the following snippet:
@if(Model.SomeBoolValue) {
@:$("#DOMelementID").hide();
}
So from what it seems here you are using the view model properties to show/hide sections of your code. OK, here's what I may suggest you: JSON serialize this model into the view and then you can start passing values from it to your newly developed jQuery plugins:
<script type="text/javascript">
var model = @Html.Raw(Json.Serialize(Model));
// now configure configure your plugins, for example
$('#mysection').myplugin({ model: model });
</script>
Now inside your plugin you will have access to absolutely all properties of your view model.
And that's all that you will need to put in your view. All the other javascript will be of course in separate javascript files, properly organized in reusable jQuery plugins.
Yep, it can get tough.
Here's what we do, and works for us (in bold, because it may not work for you).
For each View/page, we work out what model properties are required by the JavaScript in order to make decisions (a.k.a "logic").
We also have a section in the Layout for the JavaScript.
We then set a single JavaScript property in the View/page, encapsulating these properties, something like this:
@section JavaScript {
<script type="text/javascript">
yn.yp = {
someBoolValue: @Model.SomeBoolValue,
someOtheProp: '@Model.SomeOtherProp'
}
</script>
}
yn
= your namespace, tying the global namespace for your project/company.
yp
= your page that your setting the JS property for.
Then in your external JS file:
$(function() {
if (yn.yp.someBoolValue) {
$("#elementid").hide();
}
});
This is also a very clean way to handle routing URL's to be used by client-side AJAX. Setup a property like yn.yp.urls
, and set the URL's in there in the View, then the JS can access them easily and without any hard-coding whatsoever.
Overall, the goal here is to reduce server-side code in the embedded page JavaScript.
Set properties for whatever the JS needs to make decisions, then let the JS make the decisions itself.
Hope that makes sense.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With