Archive for category JavaScript

Programatically fire crossbrowser click event with JavaScript

The following function triggers a mouseclick event on the DOM-node you pass to it.
I’ve tested it with Internet Explorer 6, 7, 8 and 9, Firefox 3.x and 11 nightly. Chrome 17-dev, Opera 10 and 11, webkit on iOS 5 iPhone 4, webkit on Android 2.3.4, Safari 4.0.5 on Windows. If you need it on another browser/version/os, please test it and post the result as a comment here.

function fireClick(node){
	if ( document.createEvent ) {
		var evt = document.createEvent('MouseEvents');
		evt.initEvent('click', true, false);
		node.dispatchEvent(evt);	
	} else if( document.createEventObject ) {
		node.fireEvent('onclick') ;	
	} else if (typeof node.onclick == 'function' ) {
		node.onclick();	
	}
}

Example usage:

//assumes <a href="http://www.nonobtrusive.com" id="myLink">Click me</a>
var theNode = document.getElementById('myLink');
theNode.onclick = function(){ alert("You clicked a link with href:" + this.href); };
fireClick(theNode);

26 Comments

Lightweight JSONP javascript library

This can now be found at github: https://github.com/IntoMethod/Lightweight-JSONP

Are you one of those that include jQuery or any other library only to be able to use some JSONP in your website? In that case this might be the code for you to read and try to understand. I won’t post any detailed explainations right now but feel free to comment if you wonder anything. I’ve also included a minified version in the bottom.

Update (2012-04-10) Fixed issues/suggestions found by Zach, Gabriel and Pamela (see comments). These updates and fixes can be found on github

Update (2011-06-08) Fixed delete/setting to null as pointed out by Bryan Smith (see comment)

Update (2011-04-29) Added encodeURIComponent as suggested by yched (see comment)

Update: Fixed scoping problem as found by Damon Oehlman (see comment)

Feel free to use this script for anything that you like, commercial or non-commercial, but please keep the comment and link to this site.

Oh and by the way, the script has been tested successfully in the following browsers:
Chrome 4,5,6
Firefox 3.x
Internet Explorer 6,7,8
Opera 9.6+10
Androids webkit-based browser
Symbian S60 browser

First an example of how to use it, to show the simplicity, then the actual code.

JSONP.get( 'someUrl.php', {param1:'123', param2:'456'}, function(data){
        //do something with data, which is the JSON object you output from someUrl.php
        //into the callback javascript method specified by the "callback" value in the querystring
});

A simple example of the someUrl.php (please observe this example does not include any security checks what so ever, just to show the principle):

$myData = fetchSomeData();
 
echo $_GET['callback'];
echo "(";
echo json_encode($myData);
echo ")";

See github link above for current code and examples, the code below is old

The actual code for the Lightweight JSONP functionality.
Around 1.1kb without gzip.

//Lightweight JSONP fetcher - www.nonobtrusive.com
var JSONP = (function(){
	var counter = 0, head, query, key, window = this;
	function load(url) {
		var script = document.createElement('script'),
			done = false;
		script.src = url;
		script.async = true;
 
		script.onload = script.onreadystatechange = function() {
			if ( !done && (!this.readyState || this.readyState === "loaded" || this.readyState === "complete") ) {
				done = true;
				script.onload = script.onreadystatechange = null;
				if ( script && script.parentNode ) {
					script.parentNode.removeChild( script );
				}
			}
		};
		if ( !head ) {
			head = document.getElementsByTagName('head')[0];
		}
		head.appendChild( script );
	}
	function jsonp(url, params, callback) {
		query = "?";
		params = params || {};
		for ( key in params ) {
			if ( params.hasOwnProperty(key) ) {
				query += encodeURIComponent(key) + "=" + encodeURIComponent(params[key]) + "&";
			}
		}
		var jsonp = "json" + (++counter);
		window[ jsonp ] = function(data){
			callback(data);
			try {
				delete window[ jsonp ];
			} catch (e) {}
			window[ jsonp ] = null;
		};
 
		load(url + query + "callback=" + jsonp);
		return jsonp;
	}
	return {
		get:jsonp
	};
}());

, ,

46 Comments

Array clone in javascript ?

There’s no such thing unfortunately, but it’s easy to replicate the same behaviour since we’ve got a handy cross-browser method called slice.
So what does the slice method do ? It allows up to two parameters to be passed in, start index and end index. If none are sent in the slice method will return a COPY of the original array, which allows us to use it as if it were a clone method. If only the first parameter is specified it will assume the full length of the array as secondary parameter. Not specifying a value will as earlier mentioned behave the same as this:

var copiedArray = theArray.slice( 0, theArray.length );
 
//this results in the same
var copiedArray = theArray.slice();

Examples:

var sourceArray = [1,2,3,4,5],
     clonedArray = sourceArray.slice();
 
alert(sourceArray.slice(1));  //will return & alert a copied array with the values 2,3,4,5 at indexes 1,2,3,4
 
