<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Wolfmans Howlings: How to protect a form from accidentally losing data</title>
    <link>http://blog.wolfman.com/articles/2006/11/14/how-to-protect-a-form-from-accidentally-losing-data</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>A programmers Blog about Ruby, Rails and a few other issues</description>
    <item>
      <title>How to protect a form from accidentally losing data</title>
      <description>&lt;p&gt;Here is a good one, your users are complaining that they have spent 5
minutes filling in a web form, then lose it all by clicking on a link
away from the form, and back arrow doesn't restore the fields that
were entered. (At least on IE).&lt;/p&gt;

&lt;p&gt;I saw an interesting design in the Rails Recipes book for saving form
data at regular intervals, but I didn't like the overhead of that one.&lt;/p&gt;

&lt;p&gt;So I found a snippet of javascript that detects when you are about to
switch away from a page, I coupled that with a simple observer that
sets a dirty flag when any field is modified in anyway, and you get
something that pops up a dialog asking if they really want to leave
this page and lose their input data, they get the option to not go to
the new page and submit the form instead.&lt;/p&gt;

&lt;p&gt;This is not as clean as I'd like, so anyone with ideas of making it
cleaner please let me know.&lt;/p&gt;

&lt;p&gt;This would go in app/helpers/application.rb...&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;  &lt;span class="comment"&gt;# if the given form has changed at all then pop-up a dialog if they&lt;/span&gt;
  &lt;span class="comment"&gt;# try to move away from the form before saving&lt;/span&gt;
  &lt;span class="comment"&gt;# You have to add :html =&amp;gt; {:id =&amp;gt; 'new_mission_form'} to the form&lt;/span&gt;
  &lt;span class="comment"&gt;# and  :onclick =&amp;gt; &amp;quot;dirty_page= false;&amp;quot; to the submit button&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;catch_page_change_if_changed&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;form&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;obj&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;nil&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="punct"&gt;&amp;lt;&amp;lt;-&lt;/span&gt;&lt;span class="constant"&gt;END&lt;/span&gt;&lt;span class="string"&gt;
      &amp;lt;script language=&amp;quot;javascript&amp;quot;&amp;gt;
          &amp;lt;!--
            dirty_page = &lt;span class="expr"&gt;#{obj.nil? || obj.errors.empty? ? &amp;quot;false&amp;quot; : &amp;quot;true&amp;quot;}&lt;/span&gt;;
            new Form.EventObserver(&lt;span class="expr"&gt;#{form}&lt;/span&gt;, function(element, value) {dirty_page= true; });
            window.onbeforeunload = function (evt) {
              if (dirty_page) {
                var message = 'Leaving this page will lose all entered values';
                if (typeof evt == 'undefined') {
                  evt = window.event;
                }
                if (evt) {
                  evt.returnValue = message;
                }
                return message;
              }
            }
         //--&amp;gt;
      &amp;lt;/script&amp;gt;
&lt;/span&gt;&lt;span class="constant"&gt;    END&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the view you give the form an id, and you also need to add an
:onclick to the submit button so it allows you to submit the form
without popping up the dialog... &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;% form_for :obj, @obj,  :html =&amp;gt; {:id =&amp;gt; 'new_form'}, :url =&amp;gt; { :action =&amp;gt; 'create' } do |f| %&amp;gt;
...
&amp;lt;%= submit_tag "Submit", :onclick =&amp;gt; "dirty_page= false;" %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;then call this somewhere in that view...&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;catch_page_change_if_changed('new_form', @obj)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Basically I just set a javascript variable called dirty_page to false,
and have the observer set it to true if anything changes. The optional
object being passed in to the helper is used to detect if we are back
on the form due to input errors, in which case we set the dirty_flag
to true, so we don't lose the fields that were not in error.&lt;/p&gt;

&lt;p&gt;Oh this only works if javascript is enabled (of course!)&lt;/p&gt;

&lt;p&gt;&lt;a href="http://technorati.com/tag/rails+form" rel="tag"&gt;&lt;/a&gt;
&lt;a href="http://technorati.com/tag/rails+save+form" rel="tag"&gt;&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Tue, 14 Nov 2006 22:47:44 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:f5917acc-0fbe-4e30-904c-e57c396c155b</guid>
      <author>Jim Morris</author>
      <link>http://blog.wolfman.com/articles/2006/11/14/how-to-protect-a-form-from-accidentally-losing-data</link>
      <category>Rails</category>
      <category>rails</category>
      <category>forms</category>
      <trackback:ping>http://blog.wolfman.com/articles/trackback/72</trackback:ping>
    </item>
    <item>
      <title>"How to protect a form from accidentally losing data" by Jason</title>
      <description>&lt;p&gt;its scrubbing my inputs, it needs  this change in the application helper:&lt;br&gt;&lt;br&gt;&lt;/p&gt;

&lt;p&gt;new Event.observe(window, 'load', function() {&lt;br&gt;
 &amp;nbsp;&amp;nbsp;  new Form.EventObserver($("#{form}"), function(element, value) {dirty_page= true; });&lt;br&gt;
});  &lt;/p&gt;</description>
      <pubDate>Mon, 10 Dec 2007 17:17:07 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:0abee444-5f4d-4b7b-b83d-cf9d5d40e277</guid>
      <link>http://blog.wolfman.com/articles/2006/11/14/how-to-protect-a-form-from-accidentally-losing-data#comment-182</link>
    </item>
    <item>
      <title>"How to protect a form from accidentally losing data" by Jason</title>
      <description>&lt;p&gt;This is great, but it DOES NOT WORK AS POSTED!!!&lt;/p&gt;

&lt;p&gt;You need to encapsulate new Form.EventObserver within an onload observer, AND they way you are refering to the form #{form} needs to be in quotes or the form is never found.&lt;/p&gt;

&lt;p&gt;Like this&lt;/p&gt;

&lt;p&gt;def catch&lt;em&gt;page&lt;/em&gt;change_if_changed(form, obj= nil)
    &amp;lt;&amp;lt;-END
      
          
            window.onbeforeunload = function (evt) {
              if (dirty_page) {
                var message = 'Form values have not been submitted, leaving without submitting will loose all inputs.';
                if (typeof evt == 'undefined') {
                  evt = window.event;
                }
                if (evt) {
                  evt.returnValue = message;
                }
                return message;
              }
            }
         //--&gt;
      
    END
  end&lt;/p&gt;</description>
      <pubDate>Mon, 10 Dec 2007 17:10:37 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:ac9e1263-6656-4cb9-9d54-15662835cfd7</guid>
      <link>http://blog.wolfman.com/articles/2006/11/14/how-to-protect-a-form-from-accidentally-losing-data#comment-181</link>
    </item>
  </channel>
</rss>
