UPDATE 12 July 07: Check out this more recent post for more info on modal dialogs.
In the Ruby On Rails project on which I'm currently working, I felt the need to introduce the concept of a modal dialog box. This is a common requirement in traditional client-applications, in order to restrict a user's actions to a certain area of the screen. However, until the advent of Web 2.0 it has been tricky implement in internet-based applications.
I tried a few different approaches, but finally settled on using the Xilinus Prototype Window javascript libraries to help me out.
A bit of background...
In my project, I orginally had a table which contained links to allow the user to edit the (often complex) contents of some of the table-cells. The links would causethe user to be navigated away from the page, and so after they had finished doing their editing they would have to navigate back. This is all very well, apart from the fact that if we wanted the site to remember other values that the user had entered on the first page, it meant storing hoards of things in the session. I stuck with this approach for a while, but the more functionality I added to the page, the more work I had to put into maintaining state in the session. Something had to change!
My solution
1. First download the Prototype Window libraries from here. (I used version 0.96.2).
2. The download zip-file contains a bunch of folders. Put the window.js file from the javascripts folder into your rails project's public/javascripts folder. (You will also need the prototype.js file, but this should already be there for you if you generated your project from a skeleton). The stylesheets folder in the zip-file contains all the different themes that are demonstrated on the xilinus prototype window samples page. The styles that you want to use need to go into your rails project's public/stylesheets folder. (I made a window subfolder to keep things tidier).
3. So that your views can use the prototype window javascript, put a javascript include tag in the head of the appropriate layouts file. For the sake of this example, put it in the application.rhtml layout file.
<%= javascript_include_tag "prototype", "effects", "window" %>Also put in a stylesheet link to the style of modal dialog log you want.
<%= stylesheet_link_tag "/stylesheets/window/default" %>We're going to use some javascript later, so put a content_for_page_scripts tag in the head of the layout too.
<script type="text/javascript"><%=@content_for_page_scripts %></script>
4. In the view from which you wish to launch the modal dialog, we need some javascript. Write a function, and put it inside a content_for page_scripts block. Here, the function launches a modal dialog containing the web page at the url passed in.
<% content_for("page_scripts") do -%>
function show_Array_Window(myUrl)
{
win = new Window('window_id', {title: "Array", width:300, height:500, url:myUrl});
win.setDestroyOnClose();
win.showCenter();
}
<% end -%>
5. Now set up a link for the user to click on, and set the onclick event to the function we just wrote. In the example below, we're building up a table with a link to a different object in each row's cell. (If you just want a permanent link to a single modal dialog, you dont need to go to the trouble of building up a dynamic onclick string).
<table>
<% for i in 0...@my_array.length do %>
<tr>
<td>
<%=
# other code here if you like
"<a href = \"#\" onclick='show_Array_Window(
\"" + url_for(:controller => 'my_controller',
:action => 'my_Action', :id => i) + "\")'>
Go Modal!</a>"
%>
</td>
</tr>
<% end %>
</table>
6. You can now do whatever you want in the page that's shown. In my case, this involved allowing the user to edit the complex data structure that was represented by the object in the table.
... and that's it.
The advantage of using the Xilinus Prototype Window libraries over other modal dialog approaches like lightbox gone wild is that because you just point the dialog to a url, the page that is shown inside can include its own javascript. This allows you to do ajax stuff inside your dialog like it was any other rails page. (I wont go into the whole ajax thing here).