Amadiere.com

Fourteen and a half crazy frog burpers

30th August 2011

ASP.NET MVC 3: Drop Down Lists / SelectLists

Filed under: JQuery,MVC — Tags: , — Alex Holt @ 10:42 pm

There are a number of very useful helpers that come as default with the ASP.NET MVC framework, but one that always seems to get people confused is the Html.DropDownListFor() helper method. So in this post, I’ll quickly go over the steps I use to populate the list, as well as some of the more funky features once it’s up and running!

In our example, there will simply be a single drop down list on a form that shows a list of countries, from which you can select and submit.

First, we need to build a view model that is going to be the contract that determines the data that the view can display.

1
2
3
4
5
6
7
8
9
public class IndexViewModel
{
    // Stores the selected value from the drop down box.
    [Required]
    public int CountryID { get; set; }
 
    // Contains the list of countries.
    public SelectList Countries { get; set; }
}

Once we’ve sorted that, we can create the action result methods for our index page.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class HomeController : Controller
{
    [HttpGet]
    public ActionResult Index()
    {
        IndexViewModel viewModel = new IndexViewModel();
        viewModel.Countries = new SelectList(GetCountries(), "ID", "Name");
        return View(viewModel);
    }
 
    [HttpPost]
    public ActionResult Index(IndexViewModel viewModel)
    {
        viewModel.Countries = new SelectList(GetCountries(), "ID", "Name");
        if (!ModelState.IsValid)
            return View(viewModel);
 
        //TODO: Do something with the selected country...
        CMSService.UpdateCurrentLocation(viewModel.CountryID);
 
        return View(viewModel);
    }
}

You’ll notice there are two instances where we populate the Countries property on the viewModel, one in the HttpGet method and the other in the HttpPost. We do this so that the list of countries is available throughout our process. You see, unlike the CountryID which is submitted as part of the Request object (it’s part of the form collection), our list is never stored – it’s lost as soon as the user navigates away from that page. So we need to repopulate it. In reality, you may only need to repopulate it when the validation fails an you have to redraw the screen in the HttpPost method, so that could be moved.

Then, it’s just a simple case of adding this to my view:

@Html.DropDownListFor(x => x.CountryID, Model.Countries)

Or you could forcably add a blank value to the top with some “please select me, pretty please”-type text. e.g.

@Html.DropDownListFor(x => x.CountryID, Model.Countries, "- please select -")

And there you have it! A working drop down box using MVC 3 and Razor views.
Now for some more fancy stuff. If you’re interested in styling your menu, then you can’t really go far wrong with jQuery UI SelectMenu (of which there are a few demos available, as well as a separate tutorial). To set up, you only need to do a few things:

  • Download JQuery & JQueryUI and add to your solution. You can now do this step through NuGet, or manually by “Add Existing Item” and downloading from the respective site.
  • Add a reference to the .js and .css files to the header of your html header, often set by the _Layout.cshtml file. Something like the following:
   <link type="text/css" rel="stylesheet" href="@Url.Content("~/Content/themes/base/jquery.ui.all.css")" />
   <script type="text/javascript" src="@Url.Content("></script>
   <script type="text/javascript" src="@Url.Content("></script>
  • Download and add the SelectMenu .js and .css files in much the same way.
<link type="text/css" rel="stylesheet" href="@Url.Content("~/Content/selectmenu.css")" />
<script src="@Url.Content("~/Scripts/selectmenu.js")" type="text/javascript"></script>
  • Then all that lies to do is to set it off going:
<script type="text/javascript">
   $('select').selectmenu();
</script>

The last bit we added there simply makes this apply for every single select box that is on the page. As an aside, when doing AJAX or JQuery where you may potentially add an additional drop down list, you will need to call .selectmenu() to ensure that your new box appears like the others. It’s also worth noting that you may find if your page isn’t a fast loader, the standard drop down box (unstyled) will appear for a brief period.

20th June 2011

Unobtrusive JavaScript in ASP.NET MVC3 with JQuery

Filed under: ASP.NET,C#,HTML,JQuery,MVC — Tags: , , , , , — Alex Holt @ 9:45 pm

I’ve recently experimented a little bit with some of the new unobtrusive JavaScript stuff that is now included as part of the default ASP.NET MVC 3 project template. While not an overly complex subject, it’s been one of them plugins I wanted to have a dabble with, but I didn’t quite find the time until now. And I must say, it was a lot easier to sort out than I thought it might be! I should point out that although this is an ASP.NET MVC 3 example, the concepts and the fact that this is mostly just JQuery means that it’s not limited to that, earlier versions of ASP.NET MVC can use happily, as can WebForms, PHP, Ruby and even Classic ASP!