alert(sourceArray.slice(1,2));  //will return & alert a copied array with the value 2 at index 0
 
sourceArray = sourceArray.slice(1,4);  //sourceArray will now contain 2,3,4
 
alert(clonedArray);  //will still alert 1,2,3,4,5 since it's a copy of the original array and not a reference.

1 Comment

“Keeping” calling-context with setTimeout/setInterval

The javascript setTimeout function allows to pass some code or function to be called after a specifiec timeout in milliseconds. But since the callback is handled by the Window object it’ll loose the “this” from whatever it was called from. There’s two possible solutions to this, the first and most common is to use something like

var self = this;
setTimeout( function(){
     self.someValue = ........;
     self.someFunction();
     etc....
}, 500 );

But one other option is to execute the anonymous function which then returns another function as the code below shows.

function Foo(){
	setTimeout( (function(self){
		return function(){
			alert(this);	//Window
			alert(self);	//Foo
		}
	})(this), 2500 );
}
Foo.prototype.toString = function(){
	return "[object Foo]";
}
new Foo();

, ,

No Comments

Just a general note, you can’t delete everything

I’ve had this discussion a couple of times now with several people and maybe It’s about time to make a post for it here 🙂

The delete operator in ECMAScript-262 can only be used to delete dynamically created variables/properties. Having that said heres a code sample:

var foo = "test"; //executing this in the global window-scope will actually create window.foo and it's being considered as a  dynamically created property on the window object.
delete foo;  //will return true, success
alert(foo); //throws a javascript exception since foo is deleted, thus being undefined

On the other hand…

(function(){
var foo ="test";  //local to the anonymous function, could as well be in a named function.
delete foo;  //will return false, failure to delete
alert(foo);  //will alert "test", delete had no affect
})();

1 Comment

Dispatcher followup : A more compact way of writing prototypes + module pattern + test

The previous post I added some prototype methods to the Dispatcher class, but It could has well been written on the following syntax instead

function Dispatcher(){}
Dispatcher.prototype = {
     addEventlistener : function(event, callback){
        //code here
     },
     removeEventlistener : function(event, callback){
        //code here
     }
     //add more methods here... don't forget to comma-separate them and do not add a comma last!
}

So how about writing up this with the module pattern on the same time. I’ll also show a simple way to write an automatic unit-alike test for this.

/**
* @author: Erik Karlsson, www.nonobtrusive.com
**/
var nonobtrusive = nonobtrusive ||{}; //create the "namespace" like object if it doesnt exist
nonobtrusive.events = nonobtrusive.events || {}; //create the sub-namespace events where we'll place our Dispatcher class
nonobtrusive.events.Dispatcher = (function(){
	var undefined; //speed up references to undefined + allows munging
    function Dispatcher(){
         this.events=[];
    }
    Dispatcher.prototype = {
		addEventlistener : function(event, callback){
			if ( event == undefined || callback == undefined ) return false;	//verify that we have parameters sent in
			var listeners = this.events[event] = this.events[event] || [];		//create a new array to hold listeners if first time
			listeners[listeners.length]=callback;
		},
		removeEventlistener : function(event, callback){
			if ( event == undefined || callback == undefined ) return false;	//verify that we have parameters sent in
			var listeners = this.events[event];
			if ( listeners ) {
				for ( var i = listeners.length-1; i>=0; --i ){	//go through all listeners for this specific event
					if ( listeners[i] === callback ) {
						listeners.splice( i, 1 );	//remove the eventcallback if we found it
						return true;
					}
				}
			}
			return false;
		},
		dispatch : function(event){
			if ( event == undefined ) return false;
			if ( this.events[event] ) {
				var listeners = this.events[event], len = listeners.length;
				while ( len-- ) {
					listeners[len](this);	//callback with self
				}		
			}
		}
		//add more methods here... don't forget to comma-separate them and do not add a comma last!
   }
 
   return Dispatcher;
})();
 
 
function DispatcherTest(){
	nonobtrusive.events.Dispatcher.call(this);
 
	//Some internal variables to keep track of the test-process.
	var	dispatchOk = false,
		afterRemovalOk = false;
 
	this.dispatchCallback = function(){
		dispatchOk = !dispatchOk;
	}
 
	this.setup = function(){
		this.addEventlistener("TestEvent", this.dispatchCallback);
	}
 
	this.run = function(){
		this.dispatch("TestEvent");
		afterRemovalOk = this.removeEventlistener("TestEvent", this.dispatchCallback);
		this.dispatch("TestEvent");	//nothing should happen since we're not listening to this event anymore.
		if ( dispatchOk && afterRemovalOk ) {
			alert("DispatcherTest was ok!");
		}
	}
}
DispatcherTest.prototype = new nonobtrusive.events.Dispatcher();
 
//Run the test
var test = new DispatcherTest();
test.setup();
test.run();

