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.