2

I am currently creating a step by step registration process on my website.

The whole process has been successfully created with the exact same setup as seen on the rails cast here: http://railscasts.com/episodes/217-multistep-forms

After I got all that working, I converted the whole thing to Ajax! With either the submit buttons or forms on each step, I simply added:

remote:true

Then, after adding the proper response handling:

respond_to do|format|
  format.js { render 'new' }
  format.html { render 'new' }
end

In new.js.erb I have this:

$('#steps_content').fadeOut('fast', function(){
  $('#steps_content').html("<%= j render "#{@subscription.current_step}_step" %>", 
     $('#steps_content').fadeIn('fast', function(){})
  )
});

Here's new.html.erb:

<div id='steps_content' >
   <%= render "#{@subscription.current_step}_step" %>
</div>

Step by Step Ajaxified!

Anyways, since the whole thing has been Ajaxified, I have been trying to get the Browser Back Button to go to my previous step as well as having an on page back button.

I kind of get there by adding this to the beginning of my new.js.erb:

history.pushState(
   null, 
   '', 
   '#step=<%= j "#{@subscription.current_step}" %>'
);

And this to the end of it:

if (!$(window) || !$(window).data('events') || 
    !$(window).data('events')['popstate']) {

      $(window).bind('popstate', function() {
        $.getScript(location.href);
      });

}

This has been causing me a fair amount of trouble!

With the current setup: The JQuery Animation fires. Thought, it just fadeIn, fadeOut to the same step. I discovered the reason that happens was because all the step code is in the create action (post), not the new action (get) which is what the back button fires. Though even if I put the code in there, the back button in the browser doesn't throw in the :back_button parameter.

I have been doing quite a bit of research on getting the Back Button to work with Ajax, but all of the cases I find do not really apply! This is partially because my whole setup changes the current_step in the controller code I guess. Even if I did put my controller code into the new action, the previous step wouldn't be loaded because there is no :back_button parameter.

I guess my first question would be: Is there a way to add the :back_button parameter ONLY when the browser's back button is pressed?

That would be ideal, because then all of my current code would just work. I know one could add that param by binding to the ajax send callback somehow, but I ONLY want it to happen when the browser back button is pressed. I thought maybe I could bind to history.back somehow, but that doesn't seem possible.

My main question: How can I fix this to get the browser to go back to the proper step?

Can I somehow read the anchor param to set the current step?

Am I going to have to change the entire method I use to go to each step?

Maybe I am just failing and doing something wrong?

I feel like I am so close!

Thank you ahead of time fellow coders, any guides which point me in the the right direction, or any alternate methods which are prettier would also be helpful. Also, I don't want to use any Premade Plugins to accomplish this.

If you need more information just let me know.

Thanks!

EDIT:

I'm opening this up question up to possibly include decent pre-made plugins/gems/libraries which have a strong backing and are supported enough to go in a production environment.

Benjamin
  • 1,832
  • 1
  • 17
  • 27

3 Answers3

2

I use a jQuery plugin called jQuery BBQ, with good success

basically it allows you to push an array of data (usually to record your ajax state) whenever the user is leaving the current page. If the user clicks back button, it pops the state array and lets you write an event handler to restore your ajax state, based on the array

Either way, its worth a look, since its never caused me any support issues since I started using it a year ago.. http://benalman.com/code/projects/jquery-bbq/docs/files/jquery-ba-bbq-js.html

Its also tested on modern browsers (including safari). Admittedly I dont know what changes it introduces to work around Safari's lack of hashchange event support, but it works fine anyway.

carpii
  • 1,917
  • 4
  • 20
  • 24
  • I see Ryan Bates made a rails cast using this plugin before it was called jQuery BBQ and it seems pretty handy. I'll look into it and check back! – Benjamin Jul 13 '12 at 19:36
  • I use this too and find that it works quite well for what I need – arcyqwerty Jul 17 '12 at 14:03
1

You can watch the event called 'hashchange' with jquery

$(window).bind('hashchange',function(){ 
/*
    do stuff where you want when the back button is hit here
*/
});

Whatever logic you want to put there should work. when you hit the back button. You should be able to track the changes in that call or whatever.

I've used this trick when creating a page that is completely dynamic and using the anchor tag to navigate between pages. it works for forward and backwards. In your case you may want to make sure not to allow the forward button in case of resubmission or whatever validation logic you have.

Wilile
  • 23
  • 5
  • hashchange is not supported by Safari: a definite requirement. I was really pumped this was going to do it too. Is there a work around for browsers which don't support this? I think I am going to edit my answer to ask for possible pre-made solutions too. – Benjamin Jul 11 '12 at 00:21
  • I just tried this in safari with Version 5.1.6 (7534.56.5) and it seems to get fired. I'm not sure if its 'officially' supported, but it seems to work for me. A similar question http://stackoverflow.com/questions/4029433/does-onhashchange-work-in-safari seems to point to hashchange working in the latest version – Wilile Jul 11 '12 at 12:15
  • Strange... let me play around with it more; especially since I am using 5.1.7 – Benjamin Jul 11 '12 at 18:11
  • How are you testing it? My safari definitely says it doesn't work using this: if "onhashchange" in window alert('THIS TOTALLY IS SUPPORTED') else alert('THIS TOTALLY IS NOT SUPPORTED') That's coffee script btw. – Benjamin Jul 11 '12 at 18:19
  • I just reread your comment: are you saying despite the if statement telling me otherwise, it still works in Safari? – Benjamin Jul 11 '12 at 18:27
0

You can do that with the plugin Jquery Adress : http://www.asual.com/jquery/address/

  • Do you use this plugin at all? Mr. Bates mentioned the API isn't as intuitive as JQuery BBQ. What are your thoughts on it @tekilatexee? – Benjamin Jul 18 '12 at 19:13
  • I do not know JQuery BBQ. Jquery Adress is very simple to use. You can save all pages (with #blabla) in browser history and when user go back you can reload his data with AJAX. – Sébastien - Vélhost Jul 19 '12 at 06:54