I am trying to create a reusable widget in ASP.Net MVC. This is a widget that concatenates 2 dates into a string. The widget contains 3 files: Widget.cshtml, Widget.css, and Widget.js and dependencies to several jquery libraries.
Widget.cshtml
<h2>Create a date range</h2>
<div>
<label for="startDate">Start:</label>
<input id="startDate" class="date" name="startDate" type="text" />
</div>
<div>
<label for="endDate">End:</label>
<input id="endDate" class="date" name="endDate" type="text" />
</div>
<p id="output"></p>
<button id="createDateRange">Create</button>
Widget.css
label { color: #555;}
Widget.js
$(function () {
$(".date").datepicker();
$("#createDateRange").click(function () {
var start = $("#startDate").val();
var end = $("#endDate").val();
$("#output").html(start + " to " + end);
});
});
I want to make this widget reusable in my MVC pages. I have come up with several options, including:
I was about to use a helper, when I remembered Steve Souders rules for web site performance:
Rule 5: Put stylesheets at the top
Rule 6: Put scripts at the bottom
Options 1), 2) and 3) all seem like good ideas, but they all write the code inline and violate the performance rules. Option 4) allows me to manually put the javascript and css files where they belong, but copy-and-paste is prone to mistakes. A potential idea would be write a scaffolder that puts everything where it belongs, but that seems too much work for right now.
What is the best (hopefully simple) way to do widgets and still follow performance rules 5 & 6?
You could use RenderSection() which is similar to ContentPlaceHolder's of old and put them in your _Layout.cshtml
<head>
<title>@ViewBag.Title</title>
<link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
<script src="@Url.Content("~/Scripts/jquery-1.4.4.min.js")" type="text/javascript"></script>
@RenderSection("head");
</head>
Then in your View put:
@{
ViewBag.Title = "Home Page";
}
@section head
{
<link href="widget-style.css" type="text/css" rel="stylesheet" /><
}
<h2>@ViewBag.Message</h2>
<p>
To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>.
</p>
@section footer{
<script type="text/javascript" src="wiget.js"></script>
}
It's a simple alternative if you don't want to use Combress or Chirpy, you'll still have to add the code into the pages you use the control on, but it'll appear in the right places.
I also found a handy blog post on registering scripts from within a partial view that might be worth a read.
The original example already uses some unobtrusive javascript techniques, but here's how you could extend that pattern even further, as demonstrated in this jsfiddle.
Widget.cshtml
<div class="date-range-widget">
<h2>Create a date range</h2>
<div>
<label for="startDate">Start:</label>
<input id="startDate" class="date start-date" name="startDate" type="text" />
</div>
<div>
<label for="endDate">End:</label>
<input id="endDate" class="date end-date" name="endDate" type="text" />
</div>
<p class="output"></p>
<button class="create-date-range">Create</button>
</div>
Widget.js
$(function () {
// This line could probably be done generally, regardless of whether you're
// in the widget.
$("input.date").datepicker();
$("div.date-range-widget").each(function(){
var $t = $(this);
var startBox = $t.find("input.start-date");
var endBox = $t.find("input.end-date");
var output = $t.find("p.output");
$t.find("button.create-date-range").click(function () {
output.html(startBox.val() + " to " + endBox.val());
});
});
});
Note how you can now have multiple instances of this widget present on your page, with different id
and name
values, and they would function independently of one another.
When no data-range-widget is present, the javascript will still search the DOM, fail to find any, and move on. However, the cost of this operation is usually pretty lightweight compared to making a separate round-trip for a different javascript file. Keeping the CSS and javascript in separate, static files makes it so the browser can cache those files, which means it's pulling less data across the wire on average (since only the HTML changes from one request to the next).
I've personally found it worthwhile to combine my javascript and CSS into one file, so the browser only has to pull one javascript and one css file in for a given page load (and both will be cached after the first page load). If you have a very large javascript file that is only used on certain pages, you may want to keep it separate and only load it on certain pages.
Regardless, your javascript should be written in such a way that you could have all the javascript files on your site loaded at once without stepping on each others' toes.
Should be pretty self-explanatory.
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