Wednesday, 26 June 2013

jQuery Validate: Native Unobtrusive Validation Support!

Did you know that jQuery Validate natively supports the use of HTML 5 data attributes to drive validation unobtrusively? Neither did I - I haven't seen any documentation for it. However, I was reading the jQuery Validate test suite and that's what I spotted being used in some of the tests.

I was quite keen to give it a try as I've found the Microsoft produced unobtrusive extensions both fantastic and frustrating in nearly equal measure. Fantastic because they work and they're integrated nicely with MVC. Frustrating, because they don't allow you do all the things that jQuery Validate in the raw does.

So when I realised that there was native alternative available I was delighted. Enough with the fine words - what we want is a demo:

Not particularly exciting? Not noticably different to any other jQuery Validate demo you've ever seen? Fair enough. Now look at the source:

Do you see what I see? Data attributes (both data-rule-* and data-msg-*s) being used to drive the validation unobtrusively! And if you look at the JavaScript files referenced you will see *no sign* of jquery.validate.unobtrusive.js - this is all raw jQuery Validate. Nothing else.

Why is this useful?

First of all, I'm of the opinion that it makes intuitive sense to have the validation information relevant to various DOM elements stored directly with those DOM elements. There will be occasions where you may not want to use this approach but, in the main, I think it's very sensible. It saves you bouncing back and forth between your HTML and your JavaScript and it means when you read the HTML you know there and then what validation applies to your form.

I think this particularly applies when it comes to adding elements to the DOM dynamically. If I use data attributes to drive my validation and I dynamically add elements then jQuery Validate will parse the validation rules for me. I won't have to subsequently apply validation to those new elements once they've been added to the DOM. 1 step instead of 2. It makes for simpler code and that's always a win.

Wrapping up

For myself I'm in the early stages of experimenting with this but I thought it might be good to get something out there to show how this works. If anyone knows of any official documentation for this please do let me know - I'd love to have a read of it. Maybe it's been out there all along and it's just my Googling powers are inadequate.

Update 09/08/2012

If you're using ASP.Net MVC 3+ and this post has been of interest to you then you might want to take a look at this.

Thursday, 6 June 2013

How I'm Using Cassette part 2:
Get Cassette to Serve Scripts in Dependency Order

Last time I wrote about Cassette I was talking about how to generally get up and running. How to use Cassette within an ASP.Net MVC project. What I want to write about now is (in my eyes) the most useful feature of Cassette by a country mile. This is Cassettes ability to ensure scripts are served in dependency order.

Why does this matter?

You might well ask. If we go back 10 years or so then really this wasn't a problem. No-one was doing a great deal with JavaScript. And if they did anything it tended to be code snippets in amongst the HTML; nothing adventurous. But unless you've had your head in the sand for the last 3 years then you will have clearly noticed that JavaScript is in rude health and being used for all kinds of things you'd never have imagined. In fact some would have it that it's the assembly language of the web.

For my part, I've been doing more and more with JavaScript. And as I do more and more with it I seek to modularise my code; (like any good developer would) breaking it up into discrete areas of functionality. I aim to only serve up the JavaScript that I need on a given page. And that would be all well and good but for one of the languages shortcomings. Modules. JavaScript doesn't yet have a good module loading story to tell. (Apparently one's coming in EcmaScript 6). (I don't want to get diverted into this topic as it's a big area. But if you're interested then you can read up a little on different approaches being used here. The ongoing contest between RequireJS and CommonJS frankly makes me want to keep my distance for now.)

It Depends

Back to my point, JavaScripts native handling of script dependencies is non-existent. It's real "here be dragons" territory. If you serve up, for example, Slave.js that depends on things set up in Master.js before you've actually served up Master.js, well it's not a delightful debugging experience. The errors tend be obscure and it's not always obvious what the correct ordering should be.

Naturally this creates something of a headache around my own JavaScript modules. A certain amount of jiggery-pokery is required to ensure that scripts are served in the correct order so that they run as expected. And as your application becomes more complicated / modular, the number of problems around this area increase exponentially. It's really tedious. I don't want to be thinking about managing that as I'm developing - I want to be focused on solving the problem at hand.

In short, what I want to do is reference a script file somewhere in my server-side pipeline. I could be in a view, a layout, a controller, a partial view, a HTML helper... - I just want to know that that script is going to turn up at the client in the right place in the HTML so it works. Always. And I don't want to have to think about it any further than that.

