Sunday, June 30, 2013

jQuery: When Hide Doesn't Hide

I was recently working on a project and the requirement was basically this: A user can have up to five emergency contacts. This was a MVC project. My line of thinking was this....

-The main view model has a property List<EmergencyContactViewModel>.
-EmergencyContactViewModel contained props for name, relationship, home phone, work phone.
-When displaying this in edit mode, there would always be at least one emergency contact.

Given that, you know that you had 4 more contacts to add to the form. I thought, no problem, just add all the fields and then hide them. To my surprise, that did not work. That is the center of this posting.

Here is the abbreviated view:

<div>
   <ul>
      <li><a href="#tabs-1">My Information</a></li>
      <li><a href="#tabs-2">Emergency Contact</a></li>
      <li><a href="#tabs-3">Federal Tax</a></li>
      <li><a href="#tabs-4">State Tax</a></li>
      <li><a href="#tabs-5">Change Request</a></li>
   </ul>
   <div id="tabs-1">
   </div>
   <div id="tabs-2">
   </div>
   <div id="tabs-3">
   </div>
   <div id="tabs-4">
   </div>
   <div id="tabs-5">
      @using (Html.BeginForm())
      {
         <table id="changeRequest">
            <tr>
               <td>Emploee ID</td>
               <td>@Html.TextBoxFor(x => x.MyInfo.EmployeeId)</td>
               <td>Address</td>
               <td>@Html.TextBoxFor(x => x.MyInfo.Address&lt/td>
               <td></td>
               <td></td>
            </tr>
            <tr>
               <td>Last Name</td>
               <td>@Html.TextBoxFor(x => x.MyInfo.LastName)</td>
               <td></td>
               <td><input type="text"></td>
               <td></td>
               <td></td>
            </tr>
            <tr>
               <td>First</td>
               <td>@Html.TextBoxFor(x => x.MyInfo.FirstName)</td>
               <td></td>
               <td><input type="text"></td>
               <td></td>
               <td></td>
            </tr>
            <tr>
               <td>Middle</td>
               <td>@Html.TextBoxFor(x => x.MyInfo.MiddleName)</td>
               <td>City</td>
               <td>@Html.TextBoxFor(x => x.MyInfo.City)</td>
               <td></td>
               <td></td>
            </tr>
            <tr>
               <td>Email</td>
               <td>@Html.TextBoxFor(x => x.MyInfo.Email)</td>
               <td>State</td>
               <td>@Html.TextBoxFor(x => x.MyInfo.State)</td>
               <td></td>
               <td></td>
            </tr>
            <tr>
               <td></td>
               <td></td>
               <td>Zip Code</td>
               <td>@Html.TextBoxFor(x => x.MyInfo.ZipCode)</td>
               <td></td>
               <td></td>
            </tr>
            <tr>
               <td></td>
               <td></td>
               <td>Phone 1</td>
               <td>@Html.TextBoxFor(x => x.MyInfo.Phone1)</td>
               <td></td>
               <td></td>
            </tr>
            <tr>
               <td></td>
               <td></td>
               <td>Phone 2</td>
               <td>@Html.TextBoxFor(x => x.MyInfo.Phone2)</td>
               <td></td>
               <td></td>
            </tr>
            <tr>
               <td><input type="button" id="addContact" value="Add Contact" /></td>
            </tr>
            <tr>
               <td>Contact</td>
               <td>Relationship</td>
               <td>Home Phone</td>
               <td>Work Phone</td>
            </tr>
            @for (var i = 0; i < Model.EmergencyContacts.Count; i++)
            {
               <tr>
                  <td>@Html.TextBoxFor(x => x.EmergencyContacts[i].ContactName)</td>
                  <td>@Html.TextBoxFor(x => x.EmergencyContacts[i].Relationship)</td>
                  <td>@Html.TextBoxFor(x => x.EmergencyContacts[i].HomePhone)</td>
                  <td>@Html.TextBoxFor(x => x.EmergencyContacts[i].WorkPhone)</td>
               </tr>
            }
         </table>
         <input type="submit" value="Submit" />
      }
   </div>
</div>


A few things to point out...
Yes the for loop should be removed and be replaced with an Editor Template. However, this was the standard and how they did things so just keeping in line.

The easiest solution would be that since an employee can have up to five emergency contacts, just render all the fields right out of the gate. Afterall, this is in Edit mode, however, in this post we are going to be doing it dynamically.

Let's take a look at the form...


To do this dynamically, we will need to test for the existence of other rows since an employee can have up to five emergency contacts. If the row exists, of course, don't add. If the row doesn't exist, add a new row:

if ($('#EmergencyContacts_1__ContactName').length < 1) {
   $('#changeRequest > tbody:last').append('<tr id="contact1">' +
      <td><input name="EmergencyContacts[1].ContactName" id="EmergencyContacts_1__ContactName" +
      type="text" /><td> +
      <td>< input name="EmergencyContacts[1].Relationship" id="EmergencyContacts_1__Relationship" +
      type="text" /><td> +
      <td>< input name="EmergencyContacts[1].HomePhone" = id="EmergencyContacts_1__HomePhone" +
      type="text" /><td> +
      <td>< input name="EmergencyContacts[1].WorkPhone" = id="EmergencyContacts_1__WorkPhone" +
      type="text" /><td>
   );
}

if ($('#EmergencyContacts_2__ContactName').length < 1) {
   $('#changeRequest > tbody:last').append('<tr id="contact2">' +
      <td><input name="EmergencyContacts[2].ContactName" id="EmergencyContacts_2__ContactName" +
      type="text" /><td> +
      <td>< input name="EmergencyContacts[2].Relationship" id="EmergencyContacts_2__Relationship" +
      type="text" /><td> +
      <td>< input name="EmergencyContacts[2].HomePhone" = id="EmergencyContacts_2__HomePhone" +
      type="text" /><td> +
      <td>< input name="EmergencyContacts[2].WorkPhone" = id="EmergencyContacts_2__WorkPhone" +
      type="text" /><td>
   );
}

if ($('#EmergencyContacts_3__ContactName').length < 1) {
   $('#changeRequest > tbody:last').append('<tr id="contact3">' +
      <td><input name="EmergencyContacts[3].ContactName" id="EmergencyContacts_3__ContactName" +
      type="text" /><td> +
      <td>< input name="EmergencyContacts[3].Relationship" id="EmergencyContacts_3__Relationship" +
      type="text" /><td> +
      <td>< input name="EmergencyContacts[3].HomePhone" = id="EmergencyContacts_3__HomePhone" +
      type="text" /><td> +
      <td>< input name="EmergencyContacts[3].WorkPhone" = id="EmergencyContacts_3__WorkPhone" +
      type="text" /><td>
   );
}

if ($('#EmergencyContacts_4__ContactName').length < 1) {
   $('#changeRequest > tbody:last').append('<tr id="contact4"> +
      <td><input name="EmergencyContacts[4].ContactName" id="EmergencyContacts_4__ContactName" +
      type="text" /><td> +
      <td>< input name="EmergencyContacts[4].Relationship" id="EmergencyContacts_4__Relationship" +
      type="text" /><td> +
      <td>< input name="EmergencyContacts[4].HomePhone" = id="EmergencyContacts_4__HomePhone" +
      type="text" /><td> +
      <td>< input name="EmergencyContacts[4].WorkPhone" = id="EmergencyContacts_4__WorkPhone" +
      type="text" /><td>
   ');
}


Now it seems the next thing to do would be to add code to hide those table rows and handle the button click event as such:

$('#contact1').hide();
$('#contact2').hide();
$('#contact3').hide();
$('#contact4').hide();

$('#addContact').click(function() {
   $('#contact1').show();
   $('#contact2').show();
   $('#contact3').show();
   $('#contact4').show();
});


Let's go take a look at the result...



The rows are not hidden. The solution is rather simple. All that is needed is to add the visibility attribute with a value of hidden to each table row. For example:

$('#changeRequest > tbody:last').append('<tr id="contact1" style="visibility: hidden;">'


The next step is to handle the click event for the Add Contact button. For each row, change the visibility attribute value to visible, then hide it, then fade in. It may seem odd to show the table row and then hide it again. This is done so we can apply the fade in effect. If you omit hiding the second time, all the fields will just pop in immediately. Of course that is fine, we just want to show a smooth transition:

$('#addContact').click(function () {
   $('#contact1').css('visibility', 'visible').hide().fadeIn('slow');
   $('#contact2').css('visibility', 'visible').hide().fadeIn('slow');
   $('#contact3').css('visibility', 'visible').hide().fadeIn('slow');
   $('#contact4').css('visibility', 'visible').hide().fadeIn('slow');
});


When the page loads, the fields should be hidden...


Then when Add Contact is clicked, the fields should fade in nicely...

Friday, June 28, 2013

HTML Tables: Splitting Cells

Today is an examination of building a table that is not so straightforward. At times, you may need to split header rows or table cells to display data in a certain way. This post will tackle how to create such a table. I am not a CSS wizard by any means but the styling is reasonably close.

Normally I like to provide explanations for what is going on. Given that this is a rather lengthy post, I am going to omit that this time. This should be looked at as a template of how to build a more complex table. If someone actually wants to hear the rational, just let me know.

Let's break this in to several chunks just to see the code a little bit more clearly. Of course, all of the code will be in a table tag. The style used for the table is width 977px and margin-top 10px. First, let's look at the header.

   <tr class="trHeader">
      <td class="tdNoStyle"></td>
      <td rowspan="2" style="width: 157px;">Pizza</td>
      <td rowspan="3" style="width: 157px;">Assetts You May Give</td>
      <td colspan="2" style="width: 269px;">Your bake if you eat</td>
      <td rowspan="3" style="width: 253px;">Expectations & Exceptions</td>
   </tr>
   <tr class="trHeader">
      <td class="tdNoStyle"></td>
      <td rowspan="2" style="width: 137px; vertical-align: bottom">In-House</td>
      <td rowspan="2" style="width: 131px; vertical-align: bottom">Out-Of-House</td>
   </tr>
   <tr class="trHeader">
      <td class="tdNoStyle"></td>
      <td rowspan="2" style="width: 157px;">Planned Event</td>
   </tr>
   <tr class="trHeader">
      <td class="tdNoStyle"></td>
      <td style="width: 293px;"></td>
      <td style="width: 137px;">Provisions</td>
      <td style="width: 131px;">Provisions</td>
      <td style="width: 253px;"></td>
   </tr>


The first section:

   <tr>
      <td></td>
      <td class="col1bkGrnd">If you meant pizza</td>
      <td class="rowStyle1">Pizza/Sandwich options and services</td>
      <td class="rowStyle1">$20 slice*</td>
      <td class="rowStyle1">30% sandwich</td>
      <td class="rowStyle1">-----none-----</td>
   </tr>
   <tr>
      <td></td>
      <td class="col1bkGrnd">pizza, sandwich</td>
      <td class="rowStyle5">Pizza/Sandwich options and services</td>
      <td class="rowStyle5">20% insurance</td>
      <td class="rowStyle5">30% insurance</td>
      <td class="rowStyle5">-----none-----</td>
   </tr>
   <tr>
      <td></td>
      <td rowspan="2" class="col1bkGrnd">toppings or veggies</td>
      <td class="rowStyle4"></td>
      <td class="rowStyle4"></td>
      <td class="rowStyle4"></td>
      <td class="rowStyle4"></td>
   </tr>
   <tr>
      <td></td>
      <td class="rowStyle1">Pizza/Sandwich options and services</td>
      <td class="rowStyle1">$20 slice*</td>
      <td class="rowStyle1">30% sandwich</td>
      <td class="rowStyle1">-----none-----</td>
   </tr>
   <tr>
      <td></td>
      <td class="col1bkGrnd, col1BrdrBtm">needs</td>
      <td class="rowStyle4">Pizza/Sandwich options and services</td>
      <td class="rowStyle4">20% insurance</td>
      <td class="rowStyle4">30% insurance</td>
      <td class="rowStyle4">-----none-----</td>
   </tr>



The second section:

   <tr>
      <td></td>
      <td class="col1bkGrnd"></td>
      <td class="rowStyle1">Premium slices and sandwiches are highly recommended</td>
      <td class="rowStyle1">$20 slice*</td>
      <td class="rowStyle1">30% insurance</td>
      <td class="rowStyle1">-----none-----</td>
   </tr>
   <tr>
      <td></td>
      <td rowspan="2" class="col1bkGrnd">For a private visit</td>
      <td class="rowStyle4">Special visit</td>
      <td class="rowStyle4">$20 slice*</td>
      <td class="rowStyle4">30% insurance</td>
      <td class="rowStyle4">-----none-----</td>
   </tr>
   <tr>
      <td></td>
      <td class="rowStyle3"></td>
      <td class="rowStyle3">Artichoke: Not</td>
      <td class="rowStyle3">Artichoke: Not</td>
      <td class="rowStyle3"></td>
   </tr>
   <tr>
      <td></td>
      <td class="col1bkGrnd">and private tour</td>
      <td class="rowStyle3">Special visit and tour</td>
      <td class="rowStyle3">included</td>
      <td class="rowStyle3">included</td>
      <td class="rowStyle3">-----none-----</td>
   </tr>
   <tr>
      <td></td>
      <td class="col1bkGrnd">or show</td>
      <td class="rowStyle3"></td>
      <td class="rowStyle3">Pepperoni: $20</td>
      <td class="rowStyle3">Pepperoni: 30%</td>
      <td class="rowStyle3"></td>
   </tr>
   <tr>
      <td></td>
      <td class="col1bkGrnd"></td>
      <td class="rowStyle1"></td>
      <td class="rowStyle1">slice*</td>
      <td class="rowStyle1">insurance</td>
      <td class="rowStyle1"></td>
   </tr>
   <tr>
      <td></td>
      <td class="col1bkGrnd"></td>
      <td class="rowStyle4">Preventive damage/death/dismemberment</td>
      <td class="rowStyle4">No charge</td>
      <td class="rowStyle4">30% insurance</td>
      <td class="rowStyle4">-----none-----</td>
   </tr>




The third section:

   <tr>
      <td></td>
      <td rowspan="2" class="col1bkGrnd">If you more pizza to</td>
      <td class="rowStyle3"></td>
      <td class="rowStyle3">Preferred: $10</td>
      <td class="rowStyle3"></td>
      <td class="rowStyle3"></td>
   </tr>
   <tr>
      <td></td>
      <td class="rowStyle3"></td>
      <td rowspan="2" class="rowStyle3">slice* at retail </td>
      <td class="rowStyle3"></td>
      <td class="rowStyle3"></td>
   </tr>
   <tr>
      <td></td>
      <td class="col1bkGrnd">treat your addiction</td>
      <td class="rowStyle3"></td>
      <td class="rowStyle3">30% insurance</td>
      <td rowspan="2" class="rowStyle3">31 day supply retail/93 day supply</td>
   </tr>
   <tr>
      <td></td>
      <td rowspan="2" class="col1bkGrnd">condition</td>
      <td rowspan="2" class="rowStyle3">Premium pizza</td>
      <td class="rowStyle3">slice* at mail</td>
      <td rowspan="2" class="rowStyle3">at retail, mail not</td>
   </tr>
   <tr>
      <td></td>
      <td rowspan="2" class="rowStyle3">Non-preferred: $45</td>
      <td rowspan="2" class="rowStyle3">mail order</td>
   </tr>
   <tr>
      <td></td>
      <td class="col1bkGrnd"></td>
      <td class="rowStyle3"></td>
      <td rowspan="2" class="rowStyle3">covered</td>
   </tr>
   <tr>
      <td></td>
      <td class="col1bkGrnd"></td>
      <td class="rowStyle3"></td>
      <td class="rowStyle3">slice* at retail, $90</td>
      <td class="rowStyle3"></td>
   </tr>
   <tr>
      <td></td>
      <td rowspan="2" class="col1bkGrnd">More information</td>
      <td class="rowStyle1"></td>
      <td class="rowStyle1">slice* at mail</td>
      <td class="rowStyle1"></td>
      <td class="rowStyle1"></td>
   </tr>
   <tr>
      <td class="rowStyle2"></td>
      <td class="rowStyle2"></td>
      <td class="rowStyle2"></td>
      <td class="rowStyle2"></td>
      <td class="rowStyle2"></td>
   </tr>
   <tr>
      <td></td>
      <td class="col1bkGrnd">about pizza</td>
      <td rowspan="2" class="rowStyle2">Preferred pizza</td>
      <td class="rowStyle2">$15 slice at retail,</td>
      <td class="rowStyle2"></td>
      <td class="rowStyle2"></td>
   </tr>
   <tr>
      <td></td>
      <td rowspan="2" class="col1bkGrnd">pizza addiction</td>
      <td rowspan="2" class="rowStyle2">$30 slice* at mail</td>
      <td class="rowStyle2"></td>
      <td class="rowStyle2"></td>
   </tr>
   <tr>
      <td class="rowStyle2"></td>
      <td class="rowStyle2"></td>
      <td class="rowStyle2"></td>
      <td class="rowStyle2"></td>
   </tr>
   <tr>
      <td></td>
      <td class="col1bkGrnd">available at www</td>
      <td class="rowStyle2"></td>
      <td class="rowStyle2"></td>
      <td class="rowStyle2"></td>
      <td class="rowStyle2"></td>
   </tr>
   <tr>
      <td></td>
      <td class="col1bkGrnd">.pizzaproblem.com</td>
      <td class="rowStyle4"></td>
      <td class="rowStyle4"></td>
      <td class="rowStyle4"></td>
      <td class="rowStyle4"></td>
   </tr>
   <tr>
      <td></td>
      <td class="col1bkGrnd">/public/pizza</td>
      <td class="rowStyle3"></td>
      <td rowspan="2" class="rowStyle3">$45 slice* at retail</td>
      <td class="rowStyle3"></td>
      <td class="rowStyle3"></td>
   </tr>
   <tr>
      <td></td>
      <td rowspan="2" class="bol1bkGrnd">addiction/help</td>
      <td rowpsan="2" class="rowStyle3">Non-Preferred pizza</td>
      <td class="rowStyle3"></td>
      <td class="rowStyle3"></td>
   </tr>
   <tr>
      <td></td>
      <td rowspan="2" class="rowStyle3">$10 copay* at mail</td>
      <td class="rowStyle3"></td>
      <td class="rowStyle3"></td>
   </tr>
   <tr>
      <td></td>
      <td rowspan="2" class="rowStyle3">/morepizza/index.</td>
      <td class="rowStyle3"></td>
      <td class="rowStyle3"></td>
      <td class="rowStyle3"></td>
   </tr>
   <tr>
      <td></td>
      <td class="rowStyle3"></td>
      <td class="rowStyle3"></td>
      <td class="rowStyle3"></td>
      <td class="rowStyle3"></td>
   </tr>
   <tr>
      <td></td>
      <td class="col1bkGrnd">html.</td>
      <td class="rowStyle1"></td>
      <td class="rowStyle1"></td>
      <td class="rowStyle1"></td>
      <td class="rowStyle1"></td>
   </tr>
   <tr>
      <td></td>
      <td class="col1bkGrnd"></td>
      <td class="rowStyle2"></td>
      <td class="rowStyle2"></td>
      <td class="rowStyle2">30% insurance</td>
      <td rowspan="2" class="rowStyle2">$400 minimum order</td>
   </tr>
   <tr>
     <td></td>
     <td class="col1bkGrnd"></td>
     <td rowspan="2" class="rowStyle2">Specialty pizza</td>
     <td rowspan="2" class="rowStyle2">20% insurance</td>
     <td rowspan="2" class="rowStyle2">at retail, mail not</td>
   </tr>
   <tr>
     <td></td>
     <td class="col1bkGrnd"></td>
     <td rowspan="2" class="rowStyle4">per month</td>
   </tr>
   <tr>
     <td></td>
     <td class="col1bkGrnd, col1BrdrBtm"></td>
     <td class="rowStyle4"></td>
     <td class="rowStyle4"></td>
     <td rowspan="2" class="rowStyle4">covered</td>
   </tr>




And the CSS classes:

.trHeader {
   background: #A9A9A9;
}

.thHeader > .tdNoStyle {
   border: none;
   background-color: rgb(239, 238, 239) !important;
}

.trHeader > td {
   border-left: #C0C0C0 1px solid;
   border-right: #C0C0C0 1px solid;
   padding-left: 5px;
}

.btnBorderHeader {
   border-bottom: #C0C0C0 1px solid;
}

.col1bkGrnd {
   background: #C0E8FB;
   padding-left: 5px;
   border-left: #70AFD9 1px solid;
   border-right: #70AFD9 1px solid;
}

.col1BrdrBtm {
    background: #C0E8FB;
    padding-left: 5px;
    border-left: #70AFD9 1px solid;
    border-right: #70AFD9 1px solid;
    border-bottom: #C0E8FB 1px solid;
    border-bottom: #70AFD9 1px solid;
}

.rowStyle1 {
    border-right: #70AFD9 1px solid;
    border-bottom: #70AFD9 1px solid;
    background: #EFF9FF;
    padding-left: 5px;
}

.rowStyle2 {
    border-right: #70AFD9 1px solid;
    vertical-align: bottom;
    padding-left: 5px;
}

.rowStyle3 {
    background: #EFF9FF;
    border-right: #70AFD9 1px solid;
    padding-left: 5px;
}

.rowStyle4 {
    border-bottom: #70AFD9 1px solid;
    border-right: #70AFD9 1px solid;
    padding-left: 5px;
}

.rowStyle5 {
    border-right: #70AFD9 1px solid;
    padding-left: 5px;
}

Monday, June 3, 2013

jQuery Modal Dialog & Scrolling

Recently I was loading some documents into a jQuery modal dialog. Everything was going well until I added content to the dialog and all of a sudden, when running the page and opening the dialog, it would scroll to the bottom of the document. Not sure what causes this but someone suggested it may be caused due to a link.

Now to fix that annoying behavior...

The element clicked to cause the dialog to open:
<div id=tabs">
   <a href="#" class="modal">The Modal</a>
</div>
We have a div that contains the contents of the modal:
<div id="modalContent">
   // content here
</div>

At the top of that div, sneak in another div that contains a link, this is going to be the target that is set in the modal dialog:
<div id="modalContent">
   <div id="topPosition">
      <a href="#" class="ui-dialog-relative">&nbsp;</a>
   </div>
   // other modal content
</div>

The jQuery:
$('a.modal').click(function (e) {
   e.preventDefault();
   $('#modalContent').dialog({
      modal: true,
      autoOpen: false,
      width: 1100,
      buttons: {
         Print: function () {
            window.print();
         },
         Close: function () {
            $(this).dialog("close");
         }
      },
      open: function () {
         $('.ui-dialog-relative :link').blur();
         $('#topPosition').focus();
      },
      focus: function (event, ui) {
         $('#topPosition').focus();
      }
   });

   $('#modalContent').dialog('open');
});

The key is to hook into the ui-dialog-relative href and give that the focus when the dialog opens. Calling blur ensures that the link itself is not visible.

This did solve the initial problem, however going back to this a few days later I removed the open and focus functions from the dialog settings and things worked. Strange but initially it did solve the problem.

Sunday, June 2, 2013

Cannot Attach the File as Database...

Short post this time.

"Cannot attach the file as database....". I came across this error when rolling Membership into EF Code First. Searching, of course, led to Stack Overflow. Most of the answers were saying to drop and re-create the database. However this did not fit my situation as the database was not even created!

The solution was rather simple. Right click the App_Data folder and add a brand new (empty) database and run the solution again.

As a side note, it is quite common to get another error dealing with the database initialization. Your initialization code needs to run before the database is accessed. A good place to do that is in Application_Start in Global.asax.

protected void Application_Start()
{
   Web.Security.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
}

Of course another place to put that line of code is in OnModelCreating of your DbContext class.

Sunday, May 5, 2013

ASP.NET MVC, jQuery, Checkboxes, Tables, JSON

In this post we will be looking at the following:
1). Creating and populating a HTML table.
2). Clicking a button in the table, causing it to check a checkbox.
3). Clicking button outside of table, triggering a modal dialog to be loaded.
4). Send data back to the controller based on which checkbox was checked.
5). Send the data as text and then send it as JSON.

