IE Performance Issues Adding Dom Nodes

October 12, 2009

My app has a search screen that fetches the results via Ajax and displays them in a table. Worked fine in Firefox, but in IE there’s a slight processor jump for a second or so. Strange, but not a problem. The users of this app, however, use a remote desktop app to run IE to access it. And when they did the search, their CPU would hit 100% for 1-5 minutes, making the entire terminal completely unusable.

I agonized over different JavaScript fixes: removed a table JS widget, switched off of tables altogether, switched to innerHTML, used DocumentFragments. Nothing worked.

Then, on a whim, I disabled all the CSS files on the app, and it worked like a charm. As I narrowed it down, I discovered that some CSS I was using to emulate frames (non-scrolling header, footer, and sidebar) was the offending code.

Let’s step back and think about that one again. What caused the processor to hit 100% for 5 minutes was not JavaScript, but CSS.

Sigh. So, if you have an issue with IE hitting 100% processor load for any reason, don’t assume that JS is necessarily the problem. Try disabling your CSS and see if that fixes it.


Disable Form Field, Preserving Submit

August 25, 2009

The “disabled” attribute on an HTML form element prevents the field from being edited. Unfortunately, it also prevents the field from being submitted in the form. If you do need to submit the field even though it’s disabled, use the following instead of the disabled attribute:

this.event.addListener( field, “click”, function(e)
{
var targ;
if (e.target) targ = e.target;
else if (e.srcElement) targ = e.srcElement;
if (targ.nodeType == 3) // defeat Safari bug
targ = targ.parentNode;
targ.blur();
});

YAHOO.util.Event.addListener( field, “click”, function(e)

{

var targ;

if (e.target) targ = e.target;

else if (e.srcElement) targ = e.srcElement;

if (targ.nodeType == 3) // defeat Safari bug

targ = targ.parentNode;

targ.blur();

});

This will blur (deselect) the field as soon as you select it. Combine it with some gray styling and you’ve got a great form disabler.


JS Auto-Tab That Doesn’t Suck

July 7, 2009

Here’s a JavaScript auto-tab implementation that doesn’t have that most annoying of bugs: when you click or tab into a field that is already populated, it tabs to the next field, disallowing you from deleting or changing. This one only auto-tabs on keyup.

UPDATE: dag nabbit, I was wrong. Shift-tabbing back to the previous field doesn’t work right in Firefox. On the “var filter” line, add a 16 into the [0,8,9] list, making it [0,8,9,16], and you should be set.


Top Reasons Your YUI Widget Looks Messed Up

June 12, 2009
  1. You created the widget but didn’t call its render() method. When you create it, that seems to update some styles and DOM elements, but not all. Calling render() updates the rest.
  2. You tried to apply the widget to multiple elements, but, since they have the same ID, it was applied to the same element multiple times. This is like the Ghostbusters crossing the streams, and is very bad.

IE6 JavaScript error: “Expected identifier, string, or number”

May 20, 2009

Note to self: if your code works in FF, but  you get the “Expected identifier, string, or number” error in IE6, this is probably caused by having a list with a comma after the last item. Remove the extraneous comma, and it should work.


Submit Buttons and Ajax

April 10, 2009

We’re writing an Ajax webapp with progressive enhancement. In other words, if JavaScript is disabled, it should work – but if JavaScript is enabled, it should work better. As a general pattern, then, all of the buttons in our app are submit buttons that execute server-side behavior. When the page loads, we attach click event listeners to the buttons, to call the appropriate JavaScript methods.

By default, though, the submit buttons still try to submit the form. But we need to disable that, so that only the Ajax call happens. The first solution I tried was:

document.getElementById("myform").onsubmit=function(){return false;};

This disabled form submission altogether, which worked just fine.

The problem arose when we had a form that had to have some submit buttons work, but not all. It’s a shopping cart page, and we want “Checkout” to still submit the form and go to the checkout page; but we want the “Remove” buttons to execute Ajax calls to remove elements. They’re all in the same form, because, for example, if the user updates a quantity for one product, then removes another product, they expect the quantity change to be saved as well. So one big form.

The best solution I found for this was to actually create a new button-button, and use it to replace the submit button. At first, this seemed a bit clunky. But the problem is that the submit button wants to submit the form, and I was having trouble finding a way to prevent it from submitting. Rather than messing with its internals, it’s cleaner to create a button-button, that doesn’t want to submit.


JavaScript Documentation Recommendations

March 19, 2009

For the project I’m currently working on, here are some best practices I’m using for JavaScript documentation:

  • Use YUI Doc syntax. Even if I never actually run YUI Doc, it’s a standardized comment format.
  • At the top of every JS source file, put a multi-line comment, with the first line starting with the source file name. I combine my JS files in the build process, so this allows me to easily find out which source file a particular line of code is from. I even add these headers to JS library files I use.
  • In that file header comment, add an @global directive that lists all the global variables the file creates. Ideally, each of your files would correspond to an @module, and you wouldn’t create any global variables other than classes in that module; and any instances you create would be inside anonymous closures. But some JS libraries you use may create global variables (DWR, for example), and it’s helpful to document the variables they create.

YUI Logger Bookmarklet

March 19, 2009

So you’re using YUI Logger in your webapp, and loving it. One problem: how do you hide the console for production, but show it in development? You can have separate build targets, but what if you want to deploy the same package in all your environments?

One option is to use this bookmarklet to load YUI Logger. In other words, just load your page, then run the bookmarklet to load the logger.

One of the upsides of that bookmarklet is that it uses YUI Loader to load the logger code dynamically, so that you don’t have to include the logger code in your production side. The bookmarklet doesn’t work if you don’t have YUI Loader included on your page. For me, though, this was a problem. I don’t use YUI Loader – instead, I combine all my JavaScript library code into a single JS file that’s downloaded once, so that can be cached. And when I looked at the YUI Loader code, it’s actually larger than the YUI Logger code!

So, as an alternative, here’s a bookmarklet that will start a YUI Logger console, assuming you already have the logger code loaded into your page. Bookmark it, or drag it to your toolbar or bookmarks folder.

YUI Log

Note: as far as I can tell, your log statements are recorded even before the console is displayed, so if you have code that executes on page load, its log statements will still appear in the console when you use the bookmarklet after page load.


YUI Calendar Changes Dates

October 21, 2008

My Ajax app has a persistent date it keeps track of, to compare other dates against. But I ran into a problem where the date was somehow being changed – from 12am on a certain day to 12pm. I looked through my code, and I wasn’t even changing it anywhere.

Finally, I noticed I was passing the date into a YUI Calendar object, to specify what was the minimum allowable selectable date. JavaScript Date objects are mutable, so I realized it was possible YUI was changing the hour value on the date. Sure enough, when I changed the code to pass YUI a copy of the Date instead, the date’s hour was no longer changed.

I’m still not entirely sure why YUI would need to change the Date, or if it’s even good design for it to do so instead of creating a copy of the Date object. Nonetheless, lesson learned: if you want to make sure an object you’re passing somewhere is unchanged, make a copy before you pass it. This smacks of a general OO principle, but for some reason I haven’t run across this problem in the Java world before.


IE6 setAttribute “onclick” not working

October 16, 2008

OK, I don’t have time to fully test this one, but when I dynamically create DOM nodes in a YUI panel, and then create an anchor tag and add an onclick handler to it (no HREF) by using setAttribute, IE6 doesn’t register the click event. It seems that I need to use another event attaching method, like YUI Event addListener() – that works fine in both IE and FF.