Understanding Iframes

Oct 04 2010

Iframes can be tricky. In theory, they’re simplicity itself – need to incorporate the content of another page onto your site? Use an iframe! In practice, all sorts of issues pop up. Styling them can be a hassle. Weird and unwanted scroll bars show up, sometimes in multiple places. JavaScript events don’t fire, or fire inconsistently. The iframe, in short, just won’t integrate properly into the rest of your page.

The trick to successfully managing these issues is to change your thinking. The difficulty of integrating the iframe into your page isn’t a bug, it’s the essence of what an iframe is. Once you realize that, it becomes far easier to work with iframes.

Whenever I’m working with an iframe, I pretend that the iframe is simply a brand new browser window with no menu or address bar that happens to be sitting on top of my page. This is, in fact, not much of an imaginative stretch, because that’s basically what an iframe is. Despite the fact that the tag <iframe> is present in your code, the source of that iframe is not actually part of your page.

Here are two screen shots illustrating what I mean.  The first screen shot is a page with an iframe.  The second is the same page but with a separate browser window sitting on top of it. Conceptually, these amount to the same thing.

A page with separate content present in an iframe

A page with a new browser window sitting above it

If I keep in mind that the iframed content is essentially a separate browser window, managing it become much easier.  I don’t expect the CSS or JS in one browser window to have any effect on any other open windows, and so I don’t expect the JS and CSS in my main page to have any effect on my iframe content.  If I want my iframe content to be styled in a certain way, then I make the CSS changes in the iframed page’s code, not in the main page’s code. If I need jQuery to be available in my iframed page, then I’d better make sure I’m loading it in my iframed page’s code, regardless of whether or not I’ve already loaded jQuery in my main page. The page visible in my iframe, and the main page, are for all intents and purposes two completely separate pages that simply happen to be simultaneously visible on my screen.

What about scrollbars? Again, thinking of the pages as separate helps.  If I open up a new browser window, and shrink it so that it is smaller than the content it is displaying, then I’m going to see scrollbars. If I do not want scrollbars, I need to either make my browser window larger, or shrink my content. It works exactly the same way for an iframe – either make sure that the iframe’s dimensions are large enough to fit your content, or make sure that your content is short and narrow enough to fit inside your iframe.

All of this points toward one more consideration – do you really want an iframe? If you are simply looking to incorporate images and text from a remote site, consider ajax, json, RSS, or some other approach that simply grabs remote content and inserts it into the DOM. This way it actually becomes part of your document and is subject to the same CSS and JS that applies to the rest of your page. Only use iframes when you truly need to display content that is completely separate from the rest of your page.

No responses yet

When and why to use live in jQuery

Jul 03 2010

If you use jQuery for ajax, you probably use the live method. According to the documentation, live will

attach a handler to the event for all elements which match the current selector, now or in the future

What does this mean exactly? Let’s take one step back.  When you write your jQuery code, you put it inside a document ready function, like so:

$(document).ready(function() {
	$('#alinkwithanid').click(function(){
    	alert('you clicked me');
	});
});

In the example above, we’re telling the browser “Once you’ve finished loading the page, attach the function alert(‘you clicked me’) to the click event for the HTML element with the id alinkwithanid.”

In order for these instructions to have any meaning, there has to actually be an element with the id alinkwithanid. This may seem obvious. Why would you write a script that referenced a non-existent element, and why would you care if such an irrelevant script never executed?

Consider this example:

$(document).ready(function() {

	$('#alinkwithanid').click(function(){
    	alert('you clicked me');
	});

    $('#contentdiv').append('Click me!');
});

In this most recent example, assume that there is no element with the id alinkwithanid, but, as you can see above, we are adding it via jQuery’s append method. What do you expect will happen when you click that link?

If you said “an alert box with the message you clicked me will pop up,” you’d be wrong. The reason is that the alert function was attached to the link on document ready. However, that element did not exist then. Only after document ready was the append method called. So, as far as the browser is concerned, you tried to attach a function to a non-existent element.

We can make this example work, however, with a simple modification:

$(document).ready(function() {

	$('#alinkwithanid').live('click',function(){
    	alert('you clicked me');
	});

    $('#contentdiv').append('Click me!');
});