If you want to use this class, download the minified script here :
http://www.nonobtrusive.com/wp-content/uploads/2009/07/nonobtrusive.events.Dispatcher-min.js
or try out the test yourself by visiting this page :
http://www.nonobtrusive.com/wp-content/uploads/2009/07/dispatcher-test.html

, , , , ,

1 Comment

Custom events in javascript by making your own Dispatcher class.

Don’t have the time to comment the code and explain right now, but I will update the post later on 🙂
I wrote this in about 2minutes to help out a guy just before going to bed so I’ve only tested the addEventListener and dispatch functionality (not removeEventListener), but it actually worked in IE7, IE8, Firefox 3.5, Chrome2 and Stainless (Webkit based browser under osx) on the first try.

Feel free to comment if you find this useful

/**
* @author Erik Karlsson, www.nonobtrusive.com
*/
function Dispatcher(){
	this.events=[];
}
Dispatcher.prototype.addEventlistener=function(event,callback){
	this.events[event] = this.events[event] || [];
	if ( this.events[event] ) {
		this.events[event].push(callback);
	}
}
Dispatcher.prototype.removeEventlistener=function(event,callback){
	if ( this.events[event] ) {
		var listeners = this.events[event];
		for ( var i = listeners.length-1; i>=0; --i ){
			if ( listeners[i] === callback ) {
				listeners.splice( i, 1 );
				return true;
			}
		}
	}
	return false;
}
Dispatcher.prototype.dispatch=function(event){
	if ( this.events[event] ) {
		var listeners = this.events[event], len = listeners.length;
		while ( len-- ) {
			listeners[len](this);	//callback with self
		}		
	}
}
 
 
/** Below is some test-code to verify the most basic functionality **/
function SomeClass(){
	Dispatcher.call(this);
}
SomeClass.prototype = new Dispatcher();
 
SomeClass.prototype.sendSomeEvent=function(){
	this.dispatch("test");
}
 
var foo = new SomeClass();
foo.addEventlistener( "test", function(){ alert("bah"); } )
foo.sendSomeEvent();

, ,

17 Comments

Count the number of javascript eventhandlers in the DOM-tree.

Sometimes I’ve wanted to find out how many eventhandlers there are attached to the DOM-tree I’m working with, but I’ve never found a good tool for doing this. I decided to write a simple javascript snippet that traverses the tree and finds the fact for me and it looks like its working pretty good too.

Please don’t hesitate to comment if you find this useful or have any improvement suggestions

/**
* @author Erik Karlsson, www.nonobtrusive.com
**/
function countEventHandlers(){
 
var elements = document.getElementsByTagName("*"), len = elements.length,
     counter = 0,
     countermap = [],
     /* fill up with more events if needed or just use those you want to look for */
     events = ['onmousedown', 'onmouseup', 'onmouseover', 'onmouseout', 
                   'onclick', 'onmousemove', 'ondblclick', 'onerror', 'onresize', 'onscroll',
                   'onkeydown', 'onkeyup', 'onkeypress', 'onchange', 'onsubmit'], 
     eventlen = events.length;
 
for ( var i = eventlen-1; i >= 0; --i ) {
    countermap[events[i]] = 0;   //reset the map
}
 
 
while ( len-- ) {  //go through all DOM-nodes
    var element = elements[len],
        tmp = eventlen;
    while ( tmp-- ) {  //go through all events defined above for each node and see if it exists.
        if ( element[events[tmp]] ) {
            counter++;
            countermap[events[tmp]]++;
        }
    }    
}
 
var someStats = counter + " events found in total\n\n";
for ( var o in countermap ) {
   someStats += o + " was found " + countermap[o] + " times\n";
}
alert(someStats);
 
}

, , , , , ,

1 Comment

So you think you’re writing effiecent jQuery selectors?

Think again if you’re writing selectors such as

$("div#myId")

When selecting against the DOM ID the fastest way to get the node is to use only the id:

$("#myId") //will translate into document.getElementById("myId") internally

otherwise jQuery will first get all DIV-nodes then manually iterate over them looking for an attribute id that’s equal to “myId”. In a case with a large DOM-tree this could be a large performance-hit making your site unusable on slower computers if you’re using selectors like this everywhere.

On the other hand when selecting against CSS-classes it’s faster to use

$("div.myClass")

than just

$(".myClass")

,

2 Comments

How to get the amount of days in an arbitrary month with leapyear in consideration

function daysInMonth( month, year ) {
       var now  = new Date();
       month = month || now.getMonth()+1; //this month as default
       year = year || now.getFullYear();    //this year as default
       return new Date(year, month, 0).getDate();
}
 
//consider January as month 1, February as month 2 ... December 12
 
daysInMonth( 2, 2003 ); //returns 28, not leap-year
daysInMonth( 2, 2004 ); //returns 29, leap-year
daysInMonth( 7, 2009 ); //returns 31
daysInMonth( ); //returns the amount of days in the current month

, , , ,

3 Comments