Javascript


16
Feb 12

HTML input placeholder handling with jQuery

There’s a million of small jQuery snippets which handle input placeholders (ie. the help/explanation text that’s shown until you actually write something in the field), and when HTML5 gets widespread, they’ll all be obsoleted.

But nevertheless, here’s another one.

this post is more for self reference, but if it’s useful to you, be my guest.


29
Jul 11

DOM text search/replace with jQuery

I recently did a quick hack to modify a bunch of text (phrases) on an already rendered HTML page. It was inconvenient to manually select single elements and modify the text – what I needed was a global search/replace.

Turns out it’s quite easy to build one, so I did. I created a jQuery plugin that can go through all text nodes inside an element, match them against a fixed string or a regular expression, and replace it. The replacement can be a fixed string, a regular expression replacement, or a result of a function. Functions can also be (ab)used to modify the element beyond just changing the text.

You can get the plugin from GitHub, and see it in action on JSFiddle. In case anyone cares, I’m releasing it to Public Domain. It should work across all browsers, although it can be quite slow on big, heavy pages with a lot of text.

Beyond quick hacks, this plugin is quite useful for things like page translation, simple A/B tests and other uses where you need to manipulate text based on its content, not the page structure.


25
Jun 11

Currying in Javascript

Javascript has somewhat strange scoping rules that can catch you unaware. Here’s a typical example:

function test() {
   for (var i = 0; i < 5; i++) {
        setTimeout(function() {
            console.log(i);
        }, 1000);
   }
}
test();

This prints “0 1 2 3 4“, each number after a second, right? Wrong. What it actually outputs is “5 5 5 5 5“. Why? Because the callback function keeps a reference to i, which gets incremented to 5 long before any of the calls are made.

This is unfortunate because setting up a callback from a loop is often used in Javascript. How to work around this? There are basically two methods.

The first is wrapping the callback setup within another anonymous function, and then passing the variable as a parameter, which will effectively copy it:

   for (var i = 0; i < 5; i++) {
        (function(i) {
            setTimeout(function() {
                console.log(i);
            }, 1000);
        })(i);
   }

It works, but is rather ugly.

The second way is to add a parameter to the callback, and then curry the parameter, so it’s immediately bound and the value copied (thanks to @mreow for pointing it out). This achieves more or less the same effect as before, but is hopefully a bit more readable:

   for (var i = 0; i < 5; i++) {
        setTimeout((function(n) {
            console.log(n);
        }).bind(undefined, i), 1000);
   }

Hm. Right. Not much more readable. But, we can improve on it by creating a helper method (which will, presumably, be useful beyond this one case, so the added complexity is worth it):

function curry(val, fn) { return fn.bind(undefined, val); }
function test() {
   for (var i = 0; i < 5; i++) {
        setTimeout(curry(i, function(n) {
            console.log(n);
        }), 1000);
   }
}
test();

Now, that’s hopefully a bit cleaner. The curry function binds the value as the first parameter (the undefined there is because we don’t bind it to an object – see the bind documentation for details).

Currying is probably confusing at first sight, so here’s another example:

function curry(val, fn) { return fn.bind(undefined, val); }
function plus(a, b) { console.log(a + b); }
var plus2 = curry(2, plus);
plus2(3);

We first create a function that adds two numbers. Then, we curry that function binding value of “2″ as the first argument, and get another function, “plus2″. Then, we can call that function providing only the second argument. The end result is “5″.