Tips and Tricks - FormsIntroductionWhen I initially experimented with PHP and Javascript to make a basic test application, I created an application with a form that features some basic controls - text boxes, radio buttons, and check boxes. Also, clicking on some of these controls would sometimes do basic tasks like disabling or hiding other controls. In this article, I share several Javascript and PHP tricks I learned while developing this form. Using a Javascript libraryAt first, I found myself spending a great deal of time writing helper functions to do trivial things like traversing forms, enabling/disabling and activating/deactivating parts of a page, or even just reading a radio button. This was good exercise at first but quickly became tedious. 'There must be a better way', I thought. 'Surely a million people before me have done these exact same things, and some of them must have posted their results in some kind of library', I suspected. So I searched around and ended up finding the Prototype Javascript library, and from that point on, writing Javascript was never the same again. It basically makes every part of Javascript more powerful and easier to use, especially forms and arrays. And I know I will really learn to appreciate the library once I get around to AJAX and web services! NOTE: jQuery is another popular Javascript library used by most web developers, and is particularly good at using web services. I have chosen Prototype for its simplicity, but would probably end up using jQuery if I were working on a professional project. Logging Javascript debug outputJavascript is strange in that the only universally supported way for your code to provide feedback to developers, as far as I can tell, is through annoying popup windows. I researched the topic and found that Firebug has some built in features that let you output information, warnings, and errors in a console that you can show or hide as you are testing your site. This feature is a godsend, but unfortunately only works for Firefox browsers and can crash other browsers! I have therefore created a wrapper class for debugging output that uses Firebug's console only if it is available and defaults to using popups. The key point, though, is to create a wrapper class. That way, if I find bigger and better ways to log output in the future, which I am sure will happen, I can add them to all my future projects by changing just a single file. For example, this is what a minimalistic version of an error handling mechanism using the Firebug console without breaking other browsers would look like: function error(message) {
Using the Prototype Javascript library to disable several controls at onceI wanted a whole group of checkboxes to be grayed out / disabled when I click a certain radio button. Also, I wanted to do all of this with a single function call instead of having to list each checkbox to enable or disable individually. I did not see this feature anywhere in the Prototype Javascript library documentation, and was contemplating adding this functionality, but when I looked at the Prototype source code I realized there is in fact already a way to do this within the Prototype framework. This method takes advantage of Prototype's Form.disable method. The name of the method and its documentation suggest that you use this on a form to disable all of the form's inputs. But the function is actually much more flexible than that. You can use Form.disable on any element to disable all descendants of that element! So, for example, let's say you had an online menu with a 'pizza' radio button and a variety of different 'toppings' checkboxes. And let's say you want the toppings checkboxes to be selectable only if you have chosen a pizza. You can accomplish this as follows: Wrap all of your toppings into a parent element: <input type="radio" name="entree" value="pizza" ...> <div class="toppings"> <input type="checkbox" name="pepperoni" ...> <input type="checkbox" name="sausage" ...> ... </div> Use this javascript when processing a click on the radio button: Form.enable('toppings');
Using the onDomReady eventThere is an important but little known distinction in Javascript - the difference between the onload and onDomReady events. Most developers run Javascript after a page has loaded by using the built-in onload event. Unfortunately, if you have a large page that takes a long time to load, this can be a nuisance. I'm especially thinking of the case where you automatically direct the user's input to a text box to help them fill out a form. If this happens immediately, it can be great for the user experience, but if the page takes a few seconds to load and then redirects the user's input, it can be very annoying. Well, it turns out that there is a way to run Javascript so that your code executes before the site is fully loaded and still have access to user input and the rest of the site's DOM (Document Object Model) data. This is called the onDomReady event. Unlike the onload event, this event is not already defined for you, so you will need to use your browser's event handling system to define this event yourself. You can find the source code for defining the onDomReady event by visiting the site from which I learned this technique. Generating default data for formsOne technical challenge that I found surprisingly tricky was to set the default behavior for my user interface using solid engineering and design principles. I wanted each choice to have a default, but I did not want to hard-code this default into my forms. I also wanted the Javascript side to react as if the user had entered the defaults himself so that the appropriate parts of the form are activated or deactivated. Essentially, what I was aiming for is a form where if I want to change which fields were selected by default, I would only need to change the values of some settings, and the rest just happens automagically. Generating defaults in PHPThe first challenge that poses itself is the way a form behaves in PHP. I'm using the typical approach of submitting the form data as HTTP POST data. This means that the very first time you use the form, you will not be able to read any of the filled out form data. So for a long time my PHP code was cluttered with logic where I would account for the special case of using the form for the first time. I finally came up with an elegant general purpose solution for abstracting away from this technical detail: First, I define all of my default settings. I can put these in my PHP code in a small project, but in a larger project these would most likely be in a separate configuration file, like an .ini or .xml file: //default selection for a radio group The first time the form loads, and only the first time, I load the default settings into my list of POST values. That way, regardless of whether or not this is my first time using this form, I can always look at my POST values to see how a field in the form was filled out! This effectively abstracts away from the detail that POST data is not ready the first time you load a form, so after doing this you can always access a field's value through $_POST[field]: if (empty($_POST)) {
<input type="checkbox" name="pepperoni" <?php if($_POST['pepperoni']) echo "checked='checked'";?> /> Responding to defaults in JavascriptOn the Javascript side, you will want to react to some of the checkboxes or radio buttons as if the user pressed them so that you activate/deactivate the right parts of the user input. In this example, you want the toppings checkboxes to be active only if a pizza was selected. I do this by reading the values of the relevant inputs as soon as the form loads and modifying the form as necessary. This is where the aforementioned onDomReady trick comes in handy - I execute this logic as soon as the DOM data loads, before the site is fully loaded, so that there won't be a hitch in the user experience for large sites or slow connections. If a radio button was selected, I simply call its onclick() function to make the form respond as if someone had pressed the button. Be sure to read the onDomReady section of this writeup to understand how the event works before trying this at home. Here is the sample code for just one radio group: function init(){
switch (getSelection('entree'))
{
case 'pizza':
pizza_clicked();
break;
...
}
...
}
window.onDomReady(init);
Back to Blog |