wait30Bruce Williams is right on in Avoiding AJAX Faux Pas where he lists four inviolable conditions your AJAX code must meet. The first two conditions address the need to show (then hide) a visual progress indicator to let the user know that a network operation (XHR) is occurring. These are important rules. Unfortunately, the implementation he presents is fraught with difficulties.

Bruce’s solution is comprised of a Ruby function showing_progress which he suggests you use in every single call to (insert_html, replace_html, replace) to wrap any options you’d normally pass to those routines. The showing_progress routine adds :loading and :complete handlers that will show, then hide an element with id ‘progress’ on your page.

The solution is kind of elegant and it works as advertised but I ran into a few problems as I got deeper into my app:

  1. I forgot to call showing_progress in new invocations of insert_html, replace_html, replace – as a result I didn’t get progress indication in those cases

  2. The solution works only for Ruby RJS code – if you write JavaScript that calls Ajax.Request and Ajax.Updater then the solution of course doesn’t help.

  3. The solution ruthlessly overwrites any :loading and :complete handlers you’ve defined in your options

How about a solution that works for both Ruby and JavaScript? It’d be nice if it didn’t rely on the programmer remembering to call it everywhere? It’d be even nicer if it didn’t interfere with your application’s :loading and :complete handlers.

Here’s the solution I’m using. I don’t recall where I first saw it but I’m pretty sure I didn’t invent it. I see Nicky Peeters was suggesting a similar thing over a year ago. Just put this code in application.js:

<span class="linenum">    1</span> <span class="source source_prototype source_prototype_js"><span class="support support_class support_class_prototype support_class_prototype_js">Ajax</span><span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js">.</span><span class="support support_class support_class_prototype support_class_prototype_js">Responders</span><span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js">.</span><span class="support support_function support_function_prototype support_function_prototype_js">register</span><span class="meta meta_brace meta_brace_round meta_brace_round_js">(</span><span class="meta meta_brace meta_brace_curly meta_brace_curly_js">{</span>
<span class="linenum">    2</span> <span class="meta meta_property meta_property_function meta_property_function_prototype meta_property_function_prototype_js"><span class="object object_property object_property_function object_property_function_prototype object_property_function_prototype_js">onCreate</span>: <span class="entity entity_name entity_name_function entity_name_function_prototype entity_name_function_prototype_js">function</span>()</span> <span class="meta meta_brace meta_brace_curly meta_brace_curly_js">{</span>
<span class="linenum">    3</span>  <span class="keyword keyword_control keyword_control_js">if</span><span class="meta meta_brace meta_brace_round meta_brace_round_js">(</span><span class="keyword keyword_operator keyword_operator_js">$</span><span class="meta meta_brace meta_brace_round meta_brace_round_js">(</span><span class="string string_quoted string_quoted_single string_quoted_single_js"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js">'</span>progress<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js">'</span></span><span class="meta meta_brace meta_brace_round meta_brace_round_js">)</span> <span class="keyword keyword_operator keyword_operator_js">&&</span> <span class="support support_class support_class_prototype support_class_prototype_js">Ajax</span><span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js">.</span><span class="support support_function support_function_prototype support_function_prototype_js">activeRequestCount</span><span class="keyword keyword_operator keyword_operator_js">></span><span class="constant constant_numeric constant_numeric_js">0</span><span class="meta meta_brace meta_brace_round meta_brace_round_js">)</span>
<span class="linenum">    4</span>  <span class="support support_class support_class_prototype support_class_prototype_js">Effect</span><span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js">.</span><span class="support support_class support_class_prototype support_class_prototype_js">Appear</span><span class="meta meta_brace meta_brace_round meta_brace_round_js">(</span><span class="string string_quoted string_quoted_single string_quoted_single_js"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js">'</span>progress<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js">'</span></span><span class="meta meta_delimiter meta_delimiter_object meta_delimiter_object_comma meta_delimiter_object_comma_js">,</span><span class="meta meta_brace meta_brace_curly meta_brace_curly_js">{</span>duration:<span class="constant constant_numeric constant_numeric_js">0.5</span><span class="meta meta_delimiter meta_delimiter_object meta_delimiter_object_comma meta_delimiter_object_comma_js">,</span>queue:<span class="string string_quoted string_quoted_single string_quoted_single_js"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js">'</span>end<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js">'</span></span><span class="meta meta_brace meta_brace_curly meta_brace_curly_js">}</span><span class="meta meta_brace meta_brace_round meta_brace_round_js">)</span><span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js">;</span>
<span class="linenum">    5</span> <span class="meta meta_brace meta_brace_curly meta_brace_curly_js">}</span><span class="meta meta_delimiter meta_delimiter_object meta_delimiter_object_comma meta_delimiter_object_comma_js">,</span>
<span class="linenum">    6</span>
<span class="linenum">    7</span> <span class="meta meta_property meta_property_function meta_property_function_prototype meta_property_function_prototype_js"><span class="object object_property object_property_function object_property_function_prototype object_property_function_prototype_js">onComplete</span>: <span class="entity entity_name entity_name_function entity_name_function_prototype entity_name_function_prototype_js">function</span>()</span> <span class="meta meta_brace meta_brace_curly meta_brace_curly_js">{</span>
<span class="linenum">    8</span>  <span class="keyword keyword_control keyword_control_js">if</span><span class="meta meta_brace meta_brace_round meta_brace_round_js">(</span><span class="keyword keyword_operator keyword_operator_js">$</span><span class="meta meta_brace meta_brace_round meta_brace_round_js">(</span><span class="string string_quoted string_quoted_single string_quoted_single_js"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js">'</span>progress<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js">'</span></span><span class="meta meta_brace meta_brace_round meta_brace_round_js">)</span> <span class="keyword keyword_operator keyword_operator_js">&&</span> <span class="support support_class support_class_prototype support_class_prototype_js">Ajax</span><span class="meta meta_function meta_function_js">.<span class="entity entity_name entity_name_function entity_name_function_js">activeRequestCount</span>=</span><span class="keyword keyword_operator keyword_operator_js">=</span><span class="constant constant_numeric constant_numeric_js">0</span><span class="meta meta_brace meta_brace_round meta_brace_round_js">)</span>
<span class="linenum">    9</span>  <span class="support support_class support_class_prototype support_class_prototype_js">Effect</span><span class="meta meta_delimiter meta_delimiter_method meta_delimiter_method_period meta_delimiter_method_period_js">.</span><span class="support support_class support_class_prototype support_class_prototype_js">Fade</span><span class="meta meta_brace meta_brace_round meta_brace_round_js">(</span><span class="string string_quoted string_quoted_single string_quoted_single_js"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js">'</span>progress<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js">'</span></span><span class="meta meta_delimiter meta_delimiter_object meta_delimiter_object_comma meta_delimiter_object_comma_js">,</span><span class="meta meta_brace meta_brace_curly meta_brace_curly_js">{</span>duration:<span class="constant constant_numeric constant_numeric_js">0.5</span><span class="meta meta_delimiter meta_delimiter_object meta_delimiter_object_comma meta_delimiter_object_comma_js">,</span>queue:<span class="string string_quoted string_quoted_single string_quoted_single_js"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_js">'</span>end<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_js">'</span></span><span class="meta meta_brace meta_brace_curly meta_brace_curly_js">}</span><span class="meta meta_brace meta_brace_round meta_brace_round_js">)</span><span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js">;</span>
<span class="linenum">   10</span> <span class="meta meta_brace meta_brace_curly meta_brace_curly_js">}</span>
<span class="linenum">   11</span> <span class="meta meta_brace meta_brace_curly meta_brace_curly_js">}</span><span class="meta meta_brace meta_brace_round meta_brace_round_js">)</span><span class="punctuation punctuation_terminator punctuation_terminator_statement punctuation_terminator_statement_js">;</span>
</span>

And stick something like this in your layout:

<span class="linenum">    1</span> <span class="text text_html text_html_basic">                <span class="meta meta_tag meta_tag_inline meta_tag_inline_any meta_tag_inline_any_html"><span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_html"><</span><span class="entity entity_name entity_name_tag entity_name_tag_inline entity_name_tag_inline_any entity_name_tag_inline_any_html">span</span> <span class="meta meta_attribute-with-value meta_attribute-with-value_id meta_attribute-with-value_id_html"><span class="entity entity_other entity_other_attribute-name entity_other_attribute-name_id entity_other_attribute-name_id_html">id</span><span class="punctuation punctuation_separator punctuation_separator_key-value punctuation_separator_key-value_html">=</span><span class="string string_quoted string_quoted_single string_quoted_single_html"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_html">'</span><span class="meta meta_toc-list meta_toc-list_id meta_toc-list_id_html">progress</span><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_html">'</span></span></span> <span class="entity entity_other entity_other_attribute-name entity_other_attribute-name_html">style</span>=<span class="string string_quoted string_quoted_single string_quoted_single_html"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_html">'</span>display:none;<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_html">'</span></span><span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_html">></span></span>
<span class="linenum">    2</span>                     <span class="meta meta_tag meta_tag_inline meta_tag_inline_any meta_tag_inline_any_html"><span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_html"><</span><span class="entity entity_name entity_name_tag entity_name_tag_inline entity_name_tag_inline_any entity_name_tag_inline_any_html">img</span> <span class="entity entity_other entity_other_attribute-name entity_other_attribute-name_html">src</span>=<span class="string string_quoted string_quoted_single string_quoted_single_html"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_html">'</span>/images/busy.gif<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_html">'</span></span><span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_html">></span></span>
<span class="linenum">    3</span>                 <span class="meta meta_tag meta_tag_inline meta_tag_inline_any meta_tag_inline_any_html"><span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_html"></</span><span class="entity entity_name entity_name_tag entity_name_tag_inline entity_name_tag_inline_any entity_name_tag_inline_any_html">span</span><span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_html">></span></span>
</span>

And you’ll have one less worry in your life.