Coding with Jesse

jQuery Live Events

February 16th, 2009

jQuery 1.3 came out on January 14th, jQuery 1.3.1 on the 21st, and with them we now have live events built into jQuery.

Live events are pretty magical at first glance. They allow you to set events only once, and they work forever in the future, even as you're creating new elements and adding them to the page.

Normally if you ran:

$('a.wizard').click(function(){
    // do some wizardry
});

and then later you added wanted to add some more <a class="wizard">s to the page, you would have to re-attach this event handler over and over.

Live events allow you to add an event that will work forever. This means you only have to add each type of event once. You would only have to write:

$('a.wizard').live('click', function(){
    // do some wizardry
});

And your wizard links will work forever, even after you add 100 new wizard links to the page dynamically.

This magic trick works by attaching the click event to the document. Whenever you click anywhere on the page, the document click event gets called. jQuery compares the target element to your wizard links and triggers your click event if the click came from inside the link.

You can also do this yourself using the new closest() function. It allows you to do something like this:

// listen for clicks on the document
$(document).click(function(e){
    // look for a possible parent element matching a.wizard
    $(e.target).closest('a.wizard').each(function(){
        // wizard it up
    });
});

These live events can really help with performance. If you're attaching events to 100s of similar elements, like photos in an album, you can also save a lot of memory and speed things up by using live events, or using the example above and checking for events on a common parent element, either document or any element.

If you're used to using closures to use data within click handlers, you will find they won't work anymore which is probably a good thing. Instead, you can use data() to store any amount of data with that element and get it out later:

// maybe this is some JSON data you got using Ajax or something
var wizards = [
   { name: 'Merlin', skill: 'magic' },
   { name: 'Mr. Wizard', skill: 'science' }
];

$.each(wizards, function(i, wizard){
    // create a new link, change the text, add the data and append to the body
    $('<a class="wizard"/>')
        .text(wizard.name)
        .data('wizard', wizard)
        .appendTo(document.body);
});

then you only need to attach the click handler once:

$(document).ready(function(){

    $('a.wizard').live('click', function(){
        // fetch the data back out
        var wizard = $(this).data('wizard');

        // get the stuff you need out of the object
        var name = wizard.name;
        var skill = wizard.skill;

        // do your thing
        alert(
            "Hello my name is "
            + name
            + "and I'm better than you at "
            + skill
            + "!!!"
        );
    });

});

And you can actually do these things in reverse, the order doesn't matter because of the magic and universality of live events.

Pretty cool, eh? This way of developing has always been possible using JavaScript, but after learning about this with jQuery 1.3, it changed the way I look at programming with data and events.

What do you think? Any questions, corrections or suggestions? Leave a comment.


Interested in web development? Subscribe to my newsletter!

buttons need type="submit" to submit in IE

December 26th, 2008

In a typical round of doing Internet Explorer clean up at the end of a project, I had to figure out why my <button>Submit</button> wasn't submitting a form in IE.

I did a search on "html button" and went to the w3c HTML 4.01 specifications:

type = submit|button|reset [CI]

This attribute declares the type of the button. Possible values:

submit: Creates a submit button. This is the default value.
reset: Creates a reset button.
button: Creates a push button.

So the default is submit. But Internet Explorer has obviously forgotten this in IE6 and IE7. I found it worked without type="submit" in Firefox, Safari, Chrome and Opera. I haven't tested in IE8 because I don't have it installed. Maybe someone wants to check it out? Here is a demo page.

So I guess we should get in the habit of using:

<button type="submit">Submit</button>

Interested in web development? Subscribe to my newsletter!

Use Arrays in HTML Form Variables

November 3rd, 2008

When you're dealing with processing forms, a lot of the time you have a one-to-one mapping of form fields and database columns, with perhaps an extra submit button or some fields that need special processing (eg. passwords).

Although many frameworks like CodeIgniter make this easier, you can still easily come up with code like this:

$this->db->insert('accounts', array(
    'first_name' => $this->input->post('first_name'),
    'last_name' => $this->input->post('last_name'),
    'email' => $this->input->post('email'),
    'address1' => $this->input->post('address1'),
    'address2' => $this->input->post('address2'),
    'city' => $this->input->post('city'),
    'state' => $this->input->post('state'),
    'zip' => $this->input->post('zip'),
    'phone' => $this->input->post('phone'),
    'fax' => $this->input->post('fax')
));

See all that repetition? Whenever you see a group of lines that look almost the same, you know there is probably an opportunity to clean things up. Well luckily, there's a really neat one.

You can create arrays in form fields using square brackets. That means you can name fields like account[first_name] and account[last_name] and in most server-side languages, you will end up with an 'account' array.

In HTML, PHP and CodeIgniter, that might look something like this:

<input type="text" name="account[first_name]"/>
<input type="text" name="account[last_name]"/>
<!-- etc... -->
<input type="text" name="account[fax]"/>
<input type="submit" name="submit"/> <!-- note the lack of 'account' -->

// meanwhile, on the server...
$account = $this->input->post('account');

// VERY IMPORTANT: unset any fields that shouldn't be edited
unset($account['id']);

$this->db->insert('accounts', $account);

See? Much cleaner. Yes, you do open a slight security hole potential, so be very careful when doing this on tables that have security implications, ie. user data. If you have an 'admin' column on your 'users' table, someone could maliciously add <input type="hidden" name="users[admin]" value="1"/> to your form using Firebug and grant themselves administration access. You can solve this by adding something like unset($user['admin']); to the incoming data. If you wanted to be really safe, you could have an array of the keys you want to allow and filter against that using something like PHP's array_intersect_key with array_flip:

$user = $this->input->post('user');

// only allow keys in $user to match the values in $columns
$columns = array('first_name', 'last_name', /* etc.. */ );
$user = array_intersect_key($user, array_flip($columns)));

You can even do this with checkboxes and multiple select boxes, and alternatively leave out the key in the array to create a regular array (ie. not associative) of values:

<label><input type="checkbox" name="choice[]" value="1"/> 1</label>
<label><input type="checkbox" name="choice[]" value="2"/> 2</label>
<!-- etc... -->

// meanwhile, on the server...
$choice = $this->input->post('choice');

print_r($choice); // Array ( [0] => 1 [1] => 2 )

This "trick" can really clean your code up. I used it recently to drastically simplify a form that had a shipping address and billing address. If the user checked a box saying "My shipping and billing are the same", I was able to simply do something like this:

$shipping = $_POST['shipping'];
$shipping_billing_same = $_POST['shipping_billing_same'];

if ($shipping_billing_same) {
    $billing = $shipping;
} else {
    $billing = $_POST['billing'];
}

Much nicer than that 24 form fields that were hard-coded previously.

I've given examples here in PHP and CodeIgniter. Does anyone else want to give examples in other server-side languages and frameworks?


Interested in web development? Subscribe to my newsletter!

5 Reasons Freelancers Can Succeed in a Shrinking Economy

October 24th, 2008

Like many people, I've been a bit obsessed about the economy lately. I'm wasn't sure whether or not to be scared, and to be honest I still don't. But I did think of some reasons freelancing might be a safe place to be.

  1. You have a diversified clientele. Your clients can be anywhere in the world, and you have many of them. And if you're lucky, you have more than enough work to fill your time. No matter how bad the economy gets, there should still be some business available.
  2. You have very little overhead. For most freelancers, all you need to work is a laptop and the Internet, both of which you'd probably have even if you weren't freelancing. You probably pay $10/month for your web site hosting, but otherwise you don't have a reason to borrow money. The gears of the credit crunch don't touch your business.
  3. You can drop your prices whenever you want. If you find less people can afford what you're charging, you'll be able to adjust accordingly. If you have a job and they decide they can't afford you, then you get laid off.
  4. The Internet is the place to be for self-employed professionals. With the considerably low cost of having the Internet, I would assume that a lot more business will happen online as more people become self-employed and work from home. The number of people you can potentially connect with online feels infinite.
  5. Businesses who don't want employees might turn to freelancers. Who knows, maybe in uncertain times, more business will want to hire freelancers on a contract basis rather than dedicate to hiring an employee they don't know if they'll be able to keep.

For those of you who don't freelance, I'm not suggesting you quit your job and start freelancing tomorrow. You'll have to decide that for yourself. If you want to start freelancing, I would suggest is to get the ball rolling on the side while you have a job. Get that website up and get some presence on the Internet. That way you'll have something to fall back on if you lose your job.

So things don't look too bad for us freelancers. How about you? Have you noticed the shrinking economy having a direct effect on your business or job? What do you think we can expect?


Interested in web development? Subscribe to my newsletter!

Keeping a Live Eye on Logs

October 22nd, 2008

In web development, you can get really used to getting good error messages. If you're coding in PHP, you come to rely on the web server telling you if a variable is undefined or a file is missing.

Likewise, when you're debugging, sometimes the easiest sanity check is to output some text. You'll find me using echo "wtf?"; die; quite often when I'm trying to figure out why a block of code isn't being executed.

But sometimes, even these rudimentary methods of developing aren't available to you. Maybe error messages are turned off on the web server you're stuck debugging. Or maybe you have a lot of Ajax requests flying around and are tired of peeking at the result of each request.

Log files to the rescue. Nearly every framework and server has logging functionality. Apache usually logs every request, so you can see when images, static files, and other requests are made. CodeIgniter has several levels of logging, including DEBUG, ERROR and INFO. Whatever framework you use, or if you're using one you built yourself, you'll probably find some way of writing log messages to a file.

And if you have a log file that's being updated, you have a way of watching things happen in real time. I'm not talking about opening up the log file every now and then and looking back through it, I'm talking about watching it being updated as it happens.

Let's say you have a web server running Linux and are trying to debug something using CodeIgniter. You SSH into the web server, find the log file, and tail -f it. tail is a command which will dump the end of a file out for you. If you add the -f parameter, it will "follow" the file, printing out any new lines as they are added to the log file.

$ cd thefutureoftheweb.com/system/logs
$ tail -f log-2008-10-23.php

If you're working locally on Windows, make sure you have Cygwin installed. (Cygwin gives you a Linux-style console in Windows so you can do awesome stuff like this.) If so, you should have or be able to use tail in the exact same way. Mac and Linux users should have tail installed already.

Back at my old job, we used to keep console windows open using tail to watch the live web servers, especially after an update. This way we could see errors appearing to users live and could investigate and solve problems that would otherwise a) get buried in the logs, or b) go completely unnoticed.

It can really help to get in the groove of having one or two terminal windows open tailing the logs of the servers you're currently working on. And then if you get the urge to write echo "wtf?"; die; you can instead write log_message('info', 'wtf?'); (or equivalent in your framework of choice).

For further information, check out:

Happy tailing!


Interested in web development? Subscribe to my newsletter!

<< older posts newer posts >>