Some things we’ll try and do in this blog post:

  • Setup a simple form with server-side validation of input fields which redirects to a ‘Success’ page or re-renders the form depending on whether it was successful or not.
  • Add JQuery validation for simple client side validation to the form.
  • Add Unobtrusive JavaScript support which will submit the form via AJAX.

Creating a basic application:

Firstly, I created a ASP.NET MVC 3 Web Application (Empty) in VS2010 and got to work updating the JavaScript libraries that were in it. This can be done via the NuGet Console, or by right clicking “References” in the Solution Explorer, “Add Library Reference” and then clicking the update side-tab. From there you can update all the default stuff.

Done that? Good. Next we’ll add a default controller, a view model to pass the data around & two views (one for allowing us to edit the form and the other as a success page). It’s worth noting that I’m doing nothing that special on these and that I’m using the default _Layout.cshtml to apply the header and footer as it sees fit.

/Controllers/BlackCoffeeController.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using System.Web.Mvc;
using UnobtrusiveAjaxExample.ViewModels.BlackCoffee;
 
namespace UnobtrusiveAjaxExample.Controllers
{
    public class BlackCoffeeController : Controller
    {
        [HttpGet]
        public ActionResult Rocks()
        {
            RocksViewModel viewModel = new RocksViewModel();
            return View(viewModel);
        }
 
        [HttpPost]
        public ActionResult Rocks(RocksViewModel viewModel)
        {
            if (!ModelState.IsValid) return View(viewModel);
            // Do something Database-y here.
            return View("Success");
        }
    }
}

/ViewModels/BlackCoffee/RocksViewModel.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
using System.ComponentModel.DataAnnotations;
 
namespace UnobtrusiveAjaxExample.ViewModels.BlackCoffee
{
    public class RocksViewModel
    {
        [Required]
        public string Forename { get; set; }
 
        [Required]
        public string Surname { get; set; }
 
        [Required]
        public string Message { get; set; }
    }
}

Then the two views, firstly: /Views/BlackCoffee/Rocks.cshtml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@model UnobtrusiveAjaxExample.ViewModels.BlackCoffee.RocksViewModel
 
@{
    ViewBag.Title = "Rocks";
}
<h2>Black Coffee Rocks?</h2>
<div id="content">
@Html.ValidationSummary()
@using(Html.BeginForm())
{
<ul>
	<li>
            @Html.LabelFor(x => x.Forename)
            @Html.EditorFor(x => x.Forename)
            @Html.ValidationMessageFor(x => x.Forename)
        </li>
	<li>
            @Html.LabelFor(x => x.Surname)
            @Html.EditorFor(x => x.Surname)
            @Html.ValidationMessageFor(x => x.Surname)
        </li>
	<li>
            @Html.LabelFor(x => x.Message)
            @Html.EditorFor(x => x.Message)
            @Html.ValidationMessageFor(x => x.Message)
        </li>
</ul>
<div><input name="Continue" type="submit" value="Continue" /></div>
}
</div>

And then /Views/BlackCoffee/Success.cshtml

1
2
3
4
5
@{
    ViewBag.Title = "Success";
}
<h2>Success</h2>
<p>Congratulations! You've successfully declared BLack Coffee as being totally rockin'!</p>

At this point now, you should be able to build and run your application and navigate to /BlackCoffee/Rocks and verify that the page redraws the form unless all boxes are filled in. If you do fill them all in, you should get the success page.

Adding JQuery Validation with barely any effort for standard Data Annotations.

With certain DataAnnotations such as the [Required] attribute and [StringLength], you should be able to get simple JQuery client side checks, which while not a replacement for server side checks, add some speedy feedback which will be especially welcomed by users who find themselves struggling over long distance or slow connections. The key point to note here is that the checks are performed both sides (client and server) – so it doesn’t matter if the user has JavaScript disabled or is using a browser not capable of running it – the checks will still get done. It’s just an added bonus.

To do, simply add references to the JavaScript files to your html’s <head> tag. In this case, I’m going to add them directly to the _Layout.cshtml file.

6
7
8
9
    <script src="@Url.Content("~/Scripts/jquery-1.6.1.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript">></script>
    <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>

You’ll spot that there are 4 included files there – the last one (the JQuery.unobtrusive-ajax.min.js) is for the next part – but we’ll put it in now in preparation.

You should find that the Web.Config file already has the following lines in already (specifically lines 10 & 11), but have a gander for the following and if it doesn’t exist or is set different to this, update the file appropriately.

8
9
10
11
12
<appSettings>
    <add key="webpages:Version" value="1.0.0.0"/>
    <add key="ClientValidationEnabled" value="true"/>
    <add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>