Enter Cassette, riding a white horse

And this is where Cassette takes the pain away. To quote the documentation:

"Some assets must be included in a page before others. For example, your code may use jQuery, so the jQuery script must be included first. Cassette will sort all assets based on references they declare."

Just the ticket!

Declaring References Server-Side

What does this look like in reality? Let's build on what I did last time to demonstrate how I make use of Asset References to ensure my scripts turn up in the order I require.

In my _Layout.cshtml file I'm going to remove the following reference from the head of the file:

Bundles.Reference("~/bundles/core");

I'm pulling this out of my layout page because it's presence means that every page MVC serves up is also serving up jQuery and jQuery UI (which is what ~/bundles/core is). If a page doesn't actually make use of jQuery and / or jQuery UI then there's no point in doing this.

"But wait!", I hear you cry, "Haven't you just caused a bug with your reckless action? I distinctly recall that the Login.cshtml page has the following code in place:"

Bundles.Reference("~/bundles/validate");

"And now with your foolhardy, nay, reckless attitude to the ~/bundles/core bundle you've broken your Login screen. How can jQuery Validation be expected to work if there's no jQuery there to extend?"

Well, I understand your concerns but really you needn't worry - Cassette's got my back. Look closely at the code below:

See it? The ~/bundles/validate bundle declares a reference to the ~/bundles/core bundle. The upshot of this is, that if you tell Cassette to reference ~/bundles/validate it will ensure that before it renders that bundle it first renders any bundles that bundle depends on (in this case the ~/bundles/core bundle).

This is a very simple demonstration of the feature but I can't underplay just how useful I find this.

Declaring References in your JavaScript itself

And the good news doesn't stop there. Let's say you don't want to maintain your references in a separate file. You'd rather declare references inside your JavaScript files themselves. Well - you can. Cassette caters for this through the usage of Asset References.

Let's demo this. First of all add the following file at this location in the project: ~/Scripts/Views/Home/Index.js

The eagle-eyed amongst you will have noticed

  1. I'm mirroring the MVC folder structure inside the Scripts directory. (There's nothing special about that by the way - it's just a file structure I've come to find useful. It's very easy to find the script associated with a View if the scripts share the same organisational approach as the Views.).
  2. The purpose of the script is very simple, it fades out the main body of the screen, re-writes the HTML in that tag and then fades back in. It's purpose is just to do something that is obvious to the user - so they can see the evidence of JavaScript executing.
  3. Lastly and most importantly, do you notice that // @reference ~/bundles/core is the first line of the file? This is our script reference. It's this that Cassette will be reading to pick up references.

To make sure Cassette is picking up our brand new file let's take a look at CassetteConfiguration.cs and uncomment the line of code below:

bundles.AddPerIndividualFile("~/Scripts/Views");

With this in place Cassette will render out a bundle for each script in the Views subdirectory. Let's see if it works. Add the following reference to our new JavaScript file in ~/Views/Home/Index.cshtml:

Bundles.Reference("~/Scripts/Views/Home/Index.js");

If you browse to the home page of the application this is what you should now see:

What this means is, Index.js was served up by Cassette. And more importantly before Index.js was served the referenced ~/bundles/core was served too.

Avoiding the Gotcha

There is a gotcha which I've discovered whilst using Cassette's Asset References. Strictly speaking it's a Visual Studio gotcha rather than a Cassette gotcha. It concerns Cassette's support for Visual Studio XML style reference comments. In the example above I could have written this:

/// <reference path="~/bundles/core" />

Instead of this:

// @reference ~/bundles/core

It would fulfil exactly the same purpose and would work identically. But there's a problem. Using Visual Studio XML style reference comments to refer to Cassette bundles appears to trash the Visual Studios JavaScript Intellisense. You'll lose the Intellisense that's driven by ~/Scripts/_references.js in VS 2012. So if you value your Intellisense (and I do) my advice is to stick to using the standard Cassette references style instead.

Go Forth and Reference

There is also support in Cassette for CSS referencing (as well as other types of referencing relating to LESS and even CoffeeScript). I haven't made use of CSS referencing myself as, in stark contrast to my JS, my CSS is generally one bundle of styles which I'm happy to be rendered on each page. But it's nice to know the option is there if I wanted it.

Finally, as last time you can see what I've done in this post by just looking at the repository on GitHub. The changes I made are on the References branch of that particular repository.