# Progressively Enhance a Form to a Modal Form

With something as important as a contact form, you want it working properly for all visitors—even the JavaScript challenged. How do you handle this if you want to use a modal (pop-up) form? The answer is progressive enhancement; start with baseline, usable functionality; then increase the user experience for those who have browsers to support it.

## Step 1: Decide on the Project Goals

Before starting any journey, it helps (most times) to have a destination. The goal of this project is to take a standard link to a page containing a contact form and enable that form to pop-up on the current page in a modal dialog.

There's several reasons for this approach:

• If the user has JavaScript disabled, they are sent to the contact form page as usual.
• Only one version of the form must be maintained.

## Step 2: List the Tools

To write this from scratch in raw JavaScript would be a lot of code. Fortunately for us, there are existing tools we can leverage to make the task easier. This tutorial relies on:

To make this code as reusable as possible, we'll write a plug-in. If you are unfamiliar with authoring a plug-in, you can get an introduction from Jeffrey Way's article here on Nettuts+. The modal functionality will come from jQuery-UI's $.dialog. ## Step 3: Design the Plug-in Interface We're going to follow the normal pattern for a jQuery plug-in: calling the plug-in on a selector and setting options via array. What options are needed? There will be options both for the modal window and for the plug-in itself. We're going to expect the plug-in to be called on an anchor, and enforce that in the code. ### Examining the options Container: This is how the plug-in user will specify the ID of the form on the remote page. The link itself specifies the page, but container option will allow us to fetch the relevant part. This will be the only required option when calling the plug-in. Modal, Resizeable, Width, Title: These options are all going to be passed along to jQuery UI's$.dialog. The values above are defaults and the plug-in will run just fine without any of these being set when $.popUpForm is called. beforeOpen, onSuccess, onError: These are all callbacks, and expect a function. The function will be passed the object for the link that was clicked as 'this' and the container to which that link is targeted. Callbacks are designed to allow custom functionality for the users of a plug-in. The default for these callbacks will be an empty function. The minimum code required to use the plug-in would then look like this: That seems simple, doesn't it? When you call a plug-in like this, the plug-in's code is called with a jQuery collection of all the DOM elements matching the selector, which will be available in the special variable 'this'. ## Step 4: The Plug-In's Skeleton Most jQuery plug-ins follow a very similar pattern. They iterate over the group of selectors and do whatever it is they do. I've got a basic plug-in "outline" I generally work from, and it will fit in here nicely. This would be the start of your plug-in file, popUpForm.jquery.js. The code is wrapped in a self-executing function, and adds itself to jQuery using the$.fn namespace. The identifier following $.fn is the method name you'll use to invoke it. We're also following good coding practices by passing in the jQuery variable explicitly. This will keep us from getting into trouble if the plug-in is used on a page with other JavaScript frameworks, some of which use$ as a variable.

Next, an array of default values is created, and these defaults will be used if they aren't defined when the plug-in is called. The line immediately following the defaults array merges the passed in options with the defaults and stores them all in the opts array.

Finally, a loop is created for iterating over the jQuery collection identified by the selector when the plug-in is called.. While chances are in most situations it will be a single item ( an anchor), it will still handle multiple links with a single call - assuming they all load the same form.

An important thing to understand is that the value of the special variable 'this' changes when we enter the self.each loop; it's a special jQuery method designed to make looping DOM collections easier. The callback function uses the context of the current DOM element, so the variable 'this' refers to that element within the loop.

You can see in a very simple example how 'this' refers to a jQuery collection of jQuery objects in the plug-in function scope, but inside the each loop, 'this' refers to a single, non-jQuery DOM element.

## Step 5: Starting the Guts

The code for the next few sections is all contained within the self.each block of our skeleton. What do we do now? For each jQuery element passed in, there are going to be several steps to take:

• Make sure it is a link, and that it goes somewhere
• Fetch the part of the remote page specified
• Attach the remote form to the page, and create a hidden dialog for it
• Steal the link so it creates our pop-up
• Handle form submissions AJAX style

Before doing any of that, however, we're going to add one line of code inside the callback, at the very top

