Filtered by JavaScript

Page 18

Reset

Javascript tip: nifty use of the console.log function in Firebug

November 7, 2010
2 comments JavaScript

A classic blunder in Javascript client side apps is heavy use of the incredibly useful Firebug feature that is console.log() and then forgetting to remove any such debugging and thus causing Javascript errors for people without Firebug. To remedy this use this little nifty function:


function log() {
  if (window.console && window.console.log)
  for (var i = 0, l = arguments.length; i < l; i++)
    console.log(arguments[i]);
}

That way you can do plenty of debugging and if you accidentally leave a logging line in your code it won't break anything even if they don't have Firebug installed/enabled. Also you can easily "annotate" your debugging by writing two things in one line. Like this:


function foo(bar) {
   log("bar is:", bar);
   return bar * 2;
}

Nasty JavaScript wart (or rather, don't take shortcuts)

October 18, 2010
0 comments JavaScript

I had a piece of code that looked like this:


function add_to_form(f, all_day) {
  console.log(all_day);
  if (all_day)
    $('input[name="all_day"]', f).val('1');
  else;
    $('input[name="all_day"]', f).val('');
  console.log($('input[name="all_day"]', f).val(''));
  return f; 
}

When I ran it, the console output was this:


true
(an empty string)

What had happened was that I had accidentally put a semi-colon after the else statement. Accidentally as in stumbled on the keyboard. I didn't spot it because semi-colons are so common in JavaScript that you sort of go blind to them.

The wart was that it didn't cause a syntax error. IMHO it should have because you'd expect there to always be something happening after the else.

So instead of using the shortcut notation for if statements I've decided to write it out in full instead:


function add_to_form(f, all_day) {
  if (all_day) {
     $('input[name="all_day"]', f).val('1');
  } else {
     $('input[name="all_day"]', f).val('');
  }
  return f; 
}

Optimizers like Google Closure will do a much better job optimizing the code than I ever will anyway.

In jQuery, using the :visible selector can be dangerous

September 14, 2010
0 comments JavaScript

In jQuery, using the :visible selector can be dangerous And by "dangerous" I mean super slow to the point of making your browser shake of over exhaustion.

I have a big fat table where on the left hand side of each row there's a little toggle to open up an initially hidden sub-table. And there are toggles for those sub-tables to open up further sub-tables. It might sound complicated but it works great. The code for each toggle looks something like this:


$('a.toggle-order-on').click(function() {
   var tbody_parent = $(this).parents('tbody');

   $('tr.printdisplay:hidden', tbody_parent).show();
   $('tr.outdoor-marketing:hidden', tbody_parent).show();
   $('tr.digital:hidden', tbody_parent).show();

   // expand the little table too
   $('a.toggle-printdisplay-on', tbody_parent).click();

   var td_parent = $(this).parents('td');
   $(this).hide();
   $('a.toggle-order-off:hidden', td_parent).show();

   return false;
});

Note the heavy use of the super useful :hidden selector which is basically a reversing wrapper on the :visisble selector

What I then needed was a way to open up every single row in the whole table with one click. Here was the code I wrote:


$('a.toggle-order-on:visible').trigger('click');

See? Makes sense does it?

Problem with this was that when the table was big sometimes clicking this would make my otherwise fast browser (Chrome or Firefox) stutter and sometimes stall or at worst the alert pop-up about "a script is slowing this page down" would appear.

So I started the Firebug Profiler and clicked a couple of times and collected some numbers. On average it took 3-4.5 seconds!! and about 20,000-35,000 calls to complete the full expansion. Yikes! About 90% of the time spent by jQuery was on the visisble() function.

Solution: Instead of using the click trigger I simply just called the .show() effect on all things manually without using any :visible or :hidden operators. Here's the new code:


$('tr.printdisplay').show();
$('tr.outdoor-marketing').show();
$('tr.digital').show();
$('tr.printdisplaydetail').show();

$('a.toggle-order-off').show();
$('a.toggle-order-on').hide();

$('a.toggle-printdisplay-off').show();
$('a.toggle-printdisplay-on').hide();

This time, with the profile again, I it took on average 0.2-0.3 seconds and required about 2000-4000 calls. HUGE difference.

So, remember that next time. Don't just re-use working code en mass if it's using a much of :visible or :hidden selectors somewhere in there.

Local NodeJS development environment with Nginx

September 1, 2010
0 comments JavaScript

I'm brand spanking new to the node.js web application development. The framework I'm currently using is express which seems OK. So I've got an app that consists of 1 static HTML file, a lot of Javscript/CSS/image resources and some express GET and POST views that return small snippets of HTML. All data will be loaded with AJAX to avoid having to use any HTML templating on first load. What's cool about this is that it's soo fast! Everything except the JSON data can be loaded from an Nginx server.

At the moment I've got a light static HTML page that loads about 240Kb of Javascript and CSS (jQuery UI is big) and a couple of bytes of JSON data pulled from Node. As a little anal perfectionism I put an Nginx server in front so that Node doesn't have to serve any of the static files. To get that you have to have a Nginx site enabled that looks like this:


server {
   root /home/peterbe/task-calendar/static;
   location / {
     if (-f $request_filename) {
         add_header X-Static hit;
         access_log   off;
     }
     if (!-f $request_filename) {
         proxy_pass http://127.0.0.1:8000; # where Node is running
         add_header X-Static miss;
     }
   }
}

I think much of the fun of working with this app is that it's a delight to see it load in the browser without any sluggishness or delay. Lovely!

Too much Python makes Peter a shit Javascript developer

March 13, 2009
0 comments JavaScript

This murdered a good half hour of my time splattered with lots of alert() statements to debug. Basically, in Firefox you can do this:


var word = "Peter";
alert(word[1]); // "e" in Firefox, undefined in IE

This is the wrong way to get to character in a string in Javascript. The correct way is to use charAt() like this:


var word = "Peter";
alert(word.charAt(1)); // "e" in Firefox and IE

I don't know about the other browsers but finally Crosstips.org now works in IE7 too. I haven't even looked at it in IE6 and don't intend to either.

To $('#foo p') or to $('p', $('#foo'))

February 24, 2009
2 comments JavaScript

For the performance interested jQuery users please check out this thread

For the impatient, read Stephens reply He benchmarked what I asked and concluded that $("p", $("#foo")) is much faster in jQuery 1.3.2. I've been coding this style in jQuery for all recent projects so I'm happy with this outcome.

UPDATE

John Resig himself joined in on the discussion and had this to say:

"You should always use $("#foo").find("p") in favor of $("p", $("#foo")) - the second one ends up executing $(...) 3 times total - only to arrive at the same result as doing $("#foo").find("p")."

UPDATE 2

Not only did John join in on the discussion but it also made him work on jQuery 1.3.3 (not yet released at the time of writing) so that it doesn't matter which format you use you get the same performance. See the benchmark here

Formatting numeric amounts in Javascript

January 16, 2009
1 comment JavaScript

Dear Lazyweb,

Is there a better method than this to format numeric amounts? Here's a solution I picked up from somewhere and slightly modified. It's heavily string based but passed the tests:


function format_amount(i) {
  if(isNaN(i)) { i = 0.00; }
  var minus = '';
  if(i < 0) { minus = '-'; }
  i = Math.abs(i);
  i = parseInt((i + .005) * 100);
  i = i / 100;
  s = new String(i);
  if(s.indexOf('.') < 0) { s += '.00'; }
  if(s.indexOf('.') == (s.length - 2)) { s += '0'; }
  s = minus + s;
  return s;
}

The "tests" are:


format_amount(100)       == "100.00";
format_amount(100.0)     == "100.00";
format_amount(100.05)    == "100.05";
format_amount(100.051)   == "100.05";
format_amount(-100)      == "-100.00";
format_amount(-100.0)    == "-100.00";
format_amount(-123.45)   == "-123.45";
format_amount(-123.450)  == "-123.45";

So functionally it's OK but I'm not sure it's the best way to do it.

Lesson learnt with creating DOM element with jQuery

April 4, 2008
6 comments JavaScript

This took me some seriously wasted time to figure out yesterday. What I was trying to do was to create a DOM element of tag type A and insert it into the DOM tree of my page. As I was coding along, everything was working just fine in Firefox but the damn thing wouldn't show up anywhere in IE 6. I debugged and debugged and tried all kinds of different approaches and I just couldn't work it out. Then Karl Rudd gave the right hint on the jQuery mailing list.

Basically, what I was doing was something like this:


var a = $("<a>").attr('href','#').click(somefunction);
$('#toolbar').append(a);

What was then so strange is now less surprising. When I changed the <a> to a <span> it actually worked but just looked wrong with the rest of the site I was working on. Here's the correct way of doing it:


var a = $("<a></a>").attr('href','#').click(somefunction);
$('#toolbar').append(a);

Notice the difference between <a> and <a></a>. The strange thing is that to reproduce this I created this test.html page but here I noticed that in IE 6 it won't let you add any elements that are enclosing ones that are written as singulars. That's really strange since in the same javascript as the above stuff I did a $("<div>") which was working fine. I'll have to get back to figuring out why that one worked nad the A one didn't.

input/textarea switcher with jQuery

January 11, 2008
2 comments JavaScript

Here's a very early version of a solution to a problem where you have an input box want to give the user the option to expand the box to a textarea if they want to enter more stuff such as multiple line content. Your implementation, when you attempt the same thing, might be differently but feel free to copy this as a good start for your own projects. The demo show how it works.

What was important for me in doing this was that I didn't want to get close to the XHTML at all since (in this particular case) it was generated from a widget mechanism and I wanted the expanding option a luxury only for those who bother with the full Javascript. The key solution for me was the ability to replace elements in the DOM tree and copy the attributes when going from input to textarea or the other way around.

Feedback welcomed. Bare in mind that this was a quick first attempt and that I haven't tested this on IE.