<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Alfa Jango Blog</title>
	
	<link>http://www.alfajango.com/blog</link>
	<description>Engineering, Software, and Entrepreneurship</description>
	<lastBuildDate>Wed, 21 Mar 2012 07:18:42 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/alfajango" /><feedburner:info uri="alfajango" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Communication in Engineering, Software, and Open-source</title>
		<link>http://feedproxy.google.com/~r/alfajango/~3/1STpUPx2jX4/</link>
		<comments>http://www.alfajango.com/blog/communicating-with-engineers-and-contributing-to-open-source/#comments</comments>
		<pubDate>Tue, 27 Sep 2011 22:29:59 +0000</pubDate>
		<dc:creator>Steve Schwartz</dc:creator>
				<category><![CDATA[Engineering]]></category>
		<category><![CDATA[Open-source]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Things I've Learned]]></category>
		<category><![CDATA[Business]]></category>
		<category><![CDATA[communication]]></category>
		<category><![CDATA[writing]]></category>

		<guid isPermaLink="false">http://www.alfajango.com/blog/?p=1901</guid>
		<description><![CDATA[Engineers are not known for being the best communicators. Technical details? No problem. Explaining things in plain English? Err, that's a different story. I've seen a lot of opportunities missed due to miscommunication through my career as a Mechanical and Electrical Engineer, then as a "Marketing Engineer" (where my entire job was to translate between the engineering specs and the non-engineers ("I'm a people-person!")), and most recently, as a startup founder and developer. Below is an analysis and suggestion for improving the state of your projects by improving communication in your team.]]></description>
			<content:encoded><![CDATA[<p>
Engineers and developers are not known for being the best communicators. Technical details? No problem. Explaining things in plain English? Err, that&#8217;s a different story. I&#8217;ve seen entire projects flounder from ineffective communication through my career as an engineer.
</p>
<p>
Since transitioning to the role of startup founder and open-source developer, communication has become an even larger part of my day. Below is an analysis, including my humble suggestions, for improving the state of your projects by improving your team&#8217;s ability to communicate.
</p>
<div class="note">
<p>
A special thanks to <a href="http://greatlakesrubybash.com/speakers/">Cory Flanigan</a> (<a href="http://twitter.com/seeflanigan">@seeflanigan</a>), who gave a talk at Great Lakes Ruby Bash 2011 entitled, <em>Communicating Effectively for Fun and Profit</em>, which prompted me to write this, and also for providing feedback on this article.
</p>
</div>
<p><img src="http://www.alfajango.com/blog/wp-content/uploads/2011/08/Dwight-Schrute-False-cropped.jpg" alt="" title="Dwight-Schrute-False-cropped" width="298" height="310" class="alignright size-full wp-image-2088" /></p>
<p>
<em>Communication is about winning. Whenever you engage someone in communication, it is a competition. Who has the better story? Who can talk/write more? Who has the better code? And if you don&#8217;t win, you lose.</em>
</p>
<p>
False.
</p>
<p>
Fact: if you win a conversation, then you also lose. This is especially true when your conversation must accomplish some achievable goal.
</p>
<h2>Actionable discussion</h2>
<p>
Let&#8217;s first define &#8220;actionable conversation&#8221; as that in which we are trying to achieve some explicit goal, whether to persuade someone of something or to find a solution to some problem.
</p>
<p>
Now, let&#8217;s divide actionable conversation topics as one of two types:
</p>
<h3>Opinion vs opinion</h3>
<p>
The majority of the time, there is no right or wrong, only opinion and differing opinion. To consider yourself right here is to disregard the differing opinion as decidedly wrong. Be careful, doing this makes it difficult to ever grow and learn.
</p>
<h3>Fact (true vs false)</h3>
<p>
Then there are topics for which there is a right and wrong. Let&#8217;s say you and I are arguing the solution to 1 + 1 = 2. You say it&#8217;s 2, but I say it&#8217;s 3. In a technical sense, you are right and I am wrong.
</p>
<p><span id="more-1901"></span></p>
<p>
In the context of communication, though, what is the point of being right if you can&#8217;t convince others, or help them to arrive at the correct conclusion with you? If you are arguing with me, then you&#8217;ve already deemed it worthwhile to convince me. Therefore, our conversation is not about being right, it&#8217;s about convincing me that you&#8217;re right. And in this regard, you may be right and still be wrong.
</p>
<p>
Furthermore, true/false is a zero-sum game; if you win, then I must have lost. And if I lost, then I must not be on the winning side with you. And if I&#8217;m not on the winning side with you, then you must not have thoroughly convinced me. Which means, in the context of the conversation at hand, you still lost.
</p>
<p>
This doesn&#8217;t even address the effect &#8220;winning&#8221; has on your ability to engage me in future conversations.
</p>
<p>
The only way to actually win a conversation is to make sure we both win.
</p>
<p>
When arguing fact against someone&#8217;s disregard for fact, the best thing you can do is this:</p>
<ol>
<li>Present your facts</li>
<li>Listen to mine</li>
<li>Acknowledge the validity of my side (even if I&#8217;m wrong, there must be <em>some</em> convincing reasoning behind it for me to disregard your facts)</li>
<li>Leave it alone. This is called, picking your battles.</li>
</ol>
<p>
In other words, pick your battles.
</p>
<p>
<strong>The only winning conversation is the conversation in which everyone wins.</strong> In a game of Ego, the only winning move is not to play.
</p>
<h2>Persuasion</h2>
<p>
When trying to affect change, we often need to convince someone to help. There are entire books on the art of persuasion <sup>[<a href="#ref-1">1</a>]</sup>, so I won&#8217;t delve deeply into the subject here. I will instead share one lesson I&#8217;ve learned the hard way: <strong>Once a person becomes defensive, the conversation is over.</strong>
</p>
<p>
Human intelligence is an interesting thing. We tell ourselves that we employ logic to arrive at conclusions. More often though, we use emotion to arrive at conclusions, and then we mold logic to justify them. Sometimes it&#8217;s astounding how malleable logic can be. Once someone becomes emotionally attached to their idea, logic becomes irrelevant <sup>[<a href="#ref-2">2</a>]</sup>.
</p>
<p>
The lesson here is to <strong>avoid turning any conversation into an issue of right and wrong, because then it is a competition. Competition evokes emotion and entrenches people in opposition.</strong> Instead, consider every conversation as an opportunity for everyone involved to grow, learn, and develop together.
</p>
<h2>Communication and software / engineering</h2>
<p>
Bringing these concepts back around to software and engineering, every conversation should be viewed as an opportunity to increase the project&#8217;s reliability and applicability. If you can increase everyone&#8217;s understanding of the project, consider the dialogue a success. This is a subtle departure from the norm, where conversations are started to fix a project that is broken in some regard, or to explain why the other person is doing it wrong.
</p>
<p>
For example, don&#8217;t submit a bug report with the mindset that &#8220;this code is bad, causing this bug in this situation.&#8221; Instead, think, &#8220;here&#8217;s an opportunity to make this code applicable for this situation.&#8221; This simple change of perspective will come through in your communication and make it much easier for the recipient to react in a positive way.
</p>
<h2>Communicating with engineers</h2>
<p>
Enough of the mental voodoo; how do we actually communicate with other engineers?
</p>
<p><img src="http://www.alfajango.com/blog/wp-content/uploads/2011/08/iStock_000004434349XSmall-cropped.jpg" alt="" title="iStock_000004434349XSmall-cropped" width="290" height="282" class="alignright size-full wp-image-2084" /></p>
<p>
<strong>Engineers and software developers tend to view ambiguity and verbosity as fluff that weakens the point and hurts credibility; we tend to be succinct. However, succinctness and efficiency can easily be perceived as assertiveness and aggressiveness, which can trigger defensiveness and effectively kill the conversation.</strong>
</p>
<p>
In the real world, to prevent others from becoming defensive, we soften our stance with &#8220;I think that&#8230;&#8221;, or &#8220;I feel that&#8230;&#8221;, and use other qualifying terms like, &#8220;maybe&#8221; or &#8220;perhaps&#8221;. In the engineering and programming worlds, these can be downright annoying, especially in written form. So we must walk this line. We must learn to understand our situation, audience, and goal; tailoring our message accordingly.
</p>
<h2>Communication in open-source</h2>
<p>
Communication can be a barrier to progress from the perspectives of both the user and the maintainer of open-source software.
</p>
<h3>When submitting patches or bug reports (as a user)</h3>
<p>
When submitting a patch or bug report, realize that the project is someone&#8217;s creation, the product of their time, work, and care. It&#8217;s their baby. Their reward comes from others who use and benefit from their work (and the recognition that comes with it). Avoid telling them their baby is ugly.
</p>
<p>
Make it clear that you see this as an opportunity to improve their project. Avoid making demands which convey entitlement (e.g. &#8220;this is a serious bug that needs to be fixed now&#8221;). At the same time, don&#8217;t powder your prose with disingenuous praise or flattery; this is tomfoolery, and engineers are sensitive to that. (We tend to be easily annoyed).
</p>
<h3>When responding to patches or bug reports<br />
(as a maintainer)</h3>
<p>
More importantly, to open-source authors: realize that <strong>the worst thing we can do is discourage people from submitting patches or starting and engaging in conversations about our projects.</strong>
</p>
<p>
We often receive bug reports where our first response is, &#8220;You&#8217;re doing it wrong.&#8221; This is discouraging to the submitter and potentially embarrassing. One technique I use in this situation is to assume that I&#8217;ve misunderstood the problem. In these situations, I start with some form of, &#8220;I don&#8217;t think I understand the issue you&#8217;re having,&#8221; which leads into, &#8220;Could this be accomplished this other way instead?&#8230;&#8221;
</p>
<p>
Often this yields one of two outcomes:
</p>
<ol>
<li>
    They read through my alternative solution and realize it does work. I usually get some response like, &#8220;Oh, you&#8217;re right, I get it now, thank you!&#8221;
  </li>
<li>
    Or they explain why my solution won&#8217;t work. Now I understand their problem better, and can either pull in their code or start working on a solution.
  </li>
</ol>
<p>
In either scenario, we&#8217;ve both won. In the first scenario, I&#8217;ve helped them to grow and learn without embarrassment (a necessary part of a conducive learning environment). In the second scenario, I&#8217;ve learned the true nature of their problem by working with them, rather than assuming they were wrong and then having to backtrack &#8212; embarrassing myself in the process.
</p>
<p>
In either case, I try to conclude by making it clear that their time and efforts are appreciated. Even if they were wrong, the fact is that some level of reasoning brought them to that conclusion. Chances are, others are on the same path. Also, they will now be able to apply the sort of reasoning you gave to their next issue.
</p>
<p>
Open-source authors, remember that people who submit patches to your projects are not saying that you&#8217;re wrong or incompetent. If they believed that, they wouldn&#8217;t use your project. You have the upper hand in this situation, so it is ultimately your responsibility to ease the tension.
</p>
<p>
Give every ticket the benefit of the doubt. Instead of immediately concluding that the other person is doing it wrong, assume you don&#8217;t completely understand what they&#8217;re trying to accomplish. This is an opportunity for everyone who sees the project, to grow.
</p>
<h3>Pulling in user-submitted patches</h3>
<p>
One last thing while I&#8217;m on the subject. If someone submits a patch that comes close to something you&#8217;d want in your open-source project, pull it in!
</p>
<p>
I&#8217;ve seen the following situation happen too often:
</p>
<ol>
<li>Someone submits a patch (or pull-request) for some open-source project.</li>
<li>One of the project&#8217;s maintainers asks a couple questions about the patch.
  </li>
<li>The maintainer doesn&#8217;t like some aspect of the submitter&#8217;s code, so they implement the solution themselves and then close the submitter&#8217;s ticket.</li>
</ol>
<p>
I think one of the reasons this happens is that the maintainer has been on the other side of the fence (being the maintainer of a successful project), for so long, having responded to hundreds or thousands of questions, comments, and commits project. They&#8217;ve forgotten how rewarding it is for other developers to see just one of their patches or ideas incorporated.
</p>
<p>
The next time you find yourself about to do this, I propose a different approach. If their code requires numerous changes, politely ask them to make those changes, and resubmit the patch. To really encourage collaboration, provide them with some guidance or encourage them to further improve their solution.
</p>
<p class="in-depth">
Protip: On Github, they don&#8217;t even need to submit a new pull request. They can make the necessary change(s), amend their last commit (<code class="codecolorer text dawn"><span class="text">git commit --amend</span></code>) and then force push to their branch (<code class="codecolorer text dawn"><span class="text">git push -f myrepo fixbranch</span></code>). The existing pull request will be magically updated.
</p>
<p>
If only minor changes are needed, such that it&#8217;s not worth the effort of asking them to make said changes:</p>
<ol>
<li>merge in the submitter&#8217;s patch</li>
<li>make any necessary changes <em>in a new commit</em></li>
<li>push both commits to the public repo at once</li>
</ol>
<p>
If they submitted a patch, it shows they have invested the time and effort to fork your project, figure out your code, research and solve the issue, then make and test their changes. To see their work re-implemented and pulled into the codebase without recognition or thanks is demoralizing, if not altogether insulting.
</p>
<p>
I won&#8217;t say I&#8217;m guilt-free of committing such atrocities myself. <a href="https://github.com/rails/jquery-rails/pull/6#issuecomment-1363385">When I have made this sort of mistake</a>, I&#8217;ve tried to make it abundantly clear why. I did this by assuring the submitter their work was appreciated and encouraging them to continue submitting patches and bug reports in the future.
</p>
<h2>Conclusion</h2>
<p>
Effective interpersonal communication can be difficult, but learning actionable techniques helps overcome common barriers that prevent progress and growth in open-source, software, engineering, and the world. Above all else, cultivate the habit to recognize how your communication is perceived by your audience in order to increase reception and make your message more effective. Likewise, learn to recognize when your own emotions are preventing you from being receptive to new ideas and possibilities.
</p>
<h2>TL;DR <em>(too long; didn&#8217;t read)</em></h2>
<ul>
<li>Communication is important.</li>
<li>All conversations should be seen as an opportunity to learn and grow, for all constituents.</li>
<li>Emotion trumps logic; avoid letting emotions enter technical conversations.</li>
<li>Once someone becomes defensive, the conversation is over.</li>
<li>Engineers like succinctness. This can be misconstrued as aggressive or rude; walk that line carefully.</li>
<li>Be courteous but clear when submitting patches or bug reports to open-source projects.</li>
<li>If someone submits a patch to your open-source project, don&#8217;t dismiss their work by re-implementing their patch yourself.</li>
<li>NEVER discourage anyone from submitting patches or bug reports to your open-source project, or any other.</li>
<li>Effective communication is a skill worth improving, inside engineering and out.</li>
</ul>
<div class="resources">
<ul>
<li id="ref-1">[1] <a href="http://www.amazon.com/gp/product/0385528752/ref=as_li_ss_tl?ie=UTF8&#038;tag=persblog03c-20&#038;linkCode=as2&#038;camp=217145&#038;creative=399369&#038;creativeASIN=0385528752">Switch: How to Change Things When Change Is Hard</a><img src="http://www.assoc-amazon.com/e/ir?t=&#038;l=as2&#038;o=1&#038;a=0385528752&#038;camp=217145&#038;creative=399369" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />
</li>
<li id="ref-2">[2] Once people become emotionally attached to a conclusion, knowledge of facts does little to dissuade them. See <a href="http://www.washingtonpost.com/wp-dyn/content/article/2007/09/03/AR2007090300933.html">this Washington Post article on the Persistance of Myths</a>. Also see <a href="http://mindhacks.com/2007/09/05/infowar-strike-early-strike-often/">this related article</a> and <a href="http://www.psy.uwa.edu.au/Users%20web%20pages/cogscience/documents/Lewandowsky%20et%20al%20(2005)%20-%20Memory%20Iraq.pdf">this PDF</a> study delving further into a similar study.</li>
</ul>
</div>
<img src="http://feeds.feedburner.com/~r/alfajango/~4/1STpUPx2jX4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.alfajango.com/blog/communicating-with-engineers-and-contributing-to-open-source/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://www.alfajango.com/blog/communicating-with-engineers-and-contributing-to-open-source/</feedburner:origLink></item>
		<item>
		<title>jQuery EasyTabs v2.3 released – AJAX tabs and more</title>
		<link>http://feedproxy.google.com/~r/alfajango/~3/mrK_evzggg0/</link>
		<comments>http://www.alfajango.com/blog/jquery-easytabs-v2-3-released-ajax-tabs-and-more/#comments</comments>
		<pubDate>Thu, 15 Sep 2011 15:18:29 +0000</pubDate>
		<dc:creator>Steve Schwartz</dc:creator>
				<category><![CDATA[HTML5]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[JQuery]]></category>
		<category><![CDATA[Open-source]]></category>

		<guid isPermaLink="false">http://www.alfajango.com/blog/?p=2019</guid>
		<description><![CDATA[The jQuery EasyTabs plugin has recently hit v2.3 (well, v2.3.3 by the time I got this published). New for EasyTabs this release: Load tabs via AJAX, Nest tab-set inside another tab-set, Use non-standard markup for panels (for example, fieldsets inside a form).]]></description>
			<content:encoded><![CDATA[<p>
The jQuery EasyTabs plugin has recently hit v2.3 (well, v2.3.3 by the time I got this published). New for EasyTabs this release:
</p>
<ul>
<li><a href="#ajax-tabs">Load tabs via AJAX</a></li>
<li><a href="#nested">Nest tab-set inside another tab-set</a></li>
<li><a href="#non-standard">Use non-standard markup for panels (for example, fieldsets inside a form)</a></li>
</ul>
<p class="note">
See demos for each new feature below
</p>
<p><a name="ajax-tabs"></a></p>
<h2>AJAX tab content</h2>
<p>
It&#8217;s been a long-time coming, and it&#8217;s finally here. EasyTabs now supports loading content into panels via ajax.
</p>
<p>
EasyTabs has always placed emphasis on semantic, meaningful markup. Traditionally, markup for a tab/panel pair would look something like this:
</p>
<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;#panel-1&quot;</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;tabs&quot;</span>&gt;</span>I'm a tab<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a>&gt;</span><br />
<span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">div</span></a> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;panel-1&quot;</span>&gt;</span>Panel content<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">div</span></a>&gt;</span></div></div>
<p>
Notice that in the above example, if JavaScript is disabled, we&#8217;re left with a normal anchor and anchor link in the page, which browsers understand by default.
</p>
<p><span id="more-2019"></span></p>
<p>
The easiest way to modify a tab in order to specify that it&#8217;s content comes from some ajax url would have been to add an HTML5 <code class="codecolorer html4strict dawn"><span class="html4strict">data-</span></code> attribute, such as <code class="codecolorer html4strict dawn"><span class="html4strict">data-ajax</span></code>. However, if JS were disabled, we&#8217;re now left with an anchor link to an empty div on the page, with the actual url hidden behind a function-less data attribute.
</p>
<p>
So instead, I took a different approach with EasyTabs. If we want content for a tab to be loading via ajax, we put our ajax url in the <code class="codecolorer html4strict dawn"><span class="html4strict">href</span></code> attribute where it belongs, and move the <code class="codecolorer html4strict dawn"><span class="html4strict">id</span></code> of the target panel to a data attribute called <code class="codecolorer html4strict dawn"><span class="html4strict">data-target</span></code>.
</p>
<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;/some/ajax/path.html&quot;</span> data-<span style="color: #000066;">target</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;#panel-1&quot;</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;tabs&quot;</span>&gt;</span>I'm a tab<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a>&gt;</span><br />
<span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">div</span></a> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;panel-1&quot;</span>&gt;</span>Panel content<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">div</span></a>&gt;</span></div></div>
<p>
We can also load a page fragment with something like:
</p>
<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;/some/ajax/path.html #some-element&quot;</span> data-<span style="color: #000066;">target</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;#panel-1&quot;</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;tabs&quot;</span>&gt;</span>I'm a tab<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a>&gt;</span></div></div>
<p>
By default, EasyTabs will load the content via ajax the first time the tab is clicked, and then hide/show the loaded content in the panel for each tab-change thereafter. If we want to have the tab re-request the ajax content each time it&#8217;s clicked, we can set <code class="codecolorer javascript dawn"><span class="javascript"><span style="color: #009900;">&#123;</span> cache<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">false</span> <span style="color: #009900;">&#125;</span></span></code> in the easytabs options.
</p>
<p>
And finally, there are two new event hooks to which we can bind custom functionality, which will only be fired for ajax tabs: <code class="codecolorer javascript dawn"><span class="javascript">easytabs<span style="color: #339933;">:</span>ajax<span style="color: #339933;">:</span>beforeSend</span></code> and <code class="codecolorer javascript dawn"><span class="javascript">easytabs<span style="color: #339933;">:</span>ajax<span style="color: #339933;">:</span>complete</span></code>.
</p>
<p>
For example:
</p>
<div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#container'</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; .<span style="color: #660066;">bind</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'easytabs:ajax:beforeSend'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>e<span style="color: #339933;">,</span> clicked<span style="color: #339933;">,</span> panel<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> $this <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span>clicked<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; $this.<span style="color: #660066;">data</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'label'</span><span style="color: #339933;">,</span> $this.<span style="color: #660066;">html</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; $this.<span style="color: #660066;">html</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'Loading...'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; .<span style="color: #660066;">bind</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'easytabs:ajax:complete'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>e<span style="color: #339933;">,</span> clicked<span style="color: #339933;">,</span> panel<span style="color: #339933;">,</span> response<span style="color: #339933;">,</span> <span style="color: #000066;">status</span><span style="color: #339933;">,</span> xhr<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> $this <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span>clicked<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; $this.<span style="color: #660066;">html</span><span style="color: #009900;">&#40;</span>$this.<span style="color: #660066;">data</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'label'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000066;">status</span> <span style="color: #339933;">==</span> <span style="color: #3366CC;">&quot;error&quot;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> msg <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;Sorry but there was an error: &quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;#error&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">html</span><span style="color: #009900;">&#40;</span>msg <span style="color: #339933;">+</span> xhr.<span style="color: #000066;">status</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot; &quot;</span> <span style="color: #339933;">+</span> xhr.<span style="color: #660066;">statusText</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<ul class="group-buttons">
<li class="group-button first-child last-child">
                <a href="http://os.alfajango.com/easytabs/#ajax-tabs"><strong><br />
                        <img src="/blog/wp-content/themes/aj/images/rocket-fly.png" /> View AJAX tab demo</strong></a></li>
</ul>
<p><a name="nested"></a></p>
<h2>Nested tabs and anchors</h2>
<p>
We&#8217;ve always been able to have multiple instances of EasyTabs on one page. However, we couldn&#8217;t previously deep-link to a tab-set which was nested inside the panel of another tab. That is no longer a problem.
</p>
<p>
So for example, if we had markup such as this:
</p>
<div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#tabs'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">easytabs</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#subtabs'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">easytabs</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">div</span></a> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;#tabs&quot;</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;#panel-1&quot;</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;tabs&quot;</span>&gt;</span>Tab 1<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;#panel-2&quot;</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;tabs&quot;</span>&gt;</span>Tab 2<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">div</span></a> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;panel-1&quot;</span>&gt;</span>Panel content<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">div</span></a>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">div</span></a> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;panel-2&quot;</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">div</span></a> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;#subtabs&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;#subpanel-1&quot;</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;tabs&quot;</span>&gt;</span>Subtab 1<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a>&gt;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;#subpanel-2&quot;</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;tabs&quot;</span>&gt;</span>Subtab 2<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a>&gt;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">div</span></a> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;subpanel-1&quot;</span>&gt;</span>Panel content<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">div</span></a>&gt;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">div</span></a> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;subpanel-2&quot;</span>&gt;</span>Link to me!<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">div</span></a>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">div</span></a>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">div</span></a>&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">div</span></a>&gt;</span></div></div>
<p>
We can now bookmark Subtab 2 directly, by sharing <code class="codecolorer text dawn"><span class="text">http://example.com/page#subpanel-2</span></code>, and EasyTabs will automatically open panel-2 <em>and</em> subpanel-2 by default when the page loads.
</p>
<ul class="group-buttons">
<li class="group-button first-child last-child">
                <a href="http://os.alfajango.com/easytabs/#more-demos"><strong><br />
                        <img src="/blog/wp-content/themes/aj/images/rocket-fly.png" /> View nested demo</strong></a></li>
</ul>
<p><a name="non-standard"></a></p>
<h2>Non-standard markup for panels</h2>
<p>
Panels no longer need to be <code class="codecolorer text dawn"><span class="text">div</span></code> element, they can now be any markup we want. For example, the following now works:
</p>
<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/ul.html"><span style="color: #000000; font-weight: bold;">ul</span></a>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/li.html"><span style="color: #000000; font-weight: bold;">li</span></a>&gt;&lt;<a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;#tab1&quot;</span>&gt;</span>Tab 1<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a>&gt;&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/li.html"><span style="color: #000000; font-weight: bold;">li</span></a>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/li.html"><span style="color: #000000; font-weight: bold;">li</span></a>&gt;&lt;<a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;#tab2&quot;</span>&gt;</span>Tab 2<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/a.html"><span style="color: #000000; font-weight: bold;">a</span></a>&gt;&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/li.html"><span style="color: #000000; font-weight: bold;">li</span></a>&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/ul.html"><span style="color: #000000; font-weight: bold;">ul</span></a>&gt;</span><br />
<span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/fieldset.html"><span style="color: #000000; font-weight: bold;">fieldset</span></a> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;tab1&quot;</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/label.html"><span style="color: #000000; font-weight: bold;">label</span></a>&gt;</span>Tab 1 input<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/label.html"><span style="color: #000000; font-weight: bold;">label</span></a>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/input.html"><span style="color: #000000; font-weight: bold;">input</span></a> <span style="color: #000066;">type</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;text&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/fieldset.html"><span style="color: #000000; font-weight: bold;">fieldset</span></a>&gt;</span><br />
<span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/fieldset.html"><span style="color: #000000; font-weight: bold;">fieldset</span></a> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;tab2&quot;</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/label.html"><span style="color: #000000; font-weight: bold;">label</span></a>&gt;</span>Tab 2 input<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/label.html"><span style="color: #000000; font-weight: bold;">label</span></a>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<a href="http://december.com/html/4/element/input.html"><span style="color: #000000; font-weight: bold;">input</span></a> <span style="color: #000066;">type</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;text&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><a href="http://december.com/html/4/element/fieldset.html"><span style="color: #000000; font-weight: bold;">fieldset</span></a>&gt;</span></div></div>
<ul class="group-buttons">
<li class="group-button first-child last-child">
                <a href="http://os.alfajango.com/easytabs/#more-demos"><strong><br />
                        <img src="/blog/wp-content/themes/aj/images/rocket-fly.png" /> View custom panel markup demo</strong></a></li>
</ul>
<h2>Get it now!</h2>
<p>
Check out the updated plugin homepage to download and view the docs.
</p>
<ul class="group-buttons">
<li class="group-button first-child">
                <a href="/blog/jquery-easytabs-plugin/"><strong><br />
                        <img src="/blog/wp-content/themes/aj/images/document-globe.png" /> View plugin homepage</strong></a></li>
<li class="group-button last-child">
                <a href="https://github.com/JangoSteve/jQuery-EasyTabs/wiki/CHANGELOG"><strong><br />
                        <img src="/blog/wp-content/themes/aj/images/edit-list.png" /> View changelog</strong></a></li>
</ul>
<img src="http://feeds.feedburner.com/~r/alfajango/~4/mrK_evzggg0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.alfajango.com/blog/jquery-easytabs-v2-3-released-ajax-tabs-and-more/feed/</wfw:commentRss>
		<slash:comments>46</slash:comments>
		<feedburner:origLink>http://www.alfajango.com/blog/jquery-easytabs-v2-3-released-ajax-tabs-and-more/</feedburner:origLink></item>
		<item>
		<title>Remotipart 1.0 Released</title>
		<link>http://feedproxy.google.com/~r/alfajango/~3/w6GhWynM4Ew/</link>
		<comments>http://www.alfajango.com/blog/remotipart-1-0-released/#comments</comments>
		<pubDate>Wed, 31 Aug 2011 21:49:00 +0000</pubDate>
		<dc:creator>Steve Schwartz</dc:creator>
				<category><![CDATA[JQuery]]></category>
		<category><![CDATA[Open-source]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[gems]]></category>
		<category><![CDATA[jquery-ujs]]></category>
		<category><![CDATA[Rails 3]]></category>
		<category><![CDATA[Remotipart]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://www.alfajango.com/blog/?p=2097</guid>
		<description><![CDATA[Just 6 weeks after the announcement of v0.4, I'm pleased to announce the release of Remotipart v1.0. With this release, AJAX file uploads in Rails 3.0 and 3.1 (building off the standard jquery-ujs driver) are as easy as humanly conceivable.]]></description>
			<content:encoded><![CDATA[<p>
Just 6 weeks after the announcement of v0.4, I&#8217;m pleased to announce the release of Remotipart v1.0. With this release, AJAX file uploads in Rails 3.0 and 3.1 (building off the standard jquery-ujs driver) are as easy as humanly conceivable. This was possible thanks to a large push from <a href="https://github.com/ajrkerr">Adam Kerr</a>.
</p>
<p>
The two major changes for v1.0 are:
</p>
<ul>
<li>New jQuery 1.6 iframe-transport instead of dependency on form.js</li>
<li>New rack middleware does away with configuration</li>
</ul>
<p class="note">
With the release of v1.0, the new officially maintained repo for Remotipart has moved <a href="https://github.com/leppert/remotipart">from here</a> to the <a href="https://github.com/JangoSteve/remotipart">JangoSteve fork on Github</a>.
</p>
<p class="in-depth">
There is also now a more robust test suite. Read more about that in the <a href="/blog/remotipart-rails-gem/">Remotipart docs</a>.
</p>
<h2>New jQuery iframe-transport</h2>
<p>
Previously, the process of submitting files via an ad-hoc iframe element and inserting the response back into the page (<a href="/blog/ajax-file-uploads-with-the-iframe-method/">described here</a>) was done by the form.js. For those who aren&#8217;t familiar, form.js is an awesome plugin that does a lot of really useful things. However, we weren&#8217;t really doing it justice by requiring it as a dependency for only one small part of its capabilities.
</p>
<p><span id="more-2097"></span></p>
<p>
Also, with the introduction of <a href="http://api.jquery.com/extending-ajax/">ajax prefilters and transports</a> in jquery 1.5, there is now a more native way of extending jquery&#8217;s standard ajax capabilities. Since I finally <a href="https://github.com/rails/jquery-ujs/commit/5433841d01622345f734f22f82394ac035c2f783">removed support for jquery 1.4 in the Rails jquery-ujs</a>, remotipart can safely rely on these new transport protocols.
</p>
<p>
And so for v1.0,  we&#8217;ve switched remotipart&#8217;s to use the <a href="http://cmlenz.github.com/jquery-iframe-transport/">jquery iframe-transport.js</a> instead.
</p>
<h2>Rack middleware</h2>
<p>
In remotipart v0.4, we added a railtie (for rails 3.0) and a rails engine (for rails 3.1) to automatically add remotipart.js and its dependencies to the JS <code class="codecolorer text dawn"><span class="text">:defaults</span></code> and asset pipeline, respectively. In v1.0, we&#8217;ve taken it another step further.
</p>
<p>
There is now a new rack middleware which sits snuggly between the request and your rails app. It automatically communicates with the iframe transport when needed.
</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ rake middleware<br />
...<br />
use ActionDispatch::ParamsParser<br />
use Remotipart::Middleware &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #666666; font-style: italic;"># &lt; = w00t</span><br />
use ActionDispatch::Head<br />
...</div></div>
<p>
Because the new middleware does all the translating necessary for ajax file uploads, you no longer need the old <code class="codecolorer text dawn"><span class="text">remotipart_response</span></code> block in your js.erb response templates.</p>
<p>
Additionally, you no longer need to request the JS data-type (you could request other data-types before, but anything other than JS or HTML could be a bit buggy in IE). Remotipart is now compatible with all data-types.</p>
<h2>AJAX file uploads are easier than ever</h2>
</p>
<p>
So what does all this mean? It means that AJAX files uploads in Rails 3 are now so incredibly easy, I have no problem dubbing this v1.0.
</p>
<p>
Let&#8217;s say you have a Rails 3 app with a remote form. Everything goes great, but then you add a file input to the form. Suddenly, the form won&#8217;t submit via ajax anymore. This is by design, since a simple ajax request is incapable of uploading files.
</p>
<p>
Just install Remotipart 1.0.
</p>
<p>
For rails 3.0 apps, run:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">bundle <span style="color: #7a0874; font-weight: bold;">exec</span> rails g remotipart:install</div></div>
</p>
<p>
For rails 3.1 apps, require remotipart.js in your <code class="codecolorer text dawn"><span class="text">app/assets/application.js</span></code>:</p>
<div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #006600; font-style: italic;">//= require jquery.remotipart</span></div></div>
</p>
<p>
Done! The form will now upload the file via ajax no problem.
</p>
<ul class="group-buttons">
<li class="group-button first-child last-child">
                <a href="/blog/remotipart-rails-gem/ "><strong><br />
                        <img src="/blog/wp-content/themes/aj/images/document-globe.png" /> View Remotipart Homepage &raquo;</strong><br />
        </a></li>
</ul>
<img src="http://feeds.feedburner.com/~r/alfajango/~4/w6GhWynM4Ew" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.alfajango.com/blog/remotipart-1-0-released/feed/</wfw:commentRss>
		<slash:comments>33</slash:comments>
		<feedburner:origLink>http://www.alfajango.com/blog/remotipart-1-0-released/</feedburner:origLink></item>
		<item>
		<title>Rails 3 AJAX File Uploads with Remotipart</title>
		<link>http://feedproxy.google.com/~r/alfajango/~3/0iKbvR-y78M/</link>
		<comments>http://www.alfajango.com/blog/rails-3-ajax-file-uploads-with-remotipart/#comments</comments>
		<pubDate>Tue, 12 Jul 2011 15:42:15 +0000</pubDate>
		<dc:creator>Steve Schwartz</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[JQuery]]></category>
		<category><![CDATA[Open-source]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[AJAX]]></category>
		<category><![CDATA[jquery-ujs]]></category>
		<category><![CDATA[Rails 3]]></category>
		<category><![CDATA[Remotipart]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://www.alfajango.com/blog/?p=1791</guid>
		<description><![CDATA[Rails 3 uses Unobtrusive JavaScript for remote links and forms. However, because jquery-ujs relies on jQuery's standard .ajax() function, it is incapable of doing AJAX file uploads. Remotipart to the rescue! Remotipart enables AJAX form-uploading in Rails 3 remote forms.]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.alfajango.com/blog/wp-content/uploads/2011/05/rails-remote-file-upload-300x240.jpg" alt="" title="rails-remote-file-upload" width="300" height="240" class="alignright size-medium wp-image-1813" /></p>
<p>
In <a href="/blog/ajax-file-uploads-with-the-iframe-method/">my last article</a>, we discussed the difficulties of file-uploads via AJAX, and how the iFrame method works around the issues to provide an AJAX-like interface for uploading files to the server.
</p>
<p>
<em>So how does this relate to Rails?</em>
</p>
<p>
Rails 3 <a href="/blog/rails-3-remote-links-and-forms">uses Unobtrusive JavaScript</a> for remote links and forms (and comes packaged with the jquery-ujs driver via the jquery-rails gem as of Rails 3.1!). However, because jquery-ujs relies on jQuery&#8217;s standard <code class="codecolorer javascript dawn"><span class="javascript">.<span style="color: #660066;">ajax</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span></span></code> function, it is incapable of doing AJAX file uploads.
</p>
<h2>The Remotipart gem</h2>
<p>
Remotipart to the rescue! The Remotipart gem does two things:
</p>
<p><span id="more-1791"></span></p>
<ol>
<li>When non-blank file input fields are detected in a form, remotipart.js hijacks the remote form submission, and instead submits the form using via form.js&#8217;s <code class="codecolorer javascript dawn"><span class="javascript">.<span style="color: #660066;">ajaxSubmit</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span></span></code> function, which uses iFrame technique described in the last article.</li>
<li>Secondly, Remotipart provides the <code class="codecolorer ruby dawn"><span class="ruby">remotipart_response</span></code> block method in our response js.erb views. This method first checks to see if the form was hijacked by Remotipart and was thus submitted in an iFrame, and if so, it returns our generated JS inside a textarea element, so that it automatically gets executed in our parent window.</li>
</ol>
<p class="note">
If you&#8217;re curious about the name, it&#8217;s a contraction of &#8220;remote&#8221; and &#8220;multipart&#8221;, as in multipart forms for file uploading. Pronounced <em>remote-ee-part</em>.
</p>
<h2>Getting started</h2>
<p class="updated">
Update: Newer versions have been released since this post. <a href="/blog/remotipart-rails-gem/">See the Remotipart homepage</a> for the most up-to-date info.
</p>
<h3>New release! Remotipart 0.4 for Rails 3.0 and 3.1</h3>
<p>
I just released Remotipart version 0.4, re-written to work seamlessly with Rails 3 apps. Among other conveniences, this makes installation much simpler. Also, for Rails 3.1 apps, it now works with the built-in asset pipeline.
</p>
<h3>Check it out</h3>
<p>
For installation, documentation, and demos, check out the new Remotipart homepage:
</p>
<ul class="group-buttons">
<li class="group-button first-child last-child">
                <a href="/blog/remotipart-rails-gem/ "><strong><br />
                        <img src="/blog/wp-content/themes/aj/images/document-globe.png" /> View Remotipart Homepage &raquo;</strong><br />
        </a></li>
</ul>
<h2>A note on extending Rails jQuery UJS</h2>
<p>
Because we&#8217;ve <a href="/blog/rails-jquery-ujs-now-interactive/">opened up jquery-ujs&#8217;s internal functions</a> to be interactive and configurable, it is now easy to augment and build plugins on top of jquery-ujs. Check out the <a href="https://github.com/formasfunction/remotipart">Remotipart source on Github</a> to see this capability in action.</p>
<img src="http://feeds.feedburner.com/~r/alfajango/~4/0iKbvR-y78M" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.alfajango.com/blog/rails-3-ajax-file-uploads-with-remotipart/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		<feedburner:origLink>http://www.alfajango.com/blog/rails-3-ajax-file-uploads-with-remotipart/</feedburner:origLink></item>
		<item>
		<title>AJAX File Uploads with the iFrame Method</title>
		<link>http://feedproxy.google.com/~r/alfajango/~3/EmhiRFDuXso/</link>
		<comments>http://www.alfajango.com/blog/ajax-file-uploads-with-the-iframe-method/#comments</comments>
		<pubDate>Mon, 09 May 2011 20:05:25 +0000</pubDate>
		<dc:creator>Steve Schwartz</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[JQuery]]></category>
		<category><![CDATA[AJAX]]></category>

		<guid isPermaLink="false">http://www.alfajango.com/blog/?p=1785</guid>
		<description><![CDATA[AJAX file uploads, how do they work?! Well, they kinda don't. Browsers don't allow file uploads via XMLHttpRequest (aka XHR) for security reasons. If we try to submit a form remotely via XHR, it will work, except with the file field stripped out of the request parameters. This sort of partial, silent failure can lead to unicorn black-eyes. (I punch unicorns in the face when I'm frustrated.)]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.alfajango.com/blog/wp-content/uploads/2011/05/ajax-file-uploads-300x236.jpg" alt="" title="ajax-file-uploads" width="300" height="236" class="alignright size-medium wp-image-1805" /></p>
<p>
AJAX file uploads, how do they work?! Well, they kinda don&#8217;t.
</p>
<p>
Browsers don&#8217;t allow file uploads via <a href="http://en.wikipedia.org/wiki/XMLHttpRequest">XMLHttpRequest (aka XHR)</a> for security reasons. If we try to submit a form remotely via XHR, it will work, except with the file field stripped out of the request parameters. This sort of partial, silent failure can lead to unicorn black-eyes. (I punch unicorns in the face when I&#8217;m frustrated.)
</p>
<div class="in-depth">
<p>
This is how jQuery&#8217;s standard AJAX functions work, including <code class="codecolorer javascript dawn"><span class="javascript">.<span style="color: #660066;">ajax</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span></span></code>.
</p>
<p>
In turn, the Rails 3 jQuery UJS driver uses jQuery&#8217;s standard AJAX functions internally. To prevent this sort of silent failure in Rails 3, we added the <code class="codecolorer javascript dawn"><span class="javascript">ajax<span style="color: #339933;">:</span>aborted<span style="color: #339933;">:</span>file</span></code> event to abort the remote form submission if any non-blank file inputs are detected.
</p>
<p>
<em>See <a href="/blog/new-ajax-aborted-rails-jquery-ujs-callbacks/">New ajax:aborted Rails jQuery UJS Hooks</a>.</em>
</p>
</div>
<h2>Workarounds</h2>
<p>
So, there are a couple workarounds that give the impression of AJAX file uploads (and thus the same workflow and UI from the user&#8217;s perspective), without actually submitting the file via XHR.
</p>
<p><span id="more-1785"></span></p>
<p>
One method is to use Flash. Since Flash makes connects to the server outside the scope of the browser&#8217;s connection, it essentially plays by it&#8217;s own rules.
</p>
<p>
Another, more popular method (since it works in browsers without requiring Flash to be installed) is known as <em>the iFrame method</em>. And here&#8217;s how it works.
</p>
<h2>The iFrame method</h2>
<p class="note">
From here on, I&#8217;ll be referring specifically to the <code class="codecolorer javascript dawn"><span class="javascript">ajaxSubmit<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span></span></code> method built into the <a href="https://github.com/malsup/form">jQuery form.js plugin</a>, but the concepts are generally the same for any library that uses the iFrame method.
</p>
<p>
Assuming we have a form with a file-type input field, the iFrame method of uploading files can be summarized in the following steps:
</p>
<ol>
<li>Hijack the forms <code class="codecolorer javascript dawn"><span class="javascript">submit</span></code> event to execute our custom iFrame-method function (e.g. <code class="codecolorer javascript dawn"><span class="javascript">.<span style="color: #660066;">ajaxSubmit</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span></span></code> from the form.js plugin).<br />
        <img src="http://www.alfajango.com/blog/wp-content/uploads/2011/05/iframe-method-step-0.png" alt="" title="iframe-method-step-0" width="412" height="179" class="alignnone size-full wp-image-1851" />
        </li>
<li>Using JavaScript, create an iFrame element and insert it into the current page (and make the iFrame tiny and invisible to the user).<br />
        <img src="http://www.alfajango.com/blog/wp-content/uploads/2011/05/iframe-method-step-1a.png" alt="" title="iframe-method-step-1a" width="411" height="177" class="alignnone size-full wp-image-1857" />
        </li>
<li>&nbsp;
<div class="updated">Thanks to <a href="http://www.reddit.com/r/javascript/comments/h8yri/ajax_file_uploads_with_the_iframe_method/c1tjuck">spinn over on Reddit</a> for catching this. I&#8217;ve updated this step to illustrate the more correct way.</div>
<div class="updated">Thanks to <a href="http://www.alfajango.com/blog/ajax-file-uploads-with-the-iframe-method/comment-page-1/#comment-3828">malsup in the comments</a> for keeping me honest here and suggesting a further clarification.</div>
<p>        Change the <code class="codecolorer html4strict dawn"><span class="html4strict">target</span></code> attribute of the form, such that the results of the form submission are rendered in the new iFrame instead of the current window.<br />
        <img src="http://www.alfajango.com/blog/wp-content/uploads/2011/05/iframe-method-step-1-alt-b.png" alt="" title="iframe-method-step-1-alt-b" width="408" height="176" class="alignnone size-full wp-image-1896" />
        </li>
<li>Submit the form to the iFrame normal-style (non-AJAX).<br />
        <img src="http://www.alfajango.com/blog/wp-content/uploads/2011/05/iframe-method-step-2.png" alt="" title="iframe-method-step-2" width="414" height="196" class="alignnone size-full wp-image-1853" />
        </li>
<li>Allow the iFrame to navigate to the response page (since it was submitted normal-style). Note that because this happens in the iframe, the parent window does not go to a new page or get redirected, only the hidden iFrame.<br />
        <img src="http://www.alfajango.com/blog/wp-content/uploads/2011/05/iframe-method-step-3.png" alt="" title="iframe-method-step-3" width="407" height="174" class="alignnone size-full wp-image-1854" />
        </li>
<li>Copy the response content from the iFrame back into the parent window.<br />
        <img src="http://www.alfajango.com/blog/wp-content/uploads/2011/05/iframe-method-step-4.png" alt="" title="iframe-method-step-4" width="414" height="179" class="alignnone size-full wp-image-1855" />
        </li>
<li>Delete the iFrame, reset the form&#8217;s <code class="codecolorer html4strict dawn"><span class="html4strict">target</span></code> attribute to its original value, and inform the <code class="codecolorer javascript dawn"><span class="javascript">.<span style="color: #660066;">ajaxSubmit</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span></span></code> (from form.js) function&#8217;s callback hooks that the submission is complete.<br />
        <img src="http://www.alfajango.com/blog/wp-content/uploads/2011/05/iframe-method-step-5.png" alt="" title="iframe-method-step-5" width="413" height="216" class="alignnone size-full wp-image-1856" />
        </li>
</ol>
<p>
It&#8217;s that easy! Er, not quite&#8230;
</p>
<h2>Complications</h2>
<p>
The above steps have a couple implications to further complicate things&#8230;
</p>
<h3>Response headers and status code</h3>
<p>
Since the submission takes place normal-style in an iframe, the parent window cannot inspect the response headers or status code (from step 5 above), due to browser security restrictions.
</p>
<p>
So, <code class="codecolorer javascript dawn"><span class="javascript">.<span style="color: #660066;">ajaxSubmit</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span></span></code> in the parent window must assume, once the request is completed, that it was successful. There are <a href="https://github.com/malsup/form/pull/72">ways around this</a>, but as of this writing, they have not yet been pulled into the form.js plugin.
</p>
<h3>Response JavaScript not automatically executed</h3>
<p>
Furthermore, if a JS response was returned, it won&#8217;t get executed in the parent window, because it was returned to the iframe. We would thus need to manually check if the response was JS code (instead of HTML markup or some other format), and execute it ourselves in step 7 above.
</p>
<p>
Form.js has a workaround which allows you can return some javascript code inside a textarea element as the response content. So then, if the iframe response content contains a textarea with some text value once the iframe form is submitted, it will copy that textarea content back to the parent window and execute it as javascript.
</p>
<h2>AJAX file uploads in Rails 3</h2>
<p>
Now that I&#8217;ve set the stage, in my next article, I&#8217;ll show how we can seamlessly add AJAX file upload capabilities to Rails 3 by extending jquery-ujs.
</p>
<h2>Future-proof</h2>
<p class="updated">
Thanks to <a href="http://www.alfajango.com/blog/ajax-file-uploads-with-the-iframe-method/comment-page-1/#comment-3802">Gábor in the comments below</a> for bringing this up and prompting me to add this section.
</p>
<p>
Of course, we must ask, why are the browsers making it so hard for us to do something so simple? After all, is it really making the user&#8217;s interaction any more secure if there is such a workaround, as described here, which is as useful as it is popular? The answer is, no not really. And that is why the newest browsers have started to implement an actual AJAX file upload API.
</p>
<p>
As mentioned in the comments, we can see that <a href="http://caniuse.com/#feat=fileapi">a few of the latest browsers are already supporting this</a>. For an idea of how to use this API, check out <a href="https://developer.mozilla.org/En/Using_XMLHttpRequest#Sending_files_using_a_FormData_object">Mozilla&#8217;s documentation for using it with Firefox 4</a>.</p>
<img src="http://feeds.feedburner.com/~r/alfajango/~4/EmhiRFDuXso" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.alfajango.com/blog/ajax-file-uploads-with-the-iframe-method/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		<feedburner:origLink>http://www.alfajango.com/blog/ajax-file-uploads-with-the-iframe-method/</feedburner:origLink></item>
		<item>
		<title>New ajax:aborted Rails jQuery UJS Hooks</title>
		<link>http://feedproxy.google.com/~r/alfajango/~3/Luq4l8wz1NU/</link>
		<comments>http://www.alfajango.com/blog/new-ajax-aborted-rails-jquery-ujs-callbacks/#comments</comments>
		<pubDate>Tue, 03 May 2011 16:13:48 +0000</pubDate>
		<dc:creator>Steve Schwartz</dc:creator>
				<category><![CDATA[HTML5]]></category>
		<category><![CDATA[JQuery]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[jquery-ujs]]></category>
		<category><![CDATA[Rails 3]]></category>
		<category><![CDATA[remote_form_for]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://www.alfajango.com/blog/?p=1756</guid>
		<description><![CDATA[In my last article, I talked about my push to make Rails jQuery UJS (aka jquery-ujs) more interactive and easier to customize and extend with third-party plugins. Along those same goals, let's discuss another recent change: ajax:aborted hooks.]]></description>
			<content:encoded><![CDATA[<p><img src="/blog/wp-content/uploads/2011/04/rails-remote1.jpg" alt="" title="rails-remote" width="200" height="300" class="alignleft size-full wp-image-1757" /></p>
<p>
In my last article, <a href="http://www.alfajango.com/blog/rails-jquery-ujs-now-interactive/">Rails jQuery UJS: Now Interactive</a>, I talked about my push to make Rails jQuery UJS (aka jquery-ujs) more interactive and easier to customize and extend with third-party plugins. Along those same goals, let&#8217;s discuss another recent change: <code class="codecolorer javascript dawn"><span class="javascript">ajax<span style="color: #339933;">:</span>aborted</span></code> hooks.
</p>
<p>
There are now two scenarios where remote forms will not be submitted, and the AJAX submission will instead be aborted. When this happens, jquery-ujs now publishes hooks, to which we can bind handler functions to gracefully handle these situations.
</p>
<p>
Let&#8217;s take a look at each of these scenarios and how we can utilize the event hooks.
</p>
<table width="100%">
<tr>
<th>Scenario</th>
<th>Hook name</th>
</tr>
<tr>
<td>blank required fields</td>
<td><code class="codecolorer javascript dawn"><span class="javascript">ajax<span style="color: #339933;">:</span>aborted<span style="color: #339933;">:</span>required</span></code></td>
</tr>
<tr>
<td>non-blank file inputs</td>
<td><code class="codecolorer javascript dawn"><span class="javascript">ajax<span style="color: #339933;">:</span>aborted<span style="color: #339933;">:</span>file</span></code></td>
</tr>
</table>
<h2>Required fields</h2>
<p><span id="more-1756"></span></p>
<p>
The Opera browser has some interesting behavior (useful, but inconsistent) in which forms do not get submitted if they contain any blank required inputs. So, submitting a form containing the following blank fields would cause nothing to happen:
</p>
<div class="codecolorer-container rails twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="rails codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">...<br />
<span style="color:#006600; font-weight:bold;">&lt;%</span>= f.<span style="color:#9900CC;">text_field</span> <span style="color:#ff3333; font-weight:bold;">:name</span>, <span style="color:#ff3333; font-weight:bold;">:required</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span> <span style="color:#006600; font-weight:bold;">%&gt;</span><br />
<span style="color:#006600; font-weight:bold;">&lt;%</span>= f.<span style="color:#5A0A0A; font-weight:bold;">text_area</span> <span style="color:#ff3333; font-weight:bold;">:bio</span>, <span style="color:#ff3333; font-weight:bold;">:required</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span> <span style="color:#006600; font-weight:bold;">%&gt;</span><br />
<br />
# ...which produces:<br />
&lt;input id=&quot;person_name&quot; name=&quot;person_name&quot; required=&quot;required&quot; /&gt;<br />
&lt;textarea id=&quot;person_bio&quot; name=&quot;person_bio&quot; required=&quot;required&quot; /&gt;<br />
...</div></div>
<p>
So, we implemented the same functionality in jquery-ujs for all browsers. If there are any blank required fields in a remote form, the AJAX submission is aborted, and we trigger the event hook <code class="codecolorer javascript dawn"><span class="javascript">ajax<span style="color: #339933;">:</span>aborted<span style="color: #339933;">:</span>required</span></code>. A simple example for using this hook could look like this (in our application.js or whatever):
</p>
<div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'form'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">live</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'ajax:aborted:required'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>event<span style="color: #339933;">,</span> elements<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; elements.<span style="color: #660066;">each</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; $<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">addClass</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'blank-required'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>
Notice that the required fields that caused this event to trigger are passed into our handler function, allowing us to do whatever we want with them.
</p>
<h3>Plugging in</h3>
<p>
Also, we may want to override the default behavior of jquery-ujs, and submit the form via AJAX anyway. We can do this by binding to the <code class="codecolorer javascript dawn"><span class="javascript">ajax<span style="color: #339933;">:</span>aborted<span style="color: #339933;">:</span>required</span></code> hook with a handler function that returns false. For example:
</p>
<div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'form'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">live</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'ajax:aborted:required'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>event<span style="color: #339933;">,</span> elements<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #006600; font-style: italic;">// If user answers 'OK' to confirm dialog, we return false</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #339933;">!</span> <span style="color: #000066;">confirm</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'Submit with missing information?'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p class='in-depth'>
Keep in mind that Opera does not trigger the submit event for forms with missing required fields, so the <code class="codecolorer javascript dawn"><span class="javascript">ajax<span style="color: #339933;">:</span>aborted<span style="color: #339933;">:</span>required</span></code> event would never get fired in Opera, and thus, neither would any handlers bound to this hook.
</p>
<h2>File upload fields</h2>
<p>
Due to security restrictions, browsers do not allow file uploads via AJAX. There are workarounds, including <a href="http://www.openjs.com/articles/ajax/ajax_file_upload/">the iFrame method</a>, which allow us to simulate AJAX file uploads, but they tend to be a little more involved. So, jquery-ujs now aborts attempted AJAX file uploads, and instead makes it really easy for third-party plugins to extend rails.js to handle this functionality.
</p>
<p>
The following would cause jquery-ujs to abort the AJAX submission and fire the <code class="codecolorer javascript dawn"><span class="javascript">ajax<span style="color: #339933;">:</span>aborted<span style="color: #339933;">:</span>file</span></code> event hook:
</p>
<div class="codecolorer-container rails twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="rails codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">...<br />
<span style="color:#006600; font-weight:bold;">&lt;%</span>= f.<span style="color:#5A0A0A; font-weight:bold;">file_field</span> <span style="color:#ff3333; font-weight:bold;">:avatar</span> <span style="color:#006600; font-weight:bold;">%&gt;</span><br />
<br />
# ...which produces:<br />
&lt;input type=&quot;file&quot; id=&quot;person_avatar&quot; name=&quot;person_avatar&quot; /&gt;<br />
...</div></div>
<p class="in-depth">
For the curious, if we try to submit a form containing a file input field via AJAX with jQuery, an AJAX request will be submitted to the server, but with the file input stripped out from the request parameters.
</p>
<p>
Unlike the required field functionality of jquery-ujs, file uploads don&#8217;t cause the form submission to be completely aborted. Instead, only the AJAX form submission, allowing the browser to submit the form normally with a page refresh. Also note that this behavior only occurs for <em>non-blank</em> file inputs; otherwise, the form is AJAX-submitted as usual.
</p>
<h3>Plugging in</h3>
<p>
But what if we want to cancel the browser&#8217;s standard form submission and provide our own AJAX file upload functionality, like the iFrame method mentioned above? That&#8217;s where the <code class="codecolorer javascript dawn"><span class="javascript">ajax<span style="color: #339933;">:</span>aborted<span style="color: #339933;">:</span>file</span></code> hook comes in handy. We can bind a handler to this event hook that returns false to prevent the browser&#8217;s default functionality:
</p>
<div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'form'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">live</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'ajax:aborted:file'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>event<span style="color: #339933;">,</span> elements<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #006600; font-style: italic;">// Implement own remote file-transfer handler here for non-blank file inputs</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>
Third-party gems and plugins, like our own <a href="https://rubygems.org/gems/remotipart">Rails Remotipart gem</a>, can also use this event to automatically intervene for file uploads and provide AJAX upload functionality.
</p>
<h2>Yeah buddy</h2>
<p>
I&#8217;d like to send a shout-out to <a href="https://github.com/neerajdotname">Neeraj Singh</a> and <a href="https://github.com/mislav">Mislav Marohnić</a> for helping get these changes pulled into Rails jQuery UJS.
</p>
<p>
In other news, I&#8217;m now on <a href="https://github.com/rails">the Rails jQuery UJS core team</a>. So, stay tuned for more on the latest developments in jquery-ujs. <img src='http://cdn1.alfajango.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />
</p>
<p class="note">
If you liked this, check out our <a href="/blog/rails-3-remote-links-and-forms/">Definitive Guide to Rails 3 Remote Links and Forms Part 1</a> and <a href="/blog/rails-3-remote-links-and-forms-data-type-with-jquery/">Part 2</a>.</p>
<img src="http://feeds.feedburner.com/~r/alfajango/~4/Luq4l8wz1NU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.alfajango.com/blog/new-ajax-aborted-rails-jquery-ujs-callbacks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.alfajango.com/blog/new-ajax-aborted-rails-jquery-ujs-callbacks/</feedburner:origLink></item>
		<item>
		<title>Rails jQuery UJS: Now Interactive</title>
		<link>http://feedproxy.google.com/~r/alfajango/~3/nnlEtlTy_cE/</link>
		<comments>http://www.alfajango.com/blog/rails-jquery-ujs-now-interactive/#comments</comments>
		<pubDate>Fri, 22 Apr 2011 15:49:14 +0000</pubDate>
		<dc:creator>Steve Schwartz</dc:creator>
				<category><![CDATA[HTML5]]></category>
		<category><![CDATA[JQuery]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[jquery-ujs]]></category>
		<category><![CDATA[link_to_remote]]></category>
		<category><![CDATA[Rails 3]]></category>
		<category><![CDATA[remote_form_for]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://www.alfajango.com/blog/?p=1723</guid>
		<description><![CDATA[Rails jQuery UJS has undergone some major renovations over the past few weeks. This particular change is one I'm very excited about. I've been wanting to do this for a while, and finally knocked it out. Without further ado, Rails jQuery UJS adapter is now Interactive.]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.alfajango.com/blog/wp-content/uploads/2011/04/rails-remote.jpg" alt="" title="rails-remote" width="200" height="300" class="alignleft size-full wp-image-1732" /></p>
<p>
The <a href="https://github.com/rails/jquery-ujs">Rails jQuery UJS adapter</a> (aka jquery-ujs) has undergone some major renovations over the past few weeks. This particular change is one I&#8217;m very excited about, as I&#8217;ve been wanting to do this for a while. Without further ado, jquery-ujs is now <strong>Interactive</strong><sup>TM</sup>.
</p>
<p>
What do I mean by &#8220;interactive&#8221;? Well, we can now plug into every facet of jquery-ujs, binding to custom events, and even customizing internal functions, without hacking or monkey-patching the rails.js file itself.
</p>
<p>
We&#8217;ll start with a brief explanation of the change and then dive into a few examples.
</p>
<p class='note'>
Feel free to bypass my blabbering and <a href="https://github.com/rails/jquery-ujs/commit/d59144177d86790891fdb99b0e3437312e04fda2">check out the the commit</a>.
</p>
<h2>Closure style</h2>
<p>
Previously, rails.js was one big closure.
</p>
<h3>Before:</h3>
<div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>$<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; ...<br />
&nbsp; <span style="color: #003366; font-weight: bold;">function</span> fire<span style="color: #009900;">&#40;</span>obj<span style="color: #339933;">,</span> <span style="color: #000066;">name</span><span style="color: #339933;">,</span> data<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> event <span style="color: #339933;">=</span> $.<span style="color: #660066;">Event</span><span style="color: #009900;">&#40;</span><span style="color: #000066;">name</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; obj.<span style="color: #660066;">trigger</span><span style="color: #009900;">&#40;</span>event<span style="color: #339933;">,</span> data<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">return</span> event.<span style="color: #660066;">result</span> <span style="color: #339933;">!==</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; ...<br />
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#40;</span> jQuery <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #006600; font-style: italic;">// cannot access fire() function here</span></div></div>
<p>
This <a href="http://mark-story.com/posts/view/picking-up-javascript-closures-and-lexical-scoping">closure design had many advantages</a>. However, the biggest advantage, in this case, happened to be the biggest disadvantage as well: <em>everything inside was self-contained and inaccessible by the outside world</em>.
</p>
<p>
So, what if we like most of what jquery-ujs does for us, but just want to modify one little function? Before, we&#8217;d have to open rails.js in our editor and start hacking away. But no more!
</p>
<h2>Object literal style</h2>
<p><span id="more-1723"></span></p>
<p>
A relatively simple refactor using the <a href="http://blog.rebeccamurphey.com/2009/10/15/using-objects-to-organize-your-code">object literal design pattern</a> now allows us total control, by placing all internal functions into the externally-accessible <code class="codecolorer javascript dawn"><span class="javascript">$.<span style="color: #660066;">rails</span></span></code> object.
</p>
<h3>After:</h3>
<div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>$<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #003366; font-weight: bold;">var</span> rails<span style="color: #339933;">;</span><br />
&nbsp; $.<span style="color: #660066;">rails</span> <span style="color: #339933;">=</span> rails <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; ...<br />
&nbsp; &nbsp; <span style="color: #660066;">fire</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>obj<span style="color: #339933;">,</span> <span style="color: #000066;">name</span><span style="color: #339933;">,</span> data<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> event <span style="color: #339933;">=</span> $.<span style="color: #660066;">Event</span><span style="color: #009900;">&#40;</span><span style="color: #000066;">name</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; obj.<span style="color: #660066;">trigger</span><span style="color: #009900;">&#40;</span>event<span style="color: #339933;">,</span> data<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">return</span> event.<span style="color: #660066;">result</span> <span style="color: #339933;">!==</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; ...<br />
&nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br />
&nbsp; ...<br />
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#40;</span> jQuery <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #006600; font-style: italic;">// Can now access $.rails.fire() here</span></div></div>
<p>
Now, inside rails.js, we simply change any <code class="codecolorer javascript dawn"><span class="javascript">fire<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span></span></code> function calls to <code class="codecolorer javascript dawn"><span class="javascript">rails.<span style="color: #660066;">fire</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span></span></code>. And outside of rails.js, we can similarly call <code class="codecolorer javascript dawn"><span class="javascript">$.<span style="color: #660066;">rails</span>.<span style="color: #660066;">fire</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span></span></code>.
</p>
<p>
Furthermore, we could even redefine the <code class="codecolorer javascript dawn"><span class="javascript">fire<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span></span></code> function with our own: <code class="codecolorer javascript dawn"><span class="javascript">$.<span style="color: #660066;">rails</span>.<span style="color: #660066;">fire</span> <span style="color: #339933;">=</span> someNewFunction<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></span></code>.
</p>
<p class="note">
In the excerpted code from rails.js above, the &#8220;before&#8221; looks simpler, but the &#8220;after&#8221; actually does a nice job of keeping things clearer and better organized when there are more functions.
</p>
<h2>Some examples</h2>
<p>
So, how might we actually use this now in a production app? Let&#8217;s look at a couple examples.
</p>
<h3>Direct access</h3>
<p>
For starters, let&#8217;s say that we want for a particular form to be submitted the same as <code class="codecolorer rails dawn"><span class="rails"><span style="color:#ff3333; font-weight:bold;">:remote</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span></span></code> forms, but for whatever reason, this form does not have the remote attribute. We can now take advantage of the functionality provided by rails.js directly. In our application.js, we might have:
</p>
<div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#my-form'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">live</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'submit'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; $.<span style="color: #660066;">rails</span>.<span style="color: #660066;">handleRemote</span><span style="color: #009900;">&#40;</span> $<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; e.<span style="color: #660066;">preventDefault</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>
And now, rails.js will set up our AJAX request, serialize our form, etc., just as if it were a remote form. Of course, this example is a bit contrived, but hopefully it illustrates the potential for being able to access rails.js functions directly.
</p>
<h3>Redefining jquery-ujs functions</h3>
<p>
And of course, as mentioned before, there&#8217;s also the ability to redefine functions. For example, in our application.js, we could add:
</p>
<div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$.<span style="color: #660066;">rails</span>.<span style="color: #660066;">fire</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>obj<span style="color: #339933;">,</span> <span style="color: #000066;">name</span><span style="color: #339933;">,</span> data<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #003366; font-weight: bold;">var</span> event <span style="color: #339933;">=</span> $.<span style="color: #660066;">Event</span><span style="color: #009900;">&#40;</span><span style="color: #000066;">name</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #006600; font-style: italic;">// Custom code:</span><br />
&nbsp; <span style="color: #006600; font-style: italic;">// e.g. &quot;Fire ajax:before for my-form!&quot;</span><br />
&nbsp; console.<span style="color: #660066;">log</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;Fire &quot;</span> <span style="color: #339933;">+</span> <span style="color: #000066;">name</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot; for &quot;</span> <span style="color: #339933;">+</span> obj.<span style="color: #660066;">attr</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'id'</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot;!&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; obj.<span style="color: #660066;">trigger</span><span style="color: #009900;">&#40;</span>event<span style="color: #339933;">,</span> data<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">return</span> event.<span style="color: #660066;">result</span> <span style="color: #339933;">!==</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span></div></div>
<p>
And now we have our own custom <code class="codecolorer javascript dawn"><span class="javascript">fire<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span></span></code> function which will now be used internally by jquery-ujs without having to open up and modify rails.js.
</p>
<p class="in-depth">
On a side-note, the <code class="codecolorer javascript dawn"><span class="javascript">fire<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span></span></code> function in rails.js is probably one of my favorite little functions that I&#8217;ve actually used in several other projects, including the jQuery EasyTabs plugin. But we&#8217;ll take a closer look at this function another time.
</p>
<h3>Redefining selectors</h3>
<p>
And as an added bonus, we also moved the CSS selectors, to which jquery-ujs binds all its functionality, into the <code class="codecolorer javascript dawn"><span class="javascript">$.<span style="color: #660066;">rails</span></span></code> object. How could this be useful?
</p>
<p>
Let&#8217;s say we want the ability to kill all jquery-ujs form bindings for a particular form (maybe after it&#8217;s been submitted once already). In rails.js we have:
</p>
<div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$.<span style="color: #660066;">rails</span> <span style="color: #339933;">=</span> rails <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; ...<br />
&nbsp; <span style="color: #006600; font-style: italic;">// Form elements bound by jquery-ujs</span><br />
&nbsp; formSubmitSelector<span style="color: #339933;">:</span> <span style="color: #3366CC;">'form'</span><span style="color: #339933;">,</span><br />
&nbsp; ...<br />
<span style="color: #009900;">&#125;</span></div></div>
<p>
Now in our application.js, we could do something similar to the following:
</p>
<div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$.<span style="color: #660066;">rails</span>.<span style="color: #660066;">formSubmitSelector</span> <span style="color: #339933;">=</span> <span style="color: #3366CC;">'form:not([data-skip-remote])'</span><span style="color: #339933;">;</span><br />
<br />
$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#my-form'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">live</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'ajax:success'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; $<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">attr</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'data-skip-remote'</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">'true'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<h2>W00t</h2>
<p>
Well I hope this was helpful. One of my goals with these changes was to spur the development of additional plugins and gems that build off of and extend the great out-of-the-box functionality that rails.js provides.
</p>
<p>
As another way to help maintain third-party plugins that extend jquery-ujs, I also added a <a href="https://github.com/rails/jquery-ujs/blob/master/CHANGELOG.md">new Changelog</a>. This will hopefully make it easier to keep track of notable changes to the &#8220;api&#8221;.
</p>
<p>
I&#8217;d also like to send a big thank-you to <a href="https://github.com/neerajdotname">Neeraj Singh</a>, who has been very helpful keeping me sane and in getting changes pulled into jquery-ujs.
</p>
<p>
Stay tuned for more on recent developments in Rails jQuery UJS. In the meantime, I encourage you to <a href="https://github.com/rails/jquery-ujs">check out the source</a>.
</p>
<p class="note">
If you liked this, check out our <a href="/blog/rails-3-remote-links-and-forms/">Definitive Guide to Rails 3 Remote Links and Forms Part 1</a> and <a href="/blog/rails-3-remote-links-and-forms-data-type-with-jquery/">Part 2</a>.</p>
<img src="http://feeds.feedburner.com/~r/alfajango/~4/nnlEtlTy_cE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.alfajango.com/blog/rails-jquery-ujs-now-interactive/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		<feedburner:origLink>http://www.alfajango.com/blog/rails-jquery-ujs-now-interactive/</feedburner:origLink></item>
		<item>
		<title>jQuery EasyTabs Plugin v2.2</title>
		<link>http://feedproxy.google.com/~r/alfajango/~3/0g3jdmr9V6U/</link>
		<comments>http://www.alfajango.com/blog/jquery-easytabs-plugin-v2-2/#comments</comments>
		<pubDate>Wed, 30 Mar 2011 21:52:18 +0000</pubDate>
		<dc:creator>Steve Schwartz</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[JQuery]]></category>
		<category><![CDATA[easytabs]]></category>
		<category><![CDATA[plugins]]></category>

		<guid isPermaLink="false">http://www.alfajango.com/blog/?p=1701</guid>
		<description><![CDATA[It's only been a week since the last release, but I'm excited to present jQuery EasyTabsv2.2. New with this release: panel height animated transitions and animation transition options.]]></description>
			<content:encoded><![CDATA[<p>
It&#8217;s only been a week since the last release, but I&#8217;m excited to present <a href="http://www.alfajango.com/blog/jquery-easytabs-plugin/">jQuery EasyTabs</a> v2.2. New with this release:</p>
<ul>
<li><a href="/blog/jquery-easytabs-plugin-v2-2/#height-transition">Panel height animated transitions</a></li>
<li><a href="/blog/jquery-easytabs-plugin-v2-2/#transition-options">Animation transition options</a></li>
</ul>
<ul class="group-buttons">
<li class="group-button first-child">
                <a href="/blog/jquery-easytabs-plugin/jquery-easytabs-demo-height-and-transition-options/"><strong><br />
                        <img src="/blog/wp-content/themes/aj/images/rocket-fly.png" /> View demo with new features</strong></a></li>
<li class="group-button">
                <a href="/blog/jquery-easytabs-plugin/"><strong><br />
                        <img src="/blog/wp-content/themes/aj/images/document-globe.png" /> View plugin homepage</strong></a></li>
<li class="group-button last-child">
                <a href="https://github.com/JangoSteve/jQuery-EasyTabs/wiki/CHANGELOG"><strong><br />
                        <img src="/blog/wp-content/themes/aj/images/edit-list.png" /> View changelog</strong></a></li>
</ul>
<p><a name="height-transition"></a></p>
<h2>Animated height transitions</h2>
<p>
In many cases, the tab panels (where the tabbed content lives) are not the same height. Now, EasyTabs automatically animates the height transition between panels of differing heights. The speed for the animation to scale panel heights depends on the <code class="codecolorer javascript dawn"><span class="javascript">animationSpeed</span></code> option.
</p>
<p>
<a href="/blog/jquery-easytabs-plugin/jquery-easytabs-demo-height-and-transition-options/">View the demo</a> to see this new effect in action.
</p>
<p><a name="transition-options"></a></p>
<h2>Animated transition options</h2>
<p>
As requested, EasyTabs now gives more control over the effects used to transition between panels. The default transitions are still <code class="codecolorer javascript dawn"><span class="javascript">fadeIn</span></code> and <code class="codecolorer javascript dawn"><span class="javascript">fadeOut</span></code>, respectively. But now, you can specify any other jQuery effect to use as well. The new options are:
</p>
<p><div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">transitionIn <span style="color: #006600; font-style: italic;">// effect for appearing target panel</span><br />
transitionOut <span style="color: #006600; font-style: italic;">// effect for disappearing visible panel</span><br />
transitionCollapse <span style="color: #006600; font-style: italic;">// effect for collapsing panel</span><br />
transitionUncollapse <span style="color: #006600; font-style: italic;">// effect for uncollapsing panel</span></div></div>
</p>
<p>
For example:
</p>
<p><div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#tab-container'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">easytabs</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; transitionIn<span style="color: #339933;">:</span> <span style="color: #3366CC;">'slideDown'</span><span style="color: #339933;">,</span><br />
&nbsp; transitionOut<span style="color: #339933;">:</span> <span style="color: #3366CC;">'slideUp'</span><br />
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
</p>
<p>
To see this in action,  <a href="/blog/jquery-easytabs-plugin/jquery-easytabs-demo-height-and-transition-options/">check out the demo</a>.</p>
<img src="http://feeds.feedburner.com/~r/alfajango/~4/0g3jdmr9V6U" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.alfajango.com/blog/jquery-easytabs-plugin-v2-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.alfajango.com/blog/jquery-easytabs-plugin-v2-2/</feedburner:origLink></item>
		<item>
		<title>jQuery EasyTabs Plugin v2.1.2</title>
		<link>http://feedproxy.google.com/~r/alfajango/~3/0-Y_wC1V25E/</link>
		<comments>http://www.alfajango.com/blog/jquery-easytabs-plugin-v2-1-2/#comments</comments>
		<pubDate>Mon, 21 Mar 2011 07:30:05 +0000</pubDate>
		<dc:creator>Steve Schwartz</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[JQuery]]></category>
		<category><![CDATA[Open-source]]></category>
		<category><![CDATA[easytabs]]></category>
		<category><![CDATA[plugins]]></category>

		<guid isPermaLink="false">http://www.alfajango.com/blog/?p=1643</guid>
		<description><![CDATA[The jQuery EasyTabs plugin is now at version 2.1.2. This release adds four new features: uiTabs option, collapsible option, cancel tab-change in 'easytabs:before' hook, and useful parameters in callback hooks.]]></description>
			<content:encoded><![CDATA[<p>
The <a href="http://www.alfajango.com/blog/jquery-easytabs-plugin/">jQuery EasyTabs plugin</a> is now at version <del datetime="2011-03-21T06:46:35+00:00">2.1.0</del> 2.1.2 (I managed to bump the version number twice before publishing this post). This release adds <del datetime="2011-03-21T05:03:40+00:00">three</del> four new features:</p>
<ul>
<li><a href="/blog/jquery-easytabs-plugin-v2-1-2/#uiTabs">uiTabs option</a></li>
<li><a href="/blog/jquery-easytabs-plugin-v2-1-2/#collapsible">collapsible option</a></li>
<li><a href="/blog/jquery-easytabs-plugin-v2-1-2/#cancel-before-hook">Cancel tab-change in &#8216;easytabs:before&#8217; hook</a></li>
<li><a href="/blog/jquery-easytabs-plugin-v2-1-2/#parameters-in-hooks">Useful parameters in callback hooks</a></li>
</ul>
<ul class="group-buttons">
<li class="group-button first-child">
                <a href="/blog/jquery-easytabs-plugin/jquery-easytabs-demo-collapsible-and-cancel-change/"><strong><br />
                        <img src="/blog/wp-content/themes/aj/images/rocket-fly.png" /> View demo with new features</strong></a></li>
<li class="group-button">
                <a href="/blog/jquery-easytabs-plugin/"><strong><br />
                        <img src="/blog/wp-content/themes/aj/images/document-globe.png" /> View plugin homepage</strong></a></li>
<li class="group-button last-child">
                <a href="https://github.com/JangoSteve/jQuery-EasyTabs/wiki/CHANGELOG"><strong><br />
                        <img src="/blog/wp-content/themes/aj/images/edit-list.png" /> View changelog</strong></a></li>
</ul>
<p><a name="uiTabs"></a></p>
<h2>uiTabs option</h2>
<p>
Perhaps my favorite addition to the EasyTabs options, when <code class="codecolorer javascript dawn"><span class="javascript">uiTabs<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span></span></code>, EasyTabs will automatically add and use the same class names used by the jQuery UI tabs. This feature opens the doorway to making EasyTabs a drop-in replacement for jQuery UI tabs once you&#8217;ve outgrown UI&#8217;s out-of-the-box theming and structure.
</p>
<p>
If you are currently using UI tabs with this:
</p>
<p><div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#tab-container'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">tabs</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
</p>
<p>
Simply replace the above line with this:
</p>
<p><div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#tab-container'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">easytabs</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span> uiTabs<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
</p>
<p>
And your tabs will still look and function the same as before. Now you can start customizing the CSS and HTML markup with the flexibility of EasyTabs.
</p>
<p><span id="more-1643"></span></p>
<p class="note">
Note that EasyTabs currently only supports the <code class="codecolorer javascript dawn"><span class="javascript">collapsible</span></code> option of UI tabs (for now). So if you&#8217;re using any of UI tabs other options, these will need to be removed. If you would like support added for a specific option, request it in the <a href="https://github.com/JangoSteve/jQuery-EasyTabs/issues">GitHub issue tracker</a>, or even fork the project and submit a pull request.
</p>
<p><a name="collapsible"></a></p>
<h2>collapsible option</h2>
<p>
<a href="https://github.com/JangoSteve/jQuery-EasyTabs/issues/closed#issue/1">By request</a>, the <code class="codecolorer javascript dawn"><span class="javascript">collapsible</span></code> option has been added to EasyTabs. This allows an active tab to be &#8220;de-selected&#8221;, or collapsed, when clicked again.
</p>
<p><div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#tab-container'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">easytabs</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span> collapsible<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
</p>
<p>
This will also cause all tabs to be collapsed initially. However, this behavior may be overridden (such that the default tab will be expanded by default) with the <code class="codecolorer javascript dawn"><span class="javascript">collapsedByDefault</span></code> option:
</p>
<p><div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#tab-container'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">easytabs</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; collapsible<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">,</span><br />
&nbsp; collapsedByDefault<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">false</span> <br />
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
</p>
<p>
Alternatively, if a <code class="codecolorer javascript dawn"><span class="javascript">defaultTab</span></code> is specified, then the default tab will be expanded by default as well (as if <code class="codecolorer javascript dawn"><span class="javascript">collapsedByDefault</span></code> were true).
</p>
<p>
Also, when a panel is collapsed, EasyTabs adds the <code class="codecolorer css dawn"><span class="css">collapsed</span></code> class name to the tab, so that it may be styled uniquely (perhaps grayed out) in your CSS. You can override the collapsed CSS class name with the <code class="codecolorer javascript dawn"><span class="javascript">collapsedClass</span></code> option:
</p>
<p><div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#tab-container'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">easytabs</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; collapsible<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">,</span><br />
&nbsp; collapsedClass<span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;my-collapsed-tab&quot;</span><br />
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
</p>
<p><a name="cancel-before-hook"></a></p>
<h2>Cancel tab-change in before-hook</h2>
<p>
And finally, also <a href="https://github.com/JangoSteve/jQuery-EasyTabs/issues/closed#issue/2">by request</a>, you can now cancel the tab change event in the <code class="codecolorer javascript dawn"><span class="javascript">easytabs<span style="color: #339933;">:</span>before</span></code> event hook. If a function bound to the <code class="codecolorer javascript dawn"><span class="javascript">easytabs<span style="color: #339933;">:</span>before</span></code> hook returns false, then the tab-change event will be aborted. A simple use-case for this might be:
</p>
<p><div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#tab-container'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">bind</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'easytabs:before'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #000066;">confirm</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;Are you sure you want to switch tabs?&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
</p>
<p><a name="parameters-in-hooks"></a></p>
<h2>Useful parameters in callback hooks</h2>
<p>
In the callback hooks, it&#8217;s useful to know what tab was clicked, what the target panel is, etc. Now it&#8217;s possible. All three callback hooks (<code class="codecolorer javascript dawn"><span class="javascript">easytabs<span style="color: #339933;">:</span>before</span></code>, <code class="codecolorer javascript dawn"><span class="javascript">easytabs<span style="color: #339933;">:</span>midTransition</span></code>, and <code class="codecolorer javascript dawn"><span class="javascript">easytabs<span style="color: #339933;">:</span>after</span></code>), pass the following parameters to the handler functions:</p>
<table>
<tr>
<th>Parameter</th>
<th>Value</th>
</tr>
<tr>
<td><code class="codecolorer javascript dawn"><span class="javascript">tab</span></code></td>
<td>The tab that was clicked</td>
</tr>
<tr>
<td><code class="codecolorer javascript dawn"><span class="javascript">panel</span></code></td>
<td>the target panel for the tab that was clicked</td>
</tr>
<tr>
<td><code class="codecolorer javascript dawn"><span class="javascript">data</span></code></td>
<td>the EasyTab data for that container, include <code class="codecolorer javascript dawn"><span class="javascript">tabs</span></code>, <code class="codecolorer javascript dawn"><span class="javascript">panels</span></code>, and <code class="codecolorer javascript dawn"><span class="javascript">opts</span></code> (the options set for EasyTabs)</td>
</tr>
</table>
<p>
So, for example, we can do this:
</p>
<p><div class="codecolorer-container javascript twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#tab-container'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">bind</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'easytabs:before'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>evt<span style="color: #339933;">,</span> tab<span style="color: #339933;">,</span> panel<span style="color: #339933;">,</span> data<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span> tab.<span style="color: #660066;">hasClass</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'special-alert'</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000066;">alert</span><span style="color: #009900;">&#40;</span> <span style="color: #3366CC;">'Hi there, you are special!'</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
</p>
<ul class="group-buttons">
<li class="group-button first-child last-child">
                <a href="/blog/jquery-easytabs-plugin/jquery-easytabs-demo-collapsible-and-cancel-change/"><strong><br />
                        <img src="/blog/wp-content/themes/aj/images/rocket-fly.png" />View demo with new features</strong></a></li>
</ul>
<img src="http://feeds.feedburner.com/~r/alfajango/~4/0-Y_wC1V25E" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.alfajango.com/blog/jquery-easytabs-plugin-v2-1-2/feed/</wfw:commentRss>
		<slash:comments>21</slash:comments>
		<feedburner:origLink>http://www.alfajango.com/blog/jquery-easytabs-plugin-v2-1-2/</feedburner:origLink></item>
		<item>
		<title>Rails js.erb Remote Response not Executing</title>
		<link>http://feedproxy.google.com/~r/alfajango/~3/KEukHpIA5ZI/</link>
		<comments>http://www.alfajango.com/blog/rails-js-erb-remote-response-not-executing/#comments</comments>
		<pubDate>Tue, 15 Mar 2011 19:06:52 +0000</pubDate>
		<dc:creator>Steve Schwartz</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[JQuery]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[debugging]]></category>
		<category><![CDATA[jquery-ujs]]></category>
		<category><![CDATA[link_to_remote]]></category>
		<category><![CDATA[remote_form_for]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://www.alfajango.com/blog/?p=1542</guid>
		<description><![CDATA[A common issue that comes up in the GitHub Issues for the Rails jQuery UJS and the Remotipart gem / jQuery plugin goes like this:
The JavaScript response from my [cci]js.erb[/cci] is being interpreted as text and <em>not</em> being executed.]]></description>
			<content:encoded><![CDATA[<p>
A common issue that comes up in the GitHub Issues for the <a href="https://github.com/rails/jquery-ujs/issues/">Rails jQuery UJS</a> and the <a href="https://github.com/formasfunction/remotipart/issues/">Remotipart gem / jQuery plugin</a> goes like this:
</p>
<blockquote><p>The JavaScript response from my <code class="codecolorer text dawn"><span class="text">js.erb</span></code> is being interpreted as text and <em>not</em> being executed.</p></blockquote>
<p>
I usually point to <a href="https://github.com/rails/jquery-ujs/issues/closed#issue/91">this comment</a> in GitHub Issues, which I posted the first time I came across this problem. But GitHub Issue comments are difficult to link to, and almost useless in search results due to all their ajaxy-ness. So, I&#8217;ll repost and explain here for future reference.
</p>
<p><span id="more-1542"></span></p>
<h2>The problem</h2>
<p>
The problem usually isn&#8217;t that the JavaScript in the js.erb isn&#8217;t being executed, it&#8217;s that it&#8217;s being executed and incurring an error. By default, when jQuery processes a JavaScript response, it does two things. It executes (or evaluates) the response, and <em>also</em> returns it as a text.
</p>
<p>
Except, if there is in error in the JS evaluation, we will not see that error in our favorite JavaScript console; the automatic JS evaluation fails silently, so it appears that jQuery is only interpreting the response as text and nothing else.
</p>
<p>
Great, so now what?
</p>
<h2>The diagnosis</h2>
<p>
First, let&#8217;s make sure that this is indeed what&#8217;s happening. To verify that the response is getting interpreted as JS and not plain text, go to the Rails log and make sure the remote request looks like this:
</p>
<p>
<a href="http://www.alfajango.com/blog/wp-content/uploads/2011/02/Picture-24.png"><img src="http://www.alfajango.com/blog/wp-content/uploads/2011/02/Picture-24-550x27.png" alt="JS Request in Rails Console" title="JS Request in Rails Console" width="550" height="27" class="alignnone size-large wp-image-1596" /></a>
</p>
<p>
If the &#8220;as JS&#8221; bit is in there, then what we have is a JavaScript problem (which is addressed below). If not, then see <a href="alfajango.com/blog/rails-3-remote-links-and-forms-data-type-with-jquery/">my post on remote link and form data-type</a>.
</p>
<h2>The solution</h2>
<p>
Here is my process for debugging this type of solution. Firebug works best, because it contains all the tools needed in one place.
</p>
<ol>
<li>In Firebug, in the &#8220;Console&#8221; tab, turn on &#8220;Show XMLHttpRequests&#8221;, so that we can see AJAX requests and responses in our console. Also make sure that &#8220;Larger Command Line&#8221; is enabled.</li>
<p><a href="http://www.alfajango.com/blog/wp-content/uploads/2011/02/Picture-233.jpg"><img src="http://www.alfajango.com/blog/wp-content/uploads/2011/02/Picture-233-550x354.jpg" alt="Enable AJAX Requests in Console" title="Enable AJAX Requests in Console" width="550" height="354" class="alignnone size-large wp-image-1592" /></a></p>
<li>Reload the page and click the remote link or form in question.</li>
<li>Click the AJAX request, which should have shown up in the Console, then click the &#8220;Response&#8221; tab.</li>
<p><a href="http://www.alfajango.com/blog/wp-content/uploads/2011/02/Picture-27.png"><img src="http://www.alfajango.com/blog/wp-content/uploads/2011/02/Picture-27-550x121.png" alt="AJAX Request in Firebug Console" title="AJAX Request in Firebug Console" width="550" height="121" class="alignnone size-large wp-image-1602" /></a></p>
<li>Copy and paste the rendered JavaScript response into the command-line pane, and click &#8220;Run&#8221;.</li>
<p><a href="http://www.alfajango.com/blog/wp-content/uploads/2011/02/Picture-29.png"><img src="http://www.alfajango.com/blog/wp-content/uploads/2011/02/Picture-29-550x121.png" alt="Run rendered JS from command line" title="Run rendered JS from command line" width="550" height="121" class="alignnone size-large wp-image-1603" /></a></p>
<li>Now, any JavaScript errors will show in the console. Fix the errors in the js.erb file and repeat until it works.</li>
<p><a href="http://www.alfajango.com/blog/wp-content/uploads/2011/02/Picture-30.png"><img src="http://www.alfajango.com/blog/wp-content/uploads/2011/02/Picture-30-550x121.png" alt="JS error" title="JS error" width="550" height="121" class="alignnone size-large wp-image-1604" /></a>
</ol></p>
<img src="http://feeds.feedburner.com/~r/alfajango/~4/KEukHpIA5ZI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.alfajango.com/blog/rails-js-erb-remote-response-not-executing/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		<feedburner:origLink>http://www.alfajango.com/blog/rails-js-erb-remote-response-not-executing/</feedburner:origLink></item>
	</channel>
</rss><!-- Dynamic page generated in 0.812 seconds. --><!-- Cached page generated by WP-Super-Cache on 2012-05-16 13:04:15 -->

