Depending on what camp you find yourself in, there are the people who really like jQuery UI and the people that do not. I’m one of those people that tends to stay out of the argument because I just want to get things done as quickly and efficiently as possible. Do I use jQuery UI all the time? No. Am I using it on fairly large intranet application the team and I are working on? Yes, because it fits the bill.
Since I haven’t found a great deal of UI examples that integrate existing plugins, I thought I’d tackle one that a lot of people might find useful: using a modal form window with the excellent Validation and Form plugins. I’ve been using these plugins for a long time, and they are generally the first thing that I install with every jQuery install because they are just so darn useful. But how do you make them work with the jQuery UI theme and functionality? Lets break it down.
Note: this is a basic example, really the bare minimum one could use to get any form up and running. You could simplify this down further, but I’m trying to make it more understandable. I added a bit of additional styling to the example that I’ve omitted below for simplicity sake. The UI theme in use is called UI Lightness.
Step 1: Setup some div’s
What I like to do is always have a return message block that contains informational messages after the form post, as well as a target div for any data that needs to be loaded/refreshed/appended to. Before jQuery UI, I used to style out my own message blocks and it works totally fine. But the UI theming is just so darn good, lets put it to use.
<div class="ui-widget ui-helper-hidden" id="client-script-return-msg">
<div class="ui-state-highlight ui-corner-all" style="padding: 0pt 0.7em; margin-top: 20px;">
<p><span class="ui-icon ui-icon-circle-check" style="float: left; margin-right: 0.3em;"></span>
<span id="client-script-return-msg-rtn"></span>
</div>
</div>
Confused? I was. The block above is largely taken from the demos from the API documentation, with a few modifications for our return message. Key things to take away from that code block:
- Any class with “ui-” in front of it is part of the jQuery UI CSS Framework. If you haven’t read that documentation, I highly suggest you do so, as it’ll help make using UI much easier.
- The class “ui-helper-hidden” hides the div via display:none until we need it later (again, that’s a stock jQuery UI CSS class)
- We set the main div block with an ID equal to “client-script-return-msg”, and our return message is going into an added span element with the ID equal to “client-script-return-msg”.
We now have our return message block. Let’s now add a target for our form post return and a button we’ll use to open the modal dialog:
<button id="load-my-modal" class="ui-button ui-state-default ui-corner-all">Open Modal Form</button>
<div id="client-script-return-data" class="ui-widget ui-widget-content">For our example, our form post from the modal will replace this text.</div>
Pretty straight forward. You will note that we’ve used more UI class elements to make things theme friendly and assigned some ID’s which we’ll be using in our JavaScript calls.
We now turn our attention to the actual form and the modal window that holds it. First, let’s setup the modal div block like so:
<div id="my-modal-form" title="Edit some data"></div>
We give it and ID that we’ll use later and assign it a title with jQuery UI will use for header display on the modal popup. You’ll note, we don’t give this container a ui-helper-hidden class attribute; this is because jQuery UI will take care of that for use when we define that block as dialog.
Now let’s add in our error block to catch error messages:
<div id="my-modal-form" title="Edit some data">
<div class="ui-widget ui-helper-hidden" id="errorblock-div1">
<div class="ui-state-error ui-corner-all" style="padding: 0pt 0.7em;"
id="errorblock-div2" style="display:none;">
<p>
<span class="ui-icon ui-icon-alert"
style="float: left; margin-right: 0.3em;"></span>
<strong>Alert:</strong> Errors detected!
</p>
</div>
</div>
</div>
You’ll note this looks slightly different for our information block. Key takeaways:
- We keep the block hidden until the validation plugin needs to display it via the class ui-helper-hidden
- We give both the main div an ID of errorblock-form1 and the secondary content div the ID of errorblock-form2; you’ll need both later
- There is an empty UL tag on purpose; it’s going to hold our error messages
Now that we have our error block, lets toss in a form:
<div id="my-modal-form" title="Edit some data">
<div class="ui-widget ui-helper-hidden" id="errorblock-div1">
<div class="ui-state-error ui-corner-all" style="padding: 0pt 0.7em;"
id="errorblock-div2" style="display:none;">
<p>
<span class="ui-icon ui-icon-alert"
style="float: left; margin-right: 0.3em;"></span>
<strong>Alert:</strong> Errors detected!
</p>
</div>
</div>
<form action="testme.php" name="modal-form-test" id="modal-form-test"
method="POST">
<fieldset>
<label for="fullname">Name</label>
<input type="text" name="fullname" id="fullname"
class="text ui-widget-content ui-corner-all" />
<label for="email">Email</label>
<input type="text" name="email" id="email"
class="text ui-widget-content ui-corner-all" />
</fieldset>
</form>
</div>
The only thing to note is that there are no buttons; jQuery UI’s dialog takes care of that for use. Now let’s write some JavaScript and jQuery code!
Step 3: Wire things up with jQuery goodness
First things first: let’s make our div block with the ID of my-modal-form a modal dialog:
var amodal = $("#my-modal-form").dialog({
bgiframe: true,
autoOpen: false,
height: 300,
modal: true,
buttons: {
'Update Data': function() { $("#modal-form-test").submit(); },
Cancel: function() { $(this).dialog('close'); aform.resetForm(); }
}
});
I’m not going explain the whole list of options that a dialog() call has (that’s what the dialog documentation and demo is for) but let’s run down the important one’s that make our example really work:
- autoOpen: false keeps our dialog from automatically opening on page load
- modal: true makes our dialog modal, which basically means you aren’t doing anything else with the underlying page until you dismiss the dialog box
- buttons: setups our buttons for our form action.
Let’s talk about the buttons for a second. You will note that one button that we are calling “Update Data” has function defined that runs $("#modal-form-test").submit(); This does exactly what it says. But Justin you say, I thought we were using the Validation and Form plugins? We are…just not right there. Only thing we want that button to do is submit the form (for the purposes of this example).
The cancel button does two things: $(this).dialog(‘close’); closes the dialog box, and aform.resetForm(); resets the form state. But Justin, where did you get aform? Ah, you’re catching on. We have to define our validate() function.
var aform = $("#modal-form-test").validate({
errorContainer: "#errorblock-div1, #errorblock-div2",
errorLabelContainer: "#errorblock-div2 ul",
wrapper: "li",
rules: {
fullname: "required",
email: {
required: true,
email: true
}
},
messages: {
fullname: "Please enter your name.",
email: {
required: "Please enter your email address.",
email: "Please enter a valid email address."
}
},
submitHandler: function(form) {
jQuery(form).ajaxSubmit({
target: '#client-script-return-data',
success: function() { $('#my-modal-form').dialog('close'); successEvents('#client-script-return-msg'); }
});
}
});
A fair amount of code, but it’s not too bad. Lets break it down.
- errorContainer: “#errorblock-div1, #errorblock-div2” - a lot of people wonder why you have to set both the parent errorblock-div1 its child errorblock-div2 as the errorContainer. The reason is that if you do not, our error messages won’t properly appear. errorblock-div1 is hidden, but we also need to be able to not only show errorblock-div2, but also reset it’s message state when a submit or cancel happens.
- errorLabelContainer: “#errorblock-div2 ul” - remember that empty UL we put in? This become our container for error messages.
- wrapper: “li” - by default, the Validation plugin puts error messages into LABEL containers, but since we’re targeting a UL, we want to make sure we use LI
- rules: and messages: - these correspond to our form inputs and are for validation of the data. If you use the metadata plugin, you can do this inline on the form elements, but for the sake of this example, I’ve left them in place to make the example a little easier to understand
- submitHandler: this does all the form posting work and is part of the Form plugin (using the ajaxSubmit(); )
- target: - which block we want our return data to go into, in this case the previously setup div client-script-return-data
- success: - the function runs $('#my-modal-form').dialog(‘close’); to close the dialog on a successful submit, and then runs my custom function successEvents(); which I’ll show you shortly.
The successEvents() function is something I came up with to make things pretty, but to also make return messages fade out and hide after a certain amount of time. The function looks like:
function successEvents(msg, datatable) {
// JDR: microseconds to show return message block
var defaultmessagedisplay = 10000;
// JDR: fade in our return message block
$(msg).fadeIn('slow');
// JDR: remove return message block
setTimeout(function() { $(msg).fadeOut('slow'); }, defaultmessagedisplay);
};
As you can see, the function simply fades in our return message block (which we hide to start) and then fades it out after 10 seconds.
Step 4: The backend AJAX call
The backend form post script could do anything you want it to do. The thing to remember that in this example we’re just returning HTML to our return block (not JSON or XML). The example is important however, as it has the last key piece to our return message block:
<script type="text/javascript">
jQuery(function() {
var stringMsg = "<strong>Success!</strong> Your information was updated."
$("#client-script-return-msg-rtn").html(stringMsg);
});
</script>
<div>
<label>Name: <?php echo $_POST["fullname"]; ?></label>
<label>Email: <?php echo $_POST["email"]; ?></label>
</div>
The only major thing to note is that we had originally set up a span with the ID of client-script-return-msg-rtn to handle our return message. $("#client-script-return-msg-rtn").html(stringMsg); does the work of setting that message in that block (the var stringMsg is defined above it). We don’t we unhide it? Because the successEvents() function takes care of that for us.
Step 5: The last step
The last step is a simple one: we have to tell our button to open the dialog box. To do so, we attach a click event:
$('#load-my-modal').click(function() {
$('#my-modal-form').dialog('open');
});
And here’s a little nifty trick I picked up somewhere (for the life of me I forget where, and if you’re the author please email me because I like to give credit where credit is due). Let’s make all our buttons have a nice UI hover effect:
var abuttonglow = $(".ui-button:not(.ui-state-disabled)")
.hover(
function() {
$(this).addClass("ui-state-hover");
},
function() {
$(this).removeClass("ui-state-hover");
}
).mousedown(function() {
$(this).addClass("ui-state-active");
})
.mouseup(function() {
$(this).removeClass("ui-state-active");
});
Final Thoughts
While it may look like a lot of code for what is a fairly simple procedure, this set of tools allows a robust and consistent experience to be displayed to the user. The example above can styled with Themeroller without so much as a single line of code changed. Using the Validation and Form plugins would also us even more possibilities without having to write a lot of supporting code (and I don’t know about you, but I can’t stand writing validation rules in JavaScript by hand…that’s so 1997).
Happy coding!