Here is what we are building, the main screen:


When a user clicks the Notify button off to the right, the checkbox in that row should be checked. Note in the screenshot Leonard and Raj are selected.


The user will click the Send Notifications button after they have made all of their selections. This will trigger a modal dialog to appear on the screen. The dialog will be populated with the email address of the selected/checked row in the table. The user can then fill out the body and reason, then have the email sent.


Spin up a new MVC project. Add a PersonViewModel class to the models folder:
public class PersonViewModel
{
   public int PersonId { get; set; }
   public string FirstName { get; set; }
   public string LastName { get; set; }
   public string Age { get; set; }
   public string FavoriteFood { get; set; }
   public string Email { get; set; }
}

In the HomeController, delete the view. We will create a method to give us some data to play with. We will come back to the view in a moment.
public ActionResult Index()
{
   List<PersonViewModel> people = GetPeople();
   return View(people);
}

private static List<PersonViewModel> GetPeple()
{
   return new List<PersonViewModel>()
   {
      new PersonViewModel() { PersonId = 1, FirstName = "Sheldon", LastName = "Cooper", Age = "35", FavoriteFood = "Greek Food", Email = "sheldon@bigbang.com" }, 
      new PersonViewModel() { PersonId = 2, FirstName = "Leonard", LastName = "Hoffstadter", Age = "35", FavoriteFood = "Cheese", Email = "leonard@bigbang.com" },
      new PersonViewModel() { PersonId = 3, FirstName = "Raj", LastName = "Koothrappali", Age = "35", FavoriteFood = "Indian Food", Email = "raj@bigbang.com" },
      new PersonViewModel() { PersonId = 4, FirstName = "Howard", LastName = "Wallowitz", Age = "35", FavoriteFood = "Brisket", Email = "howard@bigbang.com" },
      new PersonViewModel() { PersonId = 5, FirstName = "Stuart", LastName = "Bloom", Age = "35", FavoriteFood = "Can of tuna", Email = "stuart@bigbang.com" }
   };
}