We’re now cooking with gas! Save, Build and try out your application. You should be able to spot that when clicking your submit button, the page doesn’t go away to the server at all to check the field validates, it’s doing it on the client. Good stuff!

Adding Unobtrusive AJAX into the mix.

This should be a relatively easy process, but there are a few things we need to consider sorting out before we continue too much further:

  • Update the views to make the Form work via AJAX (without breaking non-JavaScript/AJAX support)
  • Update the controller to detect whether the request is an AJAX request and if so, avoid sending the header / footer / other stuff back with it.

The first part is quite simple. Within the Rocks.cshtml we created earlier which is our edit form view, we used the HtmlHelper class to create the form tag. All we need to do now is change that to use the AjaxHelper class and pass in some options and we’re off to a winner!

10
@using(Ajax.BeginForm(new AjaxOptions() { HttpMethod = "Post", UpdateTargetId = "content" }))

You should be able to see there that there is AjaxOptions class “newed up” directly in the view. If you’re uncomfortable with doing this, you could create it directly in the view model and pass it in from there. There are a ton of options that you can go into, most of which are touched upon on Brad Wilson’s blog post on this subject (if you haven’t read Brad Wilson’s blog, you probably should add it to your reader – it’s exceptional and includes a good chuck of stuff relating to ASP.NET MVC and related topics). You’ll also spot we provide a UpdateTargetId – this represents the HTML element into which all the view result is going to get dumped into. In this case, our DIV on our Rocks.cshtml page – but this could be anything and in fact nothing, if you don’t want to spew out content back to the user for whatever reason.

If you ran the application now, you’d find that all the AJAX and the JQuery would work great, but as part of the Ajax Request, the header and footer would be returned and very soon you’d end up with a webpage that looks like it’s been designed by someone who’s been watching Inception too much. This thankfully (or more specifically thanks to the ASP.NET team), isn’t a problem as we can do a little check before returning the view while in the appropriate controller method. Using the example above, you’d be able to change it to something like this:

15
16
17
18
19
20
21
22
        [HttpPost]
        public ActionResult Rocks(RocksViewModel viewModel)
        {
            if (!ModelState.IsValid) return View(viewModel);
            // Do something Database-y here.
            if (Request.IsAjaxRequest()) return PartialView("Success");
            return View("Success");
        }

You’ll spot with this example we are returning exactly the same view. However, by returning it as a Partial view, we are ensuring it does not get rendered as part of a bigger page, so all of the headers / footers and other things included via layout pages are ignored.

Other things you can do to improve stuff:

There are a plenty of other very easy things you can add too, such as:

  • Loading image: Simply provide it with a content div to display while loading (and a timeout if you want) and in will show() that while that particular AJAX call is made. Meaning that if you want to, you can lock the UI or provide visual feedback that the users request is currently in progress.
  • There are four callback methods you can set for OnBegin, OnSuccess, OnFailure and OnCompleted which will trigger as appropriate. This allows you to add all sorts of extra functionality to the application in those instances you want to do more than simply “add some HTML to a div”. However, two things to note regarding these function calls:
    • The functions you declare should not live inside of the JQuery document.ready() method or other shorthand notation for that. Just plain functions in a .js file is fine (though, you can of course, still use JQuery – that’s not a problem).
    • You might find that the $(this) object within the JavaScript is not populated by the time you get to the methods. You can solve this to some degree by changing the following line from:
      244
      
              options.data.push({ name: "X-Requested-With", value: "XMLHttpRequest" });

      to:

      244
      245
      
              options.data.push({ name: "X-Requested-With", value: "XMLHttpRequest" });
              options.context = element;

      If I’m honest, I don’t know why this line is missing from the file in the first place. I can’t imagine it’s just been forgotten as it seems like such a key thing to be able to trigger events based on the click events (especially on pages where there are lots of controls which may call the AJAX request). I suspect there is a good reason – but I don’t know it yet.

  • You can use this on more than just <form> tags. For example, it’s just as easy to use the Ajax.ActionLink method which works in a very similar way and has some of your favourite overloads still available!
  • As mentioned at the top, this is mostly just JavaScript. If you wanted to do this with any other server side technology, all you’d need to do is replace the AjaxHelper methods with your own way of outputting the specific HTML “data-” based attributes and you’re up and running!

The full source code is available in a zip file here – though, as you can see above – it’s not a great deal different to the bog standard project!

1st March 2010

4 Top Tips for portable ASP.NET MVC Apps

Filed under: ASP.NET,CSS,HTML,MVC — Tags: , , , — Alex Holt @ 10:22 pm

Loooong cat! :O