This is more then just convenience; the variable 'this' will go out of scope in any closures within the each loop, and we're going to need access to the current object later. Since we'll almost always want it as a jQuery object, we're storing it as one.

## Step 8: Attach the HTML and Create the Dialog

Inside the $.load callback, the code is going to attach the form, override the click event of the anchor, and override the submit event of the form. The form's HTML is stored in the formDOM variable at this point, and attaching it to the existing page is easy. The id #popUpHide refers to a hidden div that will attached to the page by the plug-in. In order to provide that div, the following line will be added at the top of the plug-in. If it already exists, we don't recreate it. Now that the form is hidden safely away on our page, it is time to use a call to the$.dialog method to create the form. Most of the set-up params are taken from our plug-in. The 'autoopen' option is hard coded since we want the dialog to open when the link is clicked, and not when the dialog is created.

## Step 9: Override Default Event Handling

If we stopped here, the plug-in wouldn't be doing much. The link would still take us to the next page. The behavior we desire is for the link to open the dialog.

The first line of this click handler is very important. It stops the link from loading the new page when it is clicked.

The second line is our 'beforeOpen' callback. The variable opts.beforeOpen contains a function reference - that much is obvious. The .call method is used to invoke the function in a way where we can provide context -- the 'this' variable for that function. The first argument passed becomes 'this' to the called function.

When a function has access to the variable 'this' there are some contracts JavaScript has with the programmer that we should maintain.

• The 'this' variable should be the object the function acts on
• The 'this' variable is a single DOM object

In order to maintain that contract, we pass $this[0] instead of$this. $this[0] represents a single, non-jQuery DOM object. To help understand this a little better, imagine the following callback function: The link click isn't the only default behavior to override. We also want the form to submit via AJAX, so the normal form onsumbit event needs to be prevented and new behavior coded. Again, we use preventDefault() to stop the event, and in this case add a new function to handle the form submission. The ajaxSubmit() code could go directly in the callback, but it has been moved to a new function for readability. ## Step 10: Handle Form Submissions, AJAX-Style This function would be added immediately after the end of the self.each loop ( don't worry, you'll see the entire plug-in code in one shot in just a bit ). It takes the form, submits it to a remote script, and fires the appropriate callbacks. The first step is to get the form as a jQuery object, and to determine the form's method, either GET or POST. If you remember, we stored the form's ID in opts.container. The next line checks the form for a method, and assigns 'GET' if no method is present. This is consistent with HTML which uses GET by default on forms if no method is specified. Use the$.ajax method to submit the form:

The URL option is determined from the action attribute of the form tag. The data is produced by using the serialize method on the jQuery object containing the form.

## Step 14: Styling the Modal

If you've gotten this far, and you created examples forms and a page to call them from, you'd notice the form in the modal is probably, well, ugly. The modal itself isn't bad, because we're using a jQuery-UI theme. But the form inside the modal is mostly unstyled, so we should make some efforts to pretty it up.

There are some things to keep in mind when creating styles for use in a jQuery-UI modal:

• The modal itself is only a child of the page's BODY element
• The contents of the modal are all children of a div of class 'ui-dialog'

Using these small bits of information we can begin applying styles to the form in the modal. First we give the modal a background color we're happy with, and also modify the font for the title bar.

Next, we want to separate each item in the form with lines. Since the form structure alternates h3s with divs containing form elements, we add the following rules:

And we only want lines between the sections, not at the very top or very bottom.

Lets not forget to style the h3s, and the form elements. The radio buttons need to display inline so they are all in a row.

Remember, these styles are specific to this project, you'll have to style your own forms depending on what structure you use. To target the form elements specifically, you can either target descendants of .ui-dialog, or to style each form individually, include styles descending from the form ID you've included.

The styled form:

## Step 15: Conclusion

So what have we really done? We've taken a normal link leading to a contact form (or forms) and caused that form to load up in a modal dialog, and submit via ajax. For users without javascript, nothing happens and the links behave normally, so we haven't stopped anyone from filling out your forms.

If you click on the survey link in the demo, be sure to submit something. I'll post the results in the comments for fun after a week or so!