Now let's set up the view. The view will be strongly typed to an IEnumerable of PersonViewModel. Be sure to add script references for jQuery and jQuery UI, either inline or through bundling:
@model IEnumerable<YourProjectName.Models.PersonViewModel>

@{
   ViewBag.Title = "Index";
}

<div id="notificationDiv">
   <input type="button" id="btnSendNotifications" name="btnSendNotifications" value="Send Notifications" class="ui-button ui-button-text-only ui-widget ui-state-default ui-corner-all" />
</div>

<table id="tblPeople">
   <tr class="tableHeader">
      <th></th>
      <th>Id</th>
      <th>First Name</th>
      <th>Last Name</th>
      <th>Age</th>
      <th>Favorite Food</th>
      <th>Email</th>
      <th></th>
   </tr>

   @foreach (var item in Model)
   {
      <tr>
         <td>
            <input type="checkbox" name="ckCheck" id='@("ckCheck"+@item.PersonId)' />
         </td>
         <td id="personId">@item.PersonId</td>
         <td id="firstName">@item.FirstName</td>
         <td id="lastName">@item.LastName</td>
         <td id="age">@item.Age</td>
         <td id="favoriteFood>@item.FavoriteFood</td>
         <td id="email">@item.Email</td>
         <td>
            <input type="button" id='@("btnNotify"+item.PersonId)' name="btnNotify" value="Notify" class="ui-button ui-button-text-only ui-widget ui-state-default ui-corner-all" />
         </td>
      </tr>
   }
