jQuery rocks.  It makes it really easy to do cool stuff client side with JavaScript, like these cascading DropDowns (aka Select Lists).  But at the end of the day, jQuery is JavaScript, and it can still be tricky to work with.  One of these days, Visual Studio will treat JavaScript like a first class language and life will be much easier.  You’ll see that there isn’t much JavaScript here, but it took me several iterations to get this right.

I’ll start with the UI code and JavaScript.  If you want, you can read further and see the Controller code and more.

In my View, I have two DropDowns (Select Lists) and some JavaScript:

<p>
    Country:
    <%= Html.DropDownList("Countries", ViewData["Countries"] 
             as List<SelectListItem>) %>
</p>
<p>
    Region:
    <%= Html.DropDownList("Regions", new List<SelectListItem>()) %>
</p>

<script src="../../Scripts/jquery-1.3.2.js"></script>

<script type="text/javascript">
    $(function() {
        var countries = $("#Countries");
        var regions = $("#Regions");
        countries.change(function() {
            regions.find('option').remove();
            $.getJSON('/Home/Regions', { countryId: countries.val() }, function(data) {
                $(data).each(function() {
                    $("<option value=" + this.RegionId + ">" + this.RegionName + "</option>").appendTo(regions);
                });
            });
        });
    });
</script>

The Countries DropDown is pre-populated with data passed in ViewData. 

The second DropDown, Regions gets loaded when Countries changes.

Here’s how the JavaScript and jQuery stuff works…

First I get the two Select Lists, using jQuery and the ID as the selector (jQuery makes it easy!):

        var countries = $("#Countries");
        var regions = $("#Regions");

Next I wire up the change event on the Countries list to an anonymous function (jQuery makes it easy!):

        countries.change(function() {
        // ...
            });

Inside that function I do a few things.  First, find all options in the Region Select List and remove them:

            regions.find('option').remove();

Next I need to get the data for the second Select List. Guess what?  jQuery makes this easy too.  Using the getJSON() method, I supply the Controller and Action, as well as the Id of the country so I can get the correct regions.  I also declare a function to call when the JSON result comes back:

        $.getJSON('/Home/Regions', { countryId: countries.val() }, function(data) {
        // ...
        });

The last thing to do is load all of the results into the Select List.  This actually was the hardest thing to do but in the end it is very little code.  I tried using jQuery to create options and adding them to the select list.  I tried creating a list of options and setting the html value of the Select list.  I tried a bunch of stuff.  But this worked great… Iterate over the results with jQuery’s .each function and call a function for each iteration.  The function creates some dynamic html and appends it to the Region list.  I must admit, I was surprised this worked.  I’d assume that appending would put it after the select list (<select id=”Regions” />) but it actually put it inside it!

        $(data).each(function() {
            $("<option value=" + this.RegionId + ">" + this.RegionName + "</option>").appendTo(regions);
        });

That’s it!  It works great.  Of course there are more complex ways to do this, with caching etc.  This is just one way to accomplish the goal.

Here’s some code from the Controller that helps make it work.  Just remember, this is demo code.  I’m not too worried about separation of concerns and similar details. In a production app, I’d be calling more services!

In the Index Action (in this sample the Select Lists are in my Index View) I load the countries list into ViewData.  Again, this is a demo and that may not be the best practice.

    public ActionResult Index()
    {
        ViewData["Countries"] = GetCountries();
        return View();
    }

    private List<SelectListItem> GetCountries()
    {
        List<SelectListItem> countries =
            _countryList.Select(c => new SelectListItem {Text = c.CountryName, Value = c.CountryId.ToString()}).ToList();
        countries.Insert(0, new SelectListItem{ Text="", Value = "0"});
        return countries;
    }

Then I have a Regions Action that returns the JSON result with the values to add to my Regions Select List:

    [AcceptVerbs(HttpVerbs.Get)]
    public ActionResult Regions(int countryId)
    {
        return Json(_regionList.Where(r => r.CountryId == countryId).Select(r =>
                                                                            new
                                                                                {
                                                                                    r.RegionName,
                                                                                    r.RegionId
                                                                                }));
    }

 

That covers most of it.  Happy coding.

Technorati Tags: , ,

When using strongly typed views, don’t name the controller action arguments with the same name as another form value!


