Skip to main content

Search and Top Navigation

#4451 closed bug (fixed)

Opened April 09, 2009 11:37PM UTC

Closed February 24, 2010 06:44PM UTC

AJAX tabs stop functioning properly after AJAX error callback is executed

Reported by: JBeckton Owned by: jzaefferer
Priority: critical Milestone: 1.8
Component: ui.tabs Version: 1.7.1
Keywords: Cc:
Blocked by: Blocking:
Description

I have some UI Tabs set up using AJAX calls to populate the container,

set it up as suggested on the jQuery UI site.

In my AJAX options I have a handler for error event. I purposely broke

the remote page to test the error handling. When I click the tab that

calls the remote page my error callback runs as expected but now when

I try to select the other tabs they freak out! I either have to click

on them twice or they may load each others content inside them at the

same time. Very strange!

My application handles the error and returns the http status 500 so

the AJAX will know it took a crap.

Here is my code.

HTML:

<div class="AJAXErrorContainer" style="display:none"></div>
<div id="caseManagerWorkbench" class="ui-tabs ui-widget ui-widget-
content ui-corner-all">
        <ul class="ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-
header ui-corner-all">
                <li class="ui-state-default ui-corner-top ui-tabs-selected ui-state-
active"><a href="index.cfm?fuseaction=casemanager.exhibits"
title="Exhibits">Exhibits</a></li>
        <li class="ui-state-default ui-corner-top"><a href="index.cfm?
fuseaction=casemanager.checkwriter" title="Check Writer">Check Writer</
a></li>
                <li class="ui-state-default ui-corner-top"><a href="index.cfm?
fuseaction=casemanager.comments" title="Comments">Comments</a></li>
        <li class="spinnerContainer"></li>
        </ul>
    <div id="Exhibits"></div>
    <div id="Check_Writer"></div>
    <div id="Comments"></div>
</div>

JavaScript:

$(function() {

        //builds the tab interface for viewing the submittal data
        $("#caseManagerWorkbench").tabs({ ajaxOptions: {
                                                                                                        async: false,
                                                                                                        cache: false,
                                                                                                        success: function() {
                                                                                                                                                  $(".AJAXErrorContainer").hide();
                                                                                                                                                },
                                                                                                        error: function() {
                                                                                                                                                $(".AJAXErrorContainer").html("An error has occured
during the remote request, Please try again.");
                                                                                                                                                $(".AJAXErrorContainer").show();
                                                                                                                                           }
                                                                                                        },
                                                                                spinner: null,
                                                                                select: function() {$(".spinnerContainer").html("<span
style='color:white;'><img src='images/ajax-loader-blue.gif' hspace='5'
vspace='4' align='absmiddle'> Loading...</span>");},
                                                                                load: function() {$(".spinnerContainer").html("");}
                                                                        });
Attachments (2)
Change History (10)

Changed May 07, 2009 11:12AM UTC by jzaefferer comment:1

description: I have some UI Tabs set up using AJAX calls to populate the container, \ set it up as suggested on the jQuery UI site. \ \ In my AJAX options I have a handler for error event. I purposely broke \ the remote page to test the error handling. When I click the tab that \ calls the remote page my error callback runs as expected but now when \ I try to select the other tabs they freak out! I either have to click \ on them twice or they may load each others content inside them at the \ same time. Very strange! \ \ My application handles the error and returns the http status 500 so \ the AJAX will know it took a crap. \ \ Here is my code. \ HTML: \ \ <div class="AJAXErrorContainer" style="display:none"></div> \ <div id="caseManagerWorkbench" class="ui-tabs ui-widget ui-widget- \ content ui-corner-all"> \ <ul class="ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget- \ header ui-corner-all"> \ <li class="ui-state-default ui-corner-top ui-tabs-selected ui-state- \ active"><a href="index.cfm?fuseaction=casemanager.exhibits" \ title="Exhibits">Exhibits</a></li> \ <li class="ui-state-default ui-corner-top"><a href="index.cfm? \ fuseaction=casemanager.checkwriter" title="Check Writer">Check Writer</ \ a></li> \ <li class="ui-state-default ui-corner-top"><a href="index.cfm? \ fuseaction=casemanager.comments" title="Comments">Comments</a></li> \ <li class="spinnerContainer"></li> \ </ul> \ <div id="Exhibits"></div> \ <div id="Check_Writer"></div> \ <div id="Comments"></div> \ </div> \ \ JavaScript: \ $(function() { \ \ //builds the tab interface for viewing the submittal data \ $("#caseManagerWorkbench").tabs({ ajaxOptions: { \ async: false, \ cache: false, \ success: function() { \ $(".AJAXErrorContainer").hide(); \ }, \ error: function() { \ $(".AJAXErrorContainer").html("An error has occured \ during the remote request, Please try again."); \ $(".AJAXErrorContainer").show(); \ } \ }, \ spinner: null, \ select: function() {$(".spinnerContainer").html("<span \ style='color:white;'><img src='images/ajax-loader-blue.gif' hspace='5' \ vspace='4' align='absmiddle'> Loading...</span>");}, \ load: function() {$(".spinnerContainer").html("");} \ }); I have some UI Tabs set up using AJAX calls to populate the container, \ set it up as suggested on the jQuery UI site. \ \ In my AJAX options I have a handler for error event. I purposely broke \ the remote page to test the error handling. When I click the tab that \ calls the remote page my error callback runs as expected but now when \ I try to select the other tabs they freak out! I either have to click \ on them twice or they may load each others content inside them at the \ same time. Very strange! \ \ My application handles the error and returns the http status 500 so \ the AJAX will know it took a crap. \ \ Here is my code. \ HTML: \ \ {{{ \ <div class="AJAXErrorContainer" style="display:none"></div> \ <div id="caseManagerWorkbench" class="ui-tabs ui-widget ui-widget- \ content ui-corner-all"> \ <ul class="ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget- \ header ui-corner-all"> \ <li class="ui-state-default ui-corner-top ui-tabs-selected ui-state- \ active"><a href="index.cfm?fuseaction=casemanager.exhibits" \ title="Exhibits">Exhibits</a></li> \ <li class="ui-state-default ui-corner-top"><a href="index.cfm? \ fuseaction=casemanager.checkwriter" title="Check Writer">Check Writer</ \ a></li> \ <li class="ui-state-default ui-corner-top"><a href="index.cfm? \ fuseaction=casemanager.comments" title="Comments">Comments</a></li> \ <li class="spinnerContainer"></li> \ </ul> \ <div id="Exhibits"></div> \ <div id="Check_Writer"></div> \ <div id="Comments"></div> \ </div> \ }}} \ JavaScript: \ {{{ \ $(function() { \ \ //builds the tab interface for viewing the submittal data \ $("#caseManagerWorkbench").tabs({ ajaxOptions: { \ async: false, \ cache: false, \ success: function() { \ $(".AJAXErrorContainer").hide(); \ }, \ error: function() { \ $(".AJAXErrorContainer").html("An error has occured \ during the remote request, Please try again."); \ $(".AJAXErrorContainer").show(); \ } \ }, \ spinner: null, \ select: function() {$(".spinnerContainer").html("<span \ style='color:white;'><img src='images/ajax-loader-blue.gif' hspace='5' \ vspace='4' align='absmiddle'> Loading...</span>");}, \ load: function() {$(".spinnerContainer").html("");} \ }); \ }}}
milestone: TBD1.7.2

Changed May 07, 2009 01:38PM UTC by jzaefferer comment:2

milestone: 1.7.21.8

Changed May 11, 2009 01:04PM UTC by jzaefferer comment:3

Attached a patch to handle ajax errors. Currently the error message is hard coded.

Changed May 13, 2009 08:19PM UTC by itfische comment:4

Similarly, if the ajax request takes a long time, the user may click on a different tab. This causes the same behavior described for the error case -- the slow-loading tab becomes selected when the user clicks the next tab, the content is not loaded (so you end up with a blank panel), and the tab clicks become off-by-one in the stack of clicks.

To illustrate, consider the case of three tabs. Tab 1 is the currently selected. Tab 2 is a slow-loading tab. Tab 3 loads in a reasonable time.

The user starts on Tab 1 with the content loaded. He then clicks on Tab 2, but Tab 1 is still indicated as selected, since Tab 2 hasn't loaded yet. He quickly gets tired of waiting, so he clicks on Tab 3 before Tab 2 has loaded. At this point, Tab 2 becomes the selected tab, but there is no content in it. If he then clicks on Tab 3 again to try to get it to load, it does, but it has either the content for Tab 1 at the top and the content for Tab 3 at the bottom, or it has the blank div for Tab 1's panel at the top and the content for Tab 3 at the bottom (this is easiest to see if there is a minimum height set on the panels).

If instead of clicking Tab 3 a second time he clicks on Tab 1, he gets the off-by-one error behavior. Tab 3 will become selected when he clicks on Tab 1 with the double-content problem described above. If he then clicks on Tab 1 again, he will have the content from both Tab 1 and Tab 3 visible.

Obviously there is a more fundamental bug in the tabs than what this ticket initially suggests. However, I think the core if the issue would probably be corrected if selecting a tab always immediately updated the UI and displayed a spinner in the newly-displayed tab panel.

Getting this behavior may be as simple as moving

self.element.dequeue("tabs");

outside of the ajax callbacks and calling a new

displayPanelSpinner
function (as well as adding a new option for a
panelSpinner
). However, I haven't tried that fix yet.

This error is easily replicated by setting up the the three tabs as described above with normal ajax tab settings and setting a two second sleep on the server side for one of the tabs' target urls. As mentioned above, it is important to set the panels to have a minimum height in the css to be able to see the panels loading improperly.

Changed May 14, 2009 12:07AM UTC by itfische comment:5

I have verified that moving the

self.element.dequeue("tabs");
line out of the success callback does fix the slow tab/fast user errors. Presumably the same would work well with the patch attached to this ticket for the ajax error callbacks.

The end of my

load
function now looks like:

		this.xhr = $.ajax($.extend({}, o.ajaxOptions, {
			url: url,
			success: function(r, s) {
				$(self._sanitizeSelector(a.hash)).html(r);

				// take care of tab labels
				self._cleanup();

				if (o.cache) {
					$.data(a, 'cache.tabs', true); // if loaded once do not load them again
				}

				// callbacks
				self._trigger('load', null, self._ui(self.anchors[index], self.panels[index]));
				try {
					o.ajaxOptions.success(r, s);
				}
				catch (e) {}
			}
		}));

		// last, so that load event is fired before show...
		self.element.dequeue("tabs");
		return this;
	},

Changed December 07, 2009 09:01AM UTC by andrew.sharpe.7.9 comment:6

Added [attachment:ticket:4451:jquery.ui.tabs.js-4451.patch patch] against [source:/trunk/ui/jquery.ui.tabs.js@3488 r3488] which merges [attachment:ticket:4451:ui.tabs.js-4451.patch joerns patch] with the following changes

  • don't display an error message in the tab panel
  • pass extra information to the error handler
  • the index of the broken tab
  • the anchor that initiated the request

Changed December 08, 2009 07:22AM UTC by andrew.sharpe.7.9 comment:7

Replying to [comment:6 andrew.sharpe.7.9]:

And also moves

self.element.dequeue("tabs");

out of the success callback as suggested by itfische.

Changed February 03, 2010 08:54AM UTC by rdworth comment:8

Changed February 24, 2010 05:45PM UTC by jzaefferer comment:9

owner: → joern.zaefferer
status: newaccepted

Changed February 24, 2010 06:44PM UTC by jzaefferer comment:10

resolution: → fixed
status: acceptedclosed

Fixed in r3846. I removed the e-argument and changed it to call options.ajaxOptions.error to be consistent with options.ajaxOptions.success. Also extended the ajax demo to demo slow-loading and broken tabs.