<table>

Let's break this down a bit. The notificationDiv at the top of the page is what will take care of sending the notifications. As we will see, the click event will spin through the table rows to find which checkboxes are clicked and grab the email addresses. We are using jQuery UI to style the buttons and make them a little more pretty. Next we go through and create the table header. Then we spin through the model and write out the data.

A few things to note. I am being a little lazy and using foreach here. MVC purists would say to use a partial view as to get rid of the logic in the view. I agree but I admit I am being a little lazy. Note the technique for getting unique ids for the checkboxes and the Notify button. Razor syntax makes this possible. Here we are using it in two places: id='@("ckCheck"+@item.PersonId)' and id='@("btnNotify"+item.PersonId)'. I like this technique as it is an easy way to get unique ids.

On to the next order of business. We are going to set up a modal dialog. The purpose of this dialog is to display to the user all the email addresses to be sent back to the server. This will give a nice visual display of letting them double check their selections. They can then enter the message and reason, and finally, submit the request. Right after the table declaration in the view, add:

<div id="dialogTarget" title="Send Notifications>
   <p>All form fields are required.</p>
   <table id="peeps">
      <tr>
         <td>Bcc Message To:</td>
         <td>@Html.TextBox("ccTo", "", new { style = "width:300px;" })</td>
      </tr>
      <tr>
         <td>Message:</td>
         <td>@Html.TextArea("message", new { style = "width:300px;height:120px;" })</td>
      </tr>
      <tr>
         <td>Reason:</td>
         <td>@Html.TextBox("Reason", "", new { style = "width:300px;" })</td>
      </tr>
   </table>