ASP.NET MVC is awesome (find out how awesome it is over dinner) and allows for some great applications to be made, quickly, while at the same time offering a high degree of maintainability over the code that is written. The danger with being able to do things too fast is that simple mistakes are sometimes made. These hopefully are nothing major, but can become an irritation at various points down the line. One of the things that occasionally gets left behind is the portability of code – and this can be a bit of a ‘damn I wish I’d done it like that to start with’ moment.

Below are a few hints that may (or may not) help you as you develop the next great slice of awesomeness.

Disclaimer: These tips are displayed as ASP.NET MVC tips, but in reality, some of them progress to general ASP.NET Websites and Applications – or just websites in general.

  1. Don’t Assume You Know Your Root
    Before I get started, let me give some background on this point. I have recently been doing some final tweaks to an otherwise great MVC application. However, one of the tweaks I did was to make sure that part of the system was securely done via HTTPS. When looking around the net, this appeared to be a lot trickier than I thought. After all, could all these people be wrong?:

    Basically, yes they can, but only because their articles are dated, not because they are fools (it should also be noted that although their articles may be dated, there are some good techniques and ideas in them, so worth a nosey). :) Bart Wullems does a good job of explaining the amazing simplicity of this new attribute that was added in MVC 2 Preview 2. I’m a little surprised as to how this maybe wasn’t given a little bit more publicity – its a useful tool that was sorely missing before. Behold, ye [RequiresHttps] attribute!

     [RequireHttps]
     public ActionResult Login()
     {
     return View();
     }

    This addition of SSL feather to my MVC Application’s bow was to prove too much for Visual Studio’s Cassini and I was forced onto my local IIS. This in itself wasn’t a great issue, but it highlighted some issues with the way the application had been developed. It had been assumed from the start that the application would live at the root of its own domain. This is true for the production version of the system and was for the large part true of the development system. When moving to IIS however, the project was set to run as a Virtual Directory – meaning the website root was no longer the same as the application root. Which lead me to trawl through the entire application tweaking things here and there, just to make it work no matter where it lived. Don’t assume you know were your application will live! It might be any number of little requirement changes that could cause you to have to rethink how you are building your application.

  2. Use ActionLinks for linking within your application
    Doing this will save you a bunch of time and is one of the core supported features of ASP.NET MVC, so why not use it when it’s so simple? There are so many good articles and posts on this, a great starting point is (as always) ScottGu’s, which part way down talks about Constructing Outgoing URLs from the Routing System

    <%=Html.ActionLink("View more details", new { Controller = "Products", Action = "Details", Id=42 })%>

  3. Url.Content for content that is URLs.
    Url.Content is to static content, what ActionLink is to your dynamic pages. If you have any Images, CSS, Script files or basically anything else that isn’t an MVC page, then this little beaut’ is for you! This allows you to negate any issues with website roots and application roots changing – without having to monitor and check any links!

    Before, you may simply have done:

    <img src="/lolcats/longcat.png" alt="To scale" />

    This would have worked until your application was moved from the webroot (Cassini) to a virtual directory (e.g. “/MVCApp” in IIS). If you do the following however, all is solved as it works out the URL and writes that out accordingly:

    <img src="<%=Url.Content("~/lolcats/longcat.png")%>" alt="To scale" />

    Would appear as the below, automagically:

    <img src="/MVCApp/lolcats/longcat.png" alt="To scale" />

  4. Relative links within your CSS
    This is something that isn’t specifically unique to MVC applications or ASP.NET in general. It’s more a good practice / make sure you are aware of guideline.
    When coding stylesheets, you’re often faced with wanted to add background-image’s to them. Without the server-side jiggery pokery that ASP.NET (and the like) allows, you are left with limited choices how to do this. But in reality, the solution is fairly simple. You need to fix two things: The location of your Images and the location of your CSS. It doesn’t really matter where they are, but just that they are fixed (or you have the patience to correct your links should you wish to restructure).

    Images from a CSS can be HTTP, absolute to the web-root or, as is awesome, relative to the CSS itself. This means that as long as all your styles are entirely located within your stylesheet’s and not intermingled with your code, you’re on to a winner. It doesn’t matter which page calls the CSS, whether it be your homepage or one that is 42 levels deep – the links are only ever relative to the CSS page (which you included via Url.Content, right, eh? yeah!?).

    In the following example, the CSS is located within a ‘Styles’ directory directly at the project root.

    .longCat
    {
     background-image: url('../lolcats/longcat.png');
    }

Hopefully these pointers will help someone else, if not, they will hopefully protect against my own stupidity and making similar mistakes again. Feel free to comment below if there are any more thoughts and portability ideas you think I could do with including.

Older Posts »

Theme designed & built for Amadiere.com by Alex Holt. Powered by WordPress