Currently I am working on displaying different input forms on tabs in asp.net mvc 3. Each tab has several child partial views. [See the image below]
1 of the partial views contains a form for creating Sessions, and above it is another partial view with a list of sessions created (none yet).. When switching tabs at the top, and back again the jquery timepicker plugin by Francois Gelinas known as jquery.ui.timepicker.js fails to rebind/reinitialize after selecting another tab and then returning to the tab Edit Course and Program Defaults.
I'm using the razor engine, instead of the default web engine...

The masterpage/file _Layout.cshtml

  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">  
  <html>  
  <head>  
   <meta http-equiv="X-UA-Compatible" content="IE=8" />    
   <title>@ViewBag.Title</title>  
   <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")"  type="text/javascript">   </script>  
   <script src="@Url.Content("~/Scripts/jquery.ui.core.js")" type="text/javascript">   </script>   
   <script src="@Url.Content("~/Scripts/jquery.livequery.js")" type="text/javascript">  </script>  
   <script src="@Url.Content("~/Scripts/jquery.ui.widget.js")" type="text/javascript"></script>  
   <script src="@Url.Content("~/Scripts/jquery.ui.tabs.js")" type="text/javascript"></script>  
   <script src="@Url.Content("~/Scripts/jquery.ui.timepicker.js")" type="text/javascript"></script>  
   <script src="@Url.Content("~/Scripts/jquery-ui-1.8.11.custom.js")" type="text/javascript"></script>  

   <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />  
   <link href="@Url.Content("~/Content/jquery-ui-1.8.11.custom.css")" type="text/css" rel="stylesheet" />  
   <link href="@Url.Content("~/Content/jquery-ui-timepicker.css")" type="text/css" rel="stylesheet" />  

   <script src="@Url.Content("~/Scripts/MicrosoftAjax.debug.js")" type="text/javascript"></script>
   <script src="@Url.Content("~/Scripts/MicrosoftMvcAjax.debug.js")" type="text/javascript"></script>  

Index.cshtml << this is called by the create button on the main mvc application menu
It creates the 3 tabs you see in the picture above.

@using MvcHtmlHelpers;
<link href="@Url.Content("~/Content/BoxBackgrounds.css")" rel="stylesheet" type="text/css" />


@{
    ViewBag.Title = "Index";
 }

<h2>Index</h2>
<div id="tabs">
 <ul>
   <li >@Html.TabLink("Edit Student Defaults", "EditStudentDefaults", "Creation") </li>
   <li>@Html.TabLink("Edit Exam and Certification Defaults", "EditCertAndExamDefaults", "Creation") </li>
  <li>@Html.TabLink("Edit Course and Program Defaults", "EditCourseAndProgramDefaults", "Creation")</li>
 </ul>
</div>

<script type="text/javascript" language="javascript">

$(document).ready(function() {
    $("#tabs").tabs({
    cache: false
   });

 });

EditCourseAndProgramDefaults.cshtml << partial view tab with partial views inside it.

@model SMS3demo.Controllers.CourseAndProgramDefaultsViewModel
<table width="100%" class="ConfigStudentsGradient" cellspacing="0" border="0" frame="void" style="border-collapse:collapse">
 <tr>
     <td>
        @Html.Partial("ListSessions")
     </td>
     <td>
        @Html.Partial("ListCourses")
     </td>
     <td>
        @Html.Partial("ListPrograms")
    </td>


 </tr>
 <tr>
     <td>
        @Html.Partial("AddSession")
     </td>
     <td>
         @Html.Partial("AddCourse")
     </td>
     <td>
         @Html.Partial("AddProgram")
     </td>

 </tr>

</table>

AddSession.cshtml << partial view that uses the timepicker

