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.
I'm in need of a few good developers. I've put up a job posting at Authentic Jobs, PHP Web Developer / Project Manager:
(Anywhere) I'm looking for an individual (no teams) to help me lead web development projects. I need someone with lots of experience giving quotes and managing projects with other developers involved.
You will be coding in the trenches, and need to be a master of PHP, MySQL, HTML, CSS, JavaScript and other web technologies.
You should have a ton of experience with software development. You must write elegant code and be able to architect and implement beautiful, uncoupled, well tested software.
You should be a web standards advocate, be familiar with unobtrusive techniques and understand the importance of creating high-quality, accessible web sites and applications.
Your English should be impeccable and professional, both spoken and written.
I need someone that can be available to work up to 30 hours per week, and be committed to helping out over the long term.
If this sounds like you, and you want to take a lead on exciting web development projects, please contact me with the following stuff:
1. Your hourly rate
2. Your resume
3. Your location
4. Your weekly availability
5. Your work experience
6. Your expertise
7. Type of projects you enjoy most
If you'd like to work with me on cool projects, please contact me here.
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>
Sometimes the hardest part of being an aspiring writer is coming up with a practical excuse for actually sitting down and writing an article.
Contests to the rescue! Server-Side Magazine is holding a contest for new articles. What better excuse to start writing than the chance of winning a $200 Amazon gift card, just in time to do some Christmas shopping? At the same time, you'll be getting a bit of practice and feedback, and exposure with fellow developers.
You'd better hurry though - you'll need to craft a 1000-word-article about any PHP, Ruby or ASP.Net topic before November 27th, 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?