This time, we used jQuery’s live method. This allows us to attach functions to current and future elements. Any time you are using jQuery/javascript to modify the document, there’s a good chance you’ll want to use live. Examples include loading content via ajax, using jQuery’s append or prepend methods, changing an element’ attributes, etcetera.

No responses yet

Why use try/catch?

Jun 08 2010

For the longest time, I didn’t understand the point of try/catch. If I was programming in PHP, for instance, its native error handling seemed sufficient.

For instance, say I have a function that takes one required argument, but I fail to pass it that argument:

<?php
function example ($arg1) {
	echo 'The value of the passed argument is '.$arg1.'.';
}

example();
?>

This will output the following warning:

Warning: Missing argument 1 for example(),
called in C:\wamp\www\sandbox\index.php on line 6
and defined in C:\wamp\www\sandbox\index.php on line 2

No try/catch used, or apparently needed. But what if I were developing in an environment were error notices had been disabled? True, I could force error reporting back on by including

ini_set('display_errors',1); error_reporting(E_ALL);

or I could rewrite my code like so:

<?php
function example ($arg1) {
	if (!$arg1) {
		throw new Exception('Missing argument 1');
	}

	echo 'The value of the passed argument is '.$arg1.'.';
}

try {
	example();
} catch (Exception $e) {
	echo $e->getMessage();
}
?>

Assuming error reporting is disabled, I’d now get back the following output:

Missing argument 1

You may be wondering how this is helpful. After all, the code is now longer – how is this better?

For one thing, when you use try/catch, the code following the error is not executed; instead, PHP looks for a corresponding catch block and executes that instead. Why is this good? Let’s revisit our code without the try/catch block, this time assuming that error reporting has been disabled. Here’s the code:

function example ($arg1) {
	echo 'The value of the passed argument is '.$arg1.'.';
}
example();

Which outputs this:

The value of the passed argument is .

Looks fine, right? No argument was passed in, so its spot is blank. Except that $arg1 was a required argument – probably for a reason. In this case we’re simply outputting a string, but what if we were doing something more complex – connecting to a database, reading a directory, launching another function? If critical pieces of data are missing, who knows what unexpected outcomes could result. Your program will start failing in apparently random ways.

If some important expectation that your program relies on isn’t met , it’s better that your script does not go on as usual.

In our example, we’re simply outputting an error message via our exception, but we could also do something like this:

<?php
function example ($arg1) {
	if (!$arg1) {
		throw new Exception('Missing argument 1');
	}
	echo 'The value of the passed argument is '.$arg1.'.';
}

try {
	example();
} catch (Exception $e) {
	$log = new errorlogger();
	$msg = $e->getMessage();
	$log->email($msg);
}
?>

errorlogger is just a pretend class for the sake of this example. In real life, such a class might have a method for emailing the developer in case of an error, which we’re invoking via

$log->email($msg);

. Also, in real life we wouldn’t put the

$log = new errorlogger();

inside the catch block, but rather somewhere further up the page – this way we’re instantiate errorlogger only once instead of each time we have a catch block.

By using try/catch, then, we’ve gained a great deal of flexibility in dealing with errors. We can do pretty much anything we want to in that catch block. Maybe we want to redirect the user to an error page, or call some other function, or halt execution of subsequent scripts on the page – whatever is appropriate according to the business logic of your application.

In short, try/catch gives you both stability and flexibility in handling errors.

No responses yet

Automatically combine and minify JS files – UPDATED

May 31 2010

Why

A common phrase you might come across when optimizing websites is “combine and compress.” This refers to the practice of combining multiple JavaScript or CSS files into one, and compressing those files – either by removing white space and comments or by using a server-side compression technology, or both.

If you use Firebug with YSlow or Google Page Speed, you’ve probably seen it recommend minifying your external JavaScript files and reducing the number of HTTP requests.  The minification recommendation is the “compress” part – in this case, referring to removing whitespace and comments. Since a smaller file size means less data going from your server to your users, it’s easy to see how this speeds up page loading time.

Reducing HTTP requests refers to the “combine” part.  Let’s say you have three javascript files – jQuery, a jQuery plug-in, and a big file containing all your jQuery functions. You are loading each script into your page via a <script> tag. Every time the browser hits one of those <script> tags, it sends a request to the server and waits for a response. If you can reduce the number of times the browser needs to talk to the server, you reduce time and overhead, meaning your pages will load faster.

