Ticket #4451 (closed bug: fixed)

Opened 6 years ago

Last modified 5 years ago

AJAX tabs stop functioning properly after AJAX error callback is executed

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

Description (last modified by joern.zaefferer) (diff)

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

ui.tabs.js-4451.patch Download (640 bytes) - added by joern.zaefferer 5 years ago.
jquery.ui.tabs.js-4451.patch Download (1007 bytes) - added by andrew.sharpe.7.9 5 years ago.

Change History

comment:1 Changed 5 years ago by joern.zaefferer

  • Description modified (diff)
  • Milestone changed from TBD to 1.7.2

comment:2 Changed 5 years ago by joern.zaefferer

  • Milestone changed from 1.7.2 to 1.8

Changed 5 years ago by joern.zaefferer

comment:3 Changed 5 years ago by joern.zaefferer

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

comment:4 Changed 5 years ago by itfische

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.

comment:5 Changed 5 years ago by itfische

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 5 years ago by andrew.sharpe.7.9

comment:6 follow-up: ↓ 7 Changed 5 years ago by andrew.sharpe.7.9

Added patch Download against r3488 which merges joerns patch Download 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

comment:7 in reply to: ↑ 6 Changed 5 years ago by andrew.sharpe.7.9

Replying to andrew.sharpe.7.9:

And also moves

self.element.dequeue("tabs");

out of the success callback as suggested by itfische.

comment:9 Changed 5 years ago by joern.zaefferer

  • Owner set to joern.zaefferer
  • Status changed from new to accepted

comment:10 Changed 5 years ago by joern.zaefferer

  • Status changed from accepted to closed
  • Resolution set to fixed

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.

Note: See TracTickets for help on using tickets.