I’ve been working with ASP.NET MVC for a couple of months now.  It is really pretty awesome.  It’s worked so well, I haven’t had much to blog about!  The other day I ran into an issue so I’m sharing the solution.   MVC will “automagically” bind the parameters of a controller action based on the values in the form.  And if your View is strongly typed and your controller action has a parameter of that same type, it will bind it too.  But in my case, the parameter was null.  MVC wasn’t loading it. And there was no exception to help me out.


Here’s a simple demo, I’m not showing every line of code…


 


Typical for an MVC application, I have a view that is strongly typed:

<%@ Page Title=”” Language=”C#” MasterPageFile=”~/Views/Shared/Site.Master”
Inherits=”System.Web.Mvc.ViewPage<OrganizationRole>” %>

 


The View has a simple form which includes two text boxes:

<p>
<label for=”OrganizationName”>OrganizationName:</label>
<%= Html.TextBox(“OrganizationName”) %>
<%= Html.ValidationMessage(“OrganizationName”, “*”) %>
</
p>
<
p>
<label for=”Role”>Role:</label>
<%= Html.TextBox(“Role”) %>
<%= Html.ValidationMessage(“Role”, “*”) %>
</
p>

 


A button on the form posts back to the controller, calling the Create Action.  Here is Action Code:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(OrganizationRole role)
{
// Do Something Here…
return View();
}

In the screenshot below, you can see that when I debug the app, the role parameter has not been loaded.


image


The fix was simple but it took a while to figure it out!  All I had to do was re-name the parameter from “role” to “organizationRole”:


[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(OrganizationRole organizationRole)
{
    // Do Something Here…
    return View();
}


You see, I was being lazy and abbreviated the argument’s name.  That is ok, you can name the parameter almost anything you want.  But I gave the parameter the same name as one of the other form variables!  Notice above that my form has a text box named “Role”!  MVC tried to load the values of my parameters – it takes each of the posted values from the form (“OrganizationName” and “Role”) and tries to match them up with arguments with the same names (it is not case sensitive) if they exist.  It also tries to load the entire form value (strongly typed as the class OrganizationRole) to the argument of type OrganizationRole, if one exists.  But an argument of type OrganizationRole with the name “Role” screws the who thing up!  The only problem is that it doesn’t throw any exceptions.  Anyway, I changed the name and presto, it works.

It’s hard to keep up with posting these photos of Ben.  Time flies.  Lots more news since my last blog post.  First of all, Ben had his 1st birthday!  His grandma made him an awesome cake (and cupcakes) and they were a big hit. 

Ben is really trying to gain some weight (he’s a on the small side).  The Dr. put him on a “butter” diet, telling us to put butter on everything he eats.  Somehow he got the message.  All of a sudden he started eating everything in sight.  He gained 1 lb in 6 weeks.  Then he stopped eating again and got really finicky and cranky.  After a few days Rebecca took him to the Dr. to find out that he had an ear infection!  After a day or 2 of antibiotics, he was back to eating again.  He’s a pretty funny eater.  One day he’ll be eating Brussels sprout (yes, spelled with an “s” at the end, I looked it up), broccoli, meatloaf, spaghetti and meat sauce, salmon, and more.  It’s like he loves all different flavor foods.  And the next day, he’s bored of it all and won’t eat anything!

Right around the time of the ear infection Benny developed another ailment, much to our dismay.  He’s become a bit of a “momma’s boy”!  All he wants is for his mommy to hold him.  It’s pretty funny too because if it’s just me and him hanging out, it’s all good. He laughs and plays and is perfectly content.  But when Rebecca comes in the room, he starts to get cranky and he just wants her.  I’m sure this is pretty typical behavior for a kid his age.  For me, it’s a little insulting – “what, I’m not good enough for you?”.  But for Rebecca it is just plain annoying because she can’t get anything done when he is around.  This too shall pass.

We’ve had a few other big achievements lately.  Ben started taking some steps on his own.  Still just 2 or 3 at a time, but people say once it starts, he’ll be walking soon enough.  He also has increased his vast vocabulary to 3 words.  In addition to “momma” and “dadda”, he now says “dog”.  Well, more like “daw daw” but we are impressed.  It’s funny too because we don’t have a dog.  But he gets excited when he sees them on TV or out walking around, or at friends’ houses.

OK, as usual, here are some recent photos…

No, that first one isn’t Ben, but a classic just the same.  Big Steve eating Chicken Holiday!  Below are pictures of ben playing, at the park with Grandma, and showing off his new “Vail” shirt (he wants to go skiing there next year!).  Also, three classic “messy face” pictures.  The first is Ben eating his 1st Birthday Cake (his first sugar fix ever).  I think he liked it because you can see him eating his friend Ricky’s cake too (with the red icing).  Think he enjoyed it?  And there’s another with him covered in Oreo cookie!  Don’t worry, he eats a lot of veggies and fruit too!

 DSC03995 DSC04006 DSC04023 DSC04036 DSC04037 DSC04045 DSC04062 DSC04072

My blog has been pretty quiet lately.  Things got a little hectic in mid February. 

More new technology:

After struggling to get the hang of Silverlight for a while, I was really starting to get comfortable with it.  Development on my project was moving along, the client was liking the results, and I was learning a lot!  Just when things were going well, my client informed me that he’d be dropping the project (hopefully temporarily) due to financial issues.  I was disappointed for many reasons.  I felt bad for the client (this economy is hurting a lot of people) and I felt bad for me, I had to find another client without much notice.

Lucky for me, I was able to get started on a new project pretty quickly.  I was very excited to dive into ASP.Net MVC too!  But from a blogging perspective, it meant another shift in direction.  I had been trying to focus on one thing and blog about it a lot.  I like the fact that my blog isn’t tied to a particular technology, but it is fun to get good at something and share information.  Oh well.  The fact is, I have been very lucky lately regarding new technology.  I was fortunate to start using VS2008/.Net 3.5 during the Beta at Orbius (lots of LINQ to SQL), then Silverlight 2 for my next client (and lots more LINQ to SQL) and now I’m doing ASP.Net MVC with jQuery, Dependency Injection, and other related stuff (and still lots more LINQ to SQL!) in my current situation.

What to blog about?

So now, no more Silverlight posts (unless I find some time to play around with Silverlight 3 which I am very excited about).  But I hope to continue blogging about what I am learning now.  There is one problem.  I typically try to blog about something that I struggled with and then resolved, hoping to spare others the frustration.  That was easy with Silverlight 2 which I thought was sort of painful to use (but I enjoyed it and liked the result).  But MVC doesn’t seem to be like that.  The switch to ASP.Net MVC was pretty easy for me.  And it seems to work pretty well.  The basics are pretty simple, in many ways less confusing that ASP.Net web forms, and I haven’t had too many issues yet.  Could it be that MVC really is the right way to go?  So far, it seems that way.  As I dig in more, I’m sure I’ll find plenty of blog worthy material.  As a matter of fact, I already have one, to be posted soon.

Business Update:

I’ve been pretty busy and haven’t been focusing on the “business side” of business.  A lot of independent consultants aren’t sure how to set up a business and I promised to write about it.  Here’s a quick update… I had debated back and forth about incorporating by forming an LLC or S-Corp.  I spoke with a lot of people including some accountants.  In the end, it seemed that there was no need to rush.  I had a client that didn’t care.  So I started to operate as a sole proprietor.  However, as a sole proprietor you can operate in several ways.  You can just mix up all of your personal and business money and confuse everything.  Or you can be a sole proprietor and act like a business.  That is what I am doing.  I have separate bank accounts and check books, I got a business credit card, and I record all of my income and expenses in QuickBooks.  Also, being a sole proprietor, I learned that you can also “do business as” some other name. It’s called DBA (not like a database).  This is a good idea for someone like me, since I do already have the my web site, blog and email on the domain IngenuityNow.net.  You don’t need to actually be incorporated to use a business name!

I also looked into insurance and learned about liability and E and O (Errors and Omissions) insurance.  You need liability so you can’t get sued if you knock over a server rack at a client, or a client falls walking into your house (nope, personal insurance doesn’t cover that).  E and O is to cover you if you screw up an application, trash a database, or find some other way to ruin a client’s business.  From talking to a lot of people, it seems that E and O isn’t so popular and most people only get it if the client insists.  It is also pretty expensive.  Liability insurance is much cheaper and seems like a good idea.

I also set up a web site and got business cards.  A little marketing goes a long way towards professionalism!  The web site is pretty simple so far but it will grow in time.  Please let me know what you think.

So what is next on the business front?  I’ve got to keep the networking up.  There are lots of clients out there, we just need to find them!  I also plan to get the incorporation thing going.  There are some good benefits to it (for taxes and liability) and I have spoken with a few clients that won’t work with you without being incorporated (although I know many consultants who never incorporate).  My only pain point so far on all of this is the accounting stuff.  QuickBooks helps, but it isn’t that easy to use if you don’t grok all of the accounting concepts, so I have a lot to learn