If you were to combine your three separate JavaScript files into a single script, and use a minification tool on this combined script, you would save both on file size and on requests to the server.

I’ve been doing this manually, especially when working with jQuery plug-ins.  On each project, I often have a file called project.common.js which I include just before the closing <body> tag.  In project.common.js, I include not only my site-wide scripts, but also all the code for the plug-ins these scripts depend on.

For instance, instead of this:

<script type=”text/javascript” src=”js/jquery.form.js” />
<script type=”text/javascript” src=”js/jquery.validate.js” />
<script type=”text/javascript” src=”js/myproject.common.js” />

I’ll simply copy and paste the code for the plug-ins into myproject.common.js so that I only have to include one instead of three scripts. When I’m ready to go to production, I’ll run Page Speed and have it create a minified version of this combined file, then upload that to the server and point my page at it.

While this works, it’s also rather tedious, especially when you have to go back into your common.js file and make changes.  Human nature being what it is, this means that, often, the modified file is simply not re-compressed – either because I was lazy, or because  I got distracted by another project, or because I had to hand the project on to another developer who didn’t think to re-compress it, or for any of a million other reasons.  When you’re working under deadline, you often find yourself operating under the rules of “if it ain’t broke, don’t fix it,” meaning that optimization often simply doesn’t happen.

What

My solution has been to write a PHP class called jsFold that will handle this for you. Currently I am using it just for JS, but it could be easily modified for use with CSS files as well. 

The php class itself is hosted on this github repository.

Here is an example of the final implementation:

<?php
function __autoload($class_name) {
	require_once('classes/class.'.$class_name.'.php');
}

$jsfold = new jsFold();
$jsfold->fold('/wamp/www/jsfold/js/separate/','/wamp/www/jsfold/js/','combined.js');
?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>jsFold Example</title>
</head>

<body>

<a href="#" id="lnk">Click me</a>

<script type="text/javascript" src="js/combined.js"></script>
</body>
</html>

And here is a screenshot of how I set up the file structure:

file system screenshot

How

Lines 2-4 set up the PHP autoload feature.

In line 6 we initialize the jsfold class, and in line 7 we execute it. Note that it takes three required arguments:

  1. The source directory
  2. The destination directory
  3. The name of the new, combined file

The script combines all files in the source directory into a single script, minifies this (using this script, by Ryan Grove), then places it in the location specified by the destination directory (the second argument), under the name specified in the third argument.

Since it would be a needless use of server resources to do this each time the page loads, all of this happens only if the combined file does not already exist.  So whenever you update any of the individual scripts, you’ll need to delete the combined script.

UPDATE

Just came across this: minify. Looks like a more robust version of what I wrote above. Haven’t tried it out yet, so not sure how it compares to my simpler script, but thought it worth pointing out.

No responses yet

jQuery optimization: Keep DOM manipulation outside of your loops

May 05 2010

If you’ve done any research at all into JavaScript optimization, I’m sure you’ve come across this before, but I’m going to post on this anyway.

One of the biggest performance hits when doing things in JS is DOM manipulation – that is, any time you insert, remove, or modify the HTML mark-up.  When optimizing your code, then, one obvious step is to reduce the amount of times you interact with the DOM.

The easiest place to do this is within loops.  Take a look at the following code, from a recent project I re-factored:

$('div.ajaxload').each(function(index) {
 var id = 'windowContent-'+index;

 $('#windowDisplay').append('<div id="'+id+'"> </div>');

});

In this code, we’re looping through all of the DIVs with a class of “ajaxload” and appending a new div to the element with the ID “windowDisplay.”

After re-factoring, the same code snippet looks like this:

var preloadedContent = '';

$('.ajaxload').each(function(index) {
 var id = 'windowContent-'+index;

 preloadedContent += '<div id="'+id+'" rel="'+toLoad+'" index="'+cnt+'"> </div>';
});

$('#windowDisplay').append(preloadedContent);

Now we have a variable called “preloadedContent”, and on each loop we concatenate (a fancy word for “add to”) the markup for the new div.  Once we’re done, we do our append, but crucially, we do this outside of the loop.

The difference is that we do one DOM insertion, instead of inserting into the DOM each time we run through the loop.

No responses yet