</div>

All of the HTML is now good to go. Let's lay in all the script. Again, make sure your script references are set up the way you like them. We will go through piece by piece. First we will add some CSS to our table rows for the zebra striping effect. Will come back later and fill in the css business:

$('#tblPeople tr:even').addClass("alt");
$('#tblPeople tr:odd').addClass("altOdd");

Each row in the table has a Notify button. We need to handle the click event for this button and find the checkbox in that row, then check that checkbox. Since our buttons and checkboxes have unique ids, we will use the input selector 'input[name^="btnNotify"]'. The name^ syntax means "attribute starts with". We will grab the last character of the button id which will be a number. That number will then tell us which checkbox we should find, then check that checkbox:
$('input[name^="btnNotify"]').click(function (e) {
   var lastChar = e.target.id.substr(e.target.id.length - 1);
   ($(e).closest('td').find($('#ckCheck' + lastChar).attr('checked', true)));
});
The Send Notifications button click event has to go through each row in the table and find which checkboxes have been clicked. When the checkbox state is checked, we have to grab the email address from that row and put it into an array. This click event will also set the value of the ccTo field of the dialog. The last step of the event is to open the dialog.
$('#btnSendNotifications').click(function (e) {
   var emailAddresses = new Array();

   $('#tblPeople tr').each(function () {
      var checkbox = $(this).find($('input[name="ckCheck"]'));

      if (checkbox.is(":checked")) {
         var email = $(this).find('#email');
         emailAddresses.push(email.text());
      }
   });

   $('#ccTo').val(emailAddresses);
   $('#dialogTarget').dialog('open');
});