@model SMS3demo.Controllers.CourseAndProgramDefaultsViewModel  
@using (Html.BeginForm()) {
<script type="text/javascript">
 $(document).ready(function () {
     $('#StartTime').timepicker({
         showPeriod: true,
         showLeadingZero: false
     });
 });

@Html.ValidationSummary(true)
<fieldset>
    <legend>Session</legend>
        <table>
<tr>
                <td>
                    <span class="SessionStartTime">@Html.TextBoxFor(model => model.SessionStartTime, new {@id = "StartTime"  }) </span>


                    @Html.ValidationMessageFor(model => model.SessionStartTime)
                </td>

I researched this topic for a couple of days now. I tried the following ideas/options methods...

  1. using the live
  2. using livequery
  3. trying to recreate the binding after each onclick event for the input field
  4. i tried to see how others solved this problem using another control like the datepicker, since this plugin is very similar to it.

I know what is happening: the timepicker is losing its binding, when i switch back to the tab. I discovered in firebug there is a hidden timepicker object created, and it doesn't die when the tabs are switched... however, I cannot seem to rebind or recall the original method to recreate when the tab is selected again. I know document.ready is only called 1x when the partial view is 1st loaded...
I tried doing the following: in

<script type="text/javascript">
    $(document).ready(function() {
        initJQueryWidgets();
    });

    function initJQueryWidgets() {
        $("[ID$=StartTime1]").timepicker({
                showPeriod: true,
                showLeadingZero: false,
                zIndex: 1
            });
    }


</script>

I also tried at the top ofthe page in the script bracket show above

Sys.WebForms.PageRequestManager.getInstance().add_endRequest(function() {
         initJQueryWidgets();
    });

I then tried calling the initJqueryWidgets in the onClick even handler for the input box

 <span class="SessionStartTime">@Html.TextBoxFor(model => model.SessionStartTime, new {@id = "StartTime", @onClick="initJqueryWidgets"  }) </span>

The errors I consistently received were $("#StartTime").timepicker is not a function (?)()52 (line 2) anonymous()Creation (line 29) [Break On This Error] $("#StartTime").timepicker({showPeriod: true, showLeadingZero: false});

3

There are 3 best solutions below

6
On

The timepicker create an instance in the DOM once and use this instance every time it is displayed except for inline display, that's why you see it in your DOM, it does not mean that it detached from the input.

If the timepicker is now showing on click, that probably mean that there is a zIndex problem or it lost its click event.

(document).ready(function () {
 $('#StartTime').timepicker({
     showPeriod: true,
     showLeadingZero: false,
     zIndex: 9999
 });

});

If the #StartTime is loosing it's binding, you have to remove the "hasTimePicker" class to it before binding it again.


I'll investigate tonight as to how the datepicker react in this situation and make it work on the timepicker too, will update when I find the solution.

0
On

Jquery tabs often disable the div containing the elements for each tab when it's not being viewed. That said, if Jquery can't find the element then it can't create the date picker, so you'll have to fire off an event when the tab is selected to first check to see if the element exists then create the date picker accordingly.

$('#tabs a#idOfTabContainingStartTime').bind('click', function(){
    if( $("#StartTime").length ){
         $('#StartTime').timepicker({
             showPeriod: true,
             showLeadingZero: false
         });
    }
}

If that doesn't solve your problem, then it's probably because Jquery gets a bit trigger happy with the whole tabs/div/hiding thing. When you select another tab the tab you were currently viewing is hidden, but Jquery also likes to hide everything within the tab as well, so you may have to create another call that checks for any elements currently being hidden within the tab and iteratively show them.

$('#tabs a#idOfTabContainingStartTime :hidden').each(function(){
    $(this).show();
});
0
On

i fixed it, by removing the calls to load other jquery versions! Check your Firebug console when you click your tabs, and see what get commands are being processed. Make sure you link in only 1 version of jquery! Whew! Also, I found that in partial views remove all script link references, and put in in the masterpage, easier to track and correct.

Special Thanks to Francois Gelinas for taking time out of his day to help, and also to Black Box Operations for helping as well.