When the modal dialog pops open it should display the email addresses that were selected. The user can then fill out the message and the reason. Clicking the Notify button will fire off an Ajax request back to the server. When we return from the server we have to make sure that all selected checkboxes are changed to not being selected:
$('#dialogTarget').dialog({
   modal: true,
   autoOpen: false,
   width: 500,
   buttons: {
      "Notify": function (e) {
         var ccTo = $('#ccTo').val();
         var message = $('#message').val();
         var reason = $('#reason').val();
         $.ajax({
            url: '@Url.Action("EmailInfo", "Home")',
            type: "POST",
            dataType: "text",
            data: ({ ccTo: ccTo, message: message, reason: reason }),
            success: function (result) {
               alert(result);
               $('#dialogTarget').dialog('close');
               $('#tblPeople tr').each(function () {
                  var checkBox = $(this).find($('input[name="ckCheck"]'));

                  if (checkBox.is(":checked")) {
                     checkBox.attr('checked', false);
                  }
               }
            },
            error: function (jqXHR) {
               alert('Error: ' + jqXHR.responseText);
            }
         });
      },
      "Cancel": function () {
         $(this).dialog('close');
         $('#tblPeople tr').each(function () {
            var checkBox = $(this).find($('input[name="ckCheck"]'));

            if (checkBox.is(":checked")) {
               checkBox.attr('checked', false);
            }
         });
      }
   }
});

I can already hear the cringing....what the, why are you sending text data back?!?!? Hey now, just showing something different. We will come back and make it JSON. Let's take care of the server side business. We will need an Action called EmailInfo that will be expecting three string parameters. This Action will simple return a content message.
[HttpPost]
public ContentResult EmailInfo(string ccTo, string message, string reason)
{
   string result = "Email has been sent.";
   return Content(result);
}

Ok let's switch it all over to JSON. We will need a view model, EmailViewModel:
public class EmailViewModel
{
   public string EmailAddresses { get; set; }
   public string Message { get; set; }
   public string Reason { get; set; }
}

Change the EmailInfo Action:
[HttpPost]
public ActionResult EmailInfo(EmailViewModel email)
{
   if (ModelState.IsValid)
   {
      return Json(new { Message = "Email has been sent." });
   }
   else
   {
      return Json(new { Message = "Error, email was not sent." });
   }
}

The only change that we need to make in the JavaScript is in the Ajax call, more specifically, the data variable, and the success callback:
$.ajax({
   url: '@Url.Action("EmailInfo", "Home"),
   type: "POST",
   dataType: "json",
   data: {
      emailAddresses: ccTo,
      message: message,
      reason: reason
   },
   success: function (result) {
      alert(result.Message);
      $('#dialogTarget').dialog('close');
      $('#tblPeople tr').each(function () {
         var checkBox = $(this).find($('input[name="ckCheck"]'));

         if (checkBox.is(":checked")) {
            checkBox.attr('checked', false);
         }
      });
   },
   error: function (jqXHR) {
      alert('Error: ' + jqXHR.responseText);
   }
});

The final step is the css garbage. First, we will remove the border that is put around the checkboxes:
input[type="checkbox"] {
   background: transparent;
   border: none;
   width: auto;
}

And the css for the table:
table {
   border: solid 1px #e8eef4;
   border-collapse: collapse;
}

table td {
   padding: 5px;
   border: solid 1px #e8eef4;
   border-color: black;
}

table th {
   padding: 6px 5px;
   text-align: left;
   border: solid 1px #e8eef4;
}

tr.alt td {
   background-color: #F7F7DE;
   border-style: solid;
   border-width: 1px;
   border-color: black;
}

tr.altOdd td {
   border-style: solid;
   border-width: 1px;
   border-color: #000000
}

tr.tableHeader th {
   color: #FFFFFF
   background-color: #6B696B;
   font-weight: bold;
   border-style: solid;
   border-width: 1px;
   border-color: #000000;

Tuesday, March 5, 2013

ASP.NET MVC & Areas

Areas are a very handy way to segregate you application when you have alot of controllers that are very specific to a behavior or when you need to separate areas of your application. A common scenario, for example, is when you need an Admin section. The tricky thing about areas is handling the routing. In this example we will have an Admin area and a section for regular users, which should look normal to you. You can have controllers with the exact same name in your areas/non-areas and there will be no conflict. Let's see how to do this.

When creating a new MVC project we get the Home Controller right out of the box...

public class HomeController : Controller
{
   public ActionResult Index()
   {
      return View();
   }
}

We will assume that you have added an Area to your project, Admin, and added a Home Controller. The Home Controller will more than likely look quite similar.

In order to get things to work properly, we need to add namespacing in two areas, RouteConfig.cs and AdminAreaRegistration.cs. First let's have a go with RouteConfig.cs. Let's assume our project name is GiftIdeas...

public class RouteConfig
{
   public static void RegisterRoutes(RouteCollection routes)
   {
      routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

      routes.MapRoute(
         name: "Default",
         url: "{controller}/{action}/{id}",
         defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
         namespaces: new string[] { "GiftIdeas.Controllers" }
      );
   }
}

The important piece is the line namespaces: new string[] { "GiftIdeas.Controllers" }. All this is basically doing is saying, for the routes defined here, look in this namespace GiftIdeas.Controllers.

The other adjustment we need to make is very similar. By default, when you add an area to your project, a file called *YourAreaName*AreaRegistration.cs will be added. This is where we need to add some code, actually, very similar code...

public class AdminAreaRegistration : AreaRegistration
{
   public override string AreaName
   {
      get
      {
         return "Admin";
      }
   }

   public override void RegisterArea(AreaRegistrationContext context)
   {
      context.MapRoute(
         "Admin_default",
         "Admin/{controller}/{action}/{id}",
         new { action = "Index", id = UrlParameter.Optional },
         new string[] { "GiftIdeas.Areas.Controllers" }
      );
   }
}

The other piece of the puzzle is that now that we have an area in place, how do we deal with navigating the links within the application? For this, we have to go into _Layout.cshtml in the Views/Shared folder. Of course, this is if you want to show links across the top of your application. The change that needs to be made is in the nav section of the body. When you fire up a MVC application, this is what that part normally looks like:

<nav>
   <ul id="menu"
      <li>@Html.ActionLink("Home", "Index", "Home")</li>
      <li>@Html.ActionLink("About", "About", "Home")</li>
      <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
   </ul>
</nav>

We have to add another parameter in order for all the routes to hook up and work, for each action link, it is the same...

<nav>
   <ul id="menu"
      <li>@Html.ActionLink("Home", "Index", "Home", new { area = "" }, null)</li>
      <li>@Html.ActionLink("About", "About", "Home" new { area = "" }, null)</li>
      <li>@Html.ActionLink("Contact", "Contact", "Home" new { area = "" }, null)</li>
      <li>@Html.ActionLink("Admin", "Index", "Home", new { area = "admin" }, null)</li>
   </ul>
</nav>

With this in place, you should now be able to have controllers with the same name in different parts of you application.
A common scenario is that we pass an id to views. When you are working with views in an area it does look a little different. Let's take a look at how we do that. For example, let's say we want to render a view for a GiftIdeaViewModel. The view in the Admin area would look like this:
@model GiftIdeaViewModel

<div>
   @Html.HiddenFor(giftIdeaViewModel => giftIdeaViewModel.GiftIdeaId)
</div>
<br />
<div>
   Name: @Html.DisplayFor(giftIdeaViewModel => giftIdeaViewModel.Name)
</div>
<br />
<div>
   @Html.ActionLink("Edit", "Edit", "GiftIdea", new { area = "admin", id = @Model.GiftIdeaId }, null) |
   @Html.ActionLink("Details", "Details", "GiftIdea", new { area = "admin", id = @Model.GiftIdeaId }, null) |
   @Html.AcitonLink("Delete", "Delete", "GiftIdea", new { area = "admin", id = @Model.GiftIdeaId }, null) |
</div>

Just add the id in the anonymous object and you are good to go. About the null parameter, per the MSDN documentation, the null parameter is required only because the ActionLink method overloads that have a routeValues parameter also have an htmlAttributes parameter. However, this parameter is not required in order to be able to link between areas.

Cached Repository

Caching in MVC is not all that difficult. But, you can put an interesting twist on it. This blog post will look at using a cached repository. This awesome idea came to my attention after surfing the web and landing at Steve Smith's blog:

Cached Repository

Since we will be using a repository here, let's set that up first. The POCO will be a Person class:
public class Person
{
   public int Id { get; set; }
   public string FirstName { get; set; }
   public string LastName { get; set; }
}

I do have certain patterns and techniques I like to use. Since some have been featured in past postings, the code will just be posted below...
using System.Data.Entity.ModelConfiguration.Configuration;

public interface IEntityConfiguration
{
   void AddConfiguraton(ConfigurationRegistrar registrar);
}

using System.Collections.Generic;
using StructureMap;

public class ContextConfiguration
{
   public IEnumerable<IEntityConfiguration> Configurations
   {
      get { return ObjectFactory.GetAllInstances<IEntityConfiguration>(); }
   }
}

The configuration class for our Person POCO:
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
using System.Data.Entity.ModelConfiguration.Configuration;

public class PersonConfig : EntityTypeConfiguration<Person>, IEntityConfiguration
{
   public PersonConfig()
   {
      HasKey(p => p.Id);
      Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
      Property(p => p.FirstName).HasColumnName("FirstName").HasColumnType("nvarchar").HasMaxLength(30).IsRequried();
      Property(p => p.LastName).HasColumnName("LastName").HasColumnType("nvarchar").HasMaxLength(30).IsRequired();

      ToTable("Person");
   }

   public void AddConfiguration(ConfigurationRegistrar registrar)
   {
      registrar.Add(this);
   }
}

Again, because I like to do things in a particular fashion, the setup using an IDbContext interface may seem overkill for this demo scenario, but it's still valid for when you build out full repositories. Suffice to say, is still retains value. Plus, some of us like seeing the different ways people set up their repositories and data access crud. Moving on:
using System.Data.Entity;
using System.Data.Entity.Infrastructure;

public interface IDbContext
{
   IDbSet<TEntity> Set<TEntity>() where TEntity : class;
   DbEntityEntry<TEntity> Entry<TEntity>(TEntity entity) where TEntity : class;
   void SaveChanges();
   void Dispose();
}

using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Data.Entity.Validation;

public class PersonContext : DbContext, IDbContext
{
   public PersonContext()
      : base("name=DefaultConnection")
   {
      this.Configuration.AutoDetectChangedEnabled = true;
      this.Configuration.ProxyCreationEnabled = true;
   }

   public IDbSet<Person> People { get; set; }

   public IDbSet<TEntity> Set<TEntity>() where TEntity : class
   {
      return base.Set<TEntity>();
   }

   public new DbEntityEntry<TEntity> Entry<TEntity>(TEntity entity) where TEntity : class
   {
      return base.Entry<TEntity>(entity);
   }

   public new void SaveChanges()
   {
      try
      {
         base.SaveChanges();
      }
      catch (DbEntityValidationException ex)
      {
         throw new Exception(ex.Message);
      }
   }

   protected new void Dispose()
   {
      base.Dispose();
   }

   protected override void OnModelCreating(DbModelBuilder modelBuilder)
   {
      modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
      Database.SetInitializer(new PersonInitializer());

      ContextConfiguration ctxConfig = new ContextConfiguration();

      foreach (IEntityConfiguration configuration in ctxConfig.Configurations)
      {
         configuration.AddConfiguration(modelBuilder.Configurations);
      }
   }
}

The PersonInitializer class sets up seed data which will be omitted. Also omitted is the StructureMap code since that has been covered in another post, just want to keep moving along here.

For the repository, I like to take the generic approach. We will have a Repository<T> class, a concrete PersonRepository class, an IRepository<T> interface, and an IPersonRepository interface. For this posting, I am not going to show a full blown repository implementation, perhaps that will come in a later post. Presented here will just be a very scaled down version to get the point of caching across:
public interface IRepository<T> where T : class
{
   IQueryable<T> AsQueryable();
   IEnumerable<T> GetAll();
}

public class Repository<T> : IRepository<T> where T : class
{
   private IDbContext iDbContext;

   public Repository(IDbContext context)
   {
      this.iDbContext = context;
   }

   public IQueryable<T> AsQueryable()
   {
      return this.iDbContext.Set<T>().AsQueryable();
   }
}

public interface IPersonRepository : IRepository<Person>
{
}

public class PersonRepository : Repository<Person>, IPersonRepository
{
   public PersonRepository(IDbContext iDbContext)
      : base(iDbContext)
   {
   }
}

Now the normal repository business is set up. Let's set up the Cachec Repository. First, we will need the generic ICachedRepository interface. You can put whatever methods you want to cache on this interface from the generic IRepository<T> interface. Sticking with our example, we have two, AsQueryable and GetAll:
public interface ICachedRepository<out T> where T : class
{  
   IQueryable<T> AsQueryable();
   IEnumerable<T> GetAll();
}

Of course the next step is the class that implements this interface. Remember, we are hooking into the ASP.NET cache here. Here is the CacheRepository class:
public class CachedRepository<T> : ICachedRepository<T> where T : class
{
   private IDbContext iDbContext;
   private static readonly object CacheLock = new object();

   public CachedRepository(IDbContext iDbContext)
   {
      this.iDbContext = iDbContext;
   }

   public IQueryable<T> AsQueryable()
   {
      string cacheKey = "AsQueryable";
      var result = HttpRuntime.Cache[cacheKey] as IQueryable<T>;

      if (result == null)
      {
         lock (CacheLock)
         {
            result = HttpRuntime.Cache[cacheKey] as IQueryable<T>;
            if (result == null)
            {
               result = this.iDbContext.Set<T>().AsQueryable();
               HttpRuntime.Cache.Insert(cachKey, result, null, DateTime.Now.AddSeconds(20), TimeSpan.Zero);
            }
         }
      }

      return result;
   }

   public IEnumerable<T> GetAll()
   {
      string cacheKey = "GetAll";
      var result = HttpRuntime.Cache[cacheKey] as IEnumerabl<T>;

      if (result == null)
      {
         lock (CacheLock)
         {
            result = HttpRuntime.Cache[cacheKey] as IEnumerable<T>;
            if (result == null)
            {
               result = this.iDbContext.Set<T>().AsEnumerable();
               HttpRuntime.Cache.Insert(cacheKey, result, null, DateTime.Now.AddSeconds(20), TimeSpan.Zero);
            }
         }
      }

      return result;
   }
}

In each method, we start out by defining a cache key, this cache key is put into the ASP.NET cache. Next, we check the cache for the cache key, if they cache key is null, no results for that given key have been stored in the cache. Now we lock the cache. It may seem strange to check the cache again for the result but this is very common in situations involving locking, it's a double check. We check the cache again for the cache key, and compare the result. Again, if the result is null, there is nothing in the cache for this query. If null, we query the DbContext for that entity and store the result, along with the cache key, cache dependencies (null), absolute expiration (DateTime.Now.Add(20)), and a sliding expiration (TimeSpan.Zero).
To set up a cached person repository, we just follow the patterns:
public interface ICachedPersonRepository : ICachedRepository<Person>
{
}

And the class to consume the interface:
public class CachedPersonRepository : CachedRepository<Person>, ICachedRepository
{
   public CachedPersonRepository(IDbContext iDbContext)
      : base(iDbContext)
   {
   }
}

What does this look like? When I was doing this demo, I was using the Paged List package which is a nice utility you can get on NuGet for formatting results with paging and all that good stuff. I won't go into that here but anyway, we have our Home Controller, the Index method is where the action is happening. The code below is not very important, moreso for illustration purposes. Also, the StructureMap configuration is not shown as well:
private ICachedPersonRespository cachedPersonRepository;

public HomeController(ICachedPersonRepository cachedPersonRepository)
{
   this.cachedPersonRepository = cachedPersonRepository;
}

public ActionResult Index(string search = null, int page = 1)
{
   IPagedList viewModels = this.cachedRepository.AsQueryable()
                                            .OrderByDescending(p => Id)
                                            .Where(p => search = null || p.FirstName.EndsWith(search))
                                            .Select(p => new PersonViewModel()
                                            {
                                               Id = p.Id,
                                               FirstName = p.FirstName,
                                               LastName = p.LastName
                                            }).ToPagedList(page, 5);

   return View(viewModels);
}

When the application first loads and we hit this method, the cached repository will be checked with the call to AsQueryable(). If we were to step through the code upon page load, here is the breakdown:
public IQueryable<T> AsQueryable()
{
   // upon page load, define the cache key
   string cacheKey = "AsQueryable";

   // look in cache for the cach ekey
   var result = HttpRuntime.Cache[cacheKey] as IQueryable<T>;

   // first page load, result will be null, nothing in cache
   if (result == null)
   {
      // lock the cache
      lock (CacheLock)
      {
         // double check
         result = HttpRuntime.Cache[cacheKey] as IQueryable<T>;

         // check the result again, result will be null on first page load
         if (result == null)
         {
            // get entity of T AsQueryable
            result = this.iDbContext.Set<T>.AsQueryable();

            // insert into the cache
            HttpRuntime.Cache.Insert(cacheKey, result, null, DateTime.Now.AddSeconds(20), TimeSpan.Zero);
         }
      }
   }

   return result;
}

We have assigned the result to be cached for 20 seconds. This means that for the next 20 seconds, any call that comes into the cached repository with the call to AsQueryable(), the ASP.NET runtime will return the cached response. In his article, Steve Smith points out that this approach does violate the DRY principle. If you want to look into that, check this link:

Cached Repository with Strategy Pattern