Today one of my college has approached me saying that the form submission extension i created for Radiant CMS is not working any more. It used to be able to validate the form before submitting the form. However, in IE8 and below, the validation is gone. In Firefox and Google Chrome and IE 9, it is working fine.

I open the IE developer tools and found the javascript error message:

Unexpected call to method or property access

The error messages points to one line of the javascript in jQuery. However, it is unlikely that jquery libary itselves contains errors. So I remove all other javascripts files and leave with jquery and the error message is gone. This confirms that jquery has no problem. So I start to adding one javascript at a time, and realize that when adding one of the javascript the error message appears. And in the end it turns out that the following javascript line is causing problem.

$('.button2').append('');

The button2 class name is added to form submission input button.

Actually appending some html to input tag doesn’t make any sense as input tag should not contain any inner html. And IE is complaining that it doesn’t have the property. The only solution is not to use append for input tag.

In jQuery, if you want to observe an event on certain element, you can choose to use .bind() or .live().

$('#page_title').bind('click', function(){
     $(this).html('you clicked me');
});

Alternatively, you can write the above using shortcut:

$('#page_title').click(function(){
     $(this).html('you clicked me');
});

However, the first format allows you to bind multiple events to the same element with same call back method.

$('#page_title').bind('mouseover mouseout', function(){
     $(this).html('you didn't me');
});

In jQuery, you can also use .live() method.

$('#page_title').live('click', function(){
     $(this).html('you clicked me');
});

According to jQuery doc, .live() attaches a handler to the event for all elements which match the current selector, now or in the future. The difference lies in the word in the future. You could attach a handler to the event for the element even the element doesn’t exist! So you could run the following code before the document is fully loaded.

$('#page_title').live('click', function(){
     $(this).html('you clicked me');
});

However, if you use .bind() method, you must make sure that the document element already exists before you observe it. Otherwise, the event handler won’t be triggered. This is especially useful when you are using Ajax in your website. You could observe the element before the Ajax loads. So you don’t have to rebind the event to the element everytime Ajax finished loading.E.g, normally you will do this :

$.ajax({
   type: "POST",
   url: "some.php",
   data: "name=John&location=Boston",
   success: function(msg){
     $('#page_title').live('click', function(){
          $(this).html("you clicked me");
    });
   }
 });

This is very troublesome and every time you have to reattach those event handlers to the event on the elements. So what you could is adding the event observer even before you add the Ajax:

$('#page_title').live('click', function(){
          $(this).html("you clicked me");
}); 

$.ajax({
   type: "POST",
   url: "some.php",
   data: "name=John&location=Boston",
   success: function(msg){
       //...anything here
   }
 });

But do you find any problem with the above code?

$.ajax({
   type: "POST",
   url: "some.php",
   data: "name=John&location=Boston",
   success: function(msg){
     $('#page_title').live('click', function(){
          $(this).html("you clicked me");
    });
   }
 });

Yes, you shouldn’t use .live(), you should use .bind() instead. If you use .live() here, then every time the Ajax finished loading, the element will add a event handler, although they are the same functionality but different reference. So the Ajax loads twice, you click on the ‘page_title’, it should alert twice.

So remember to use .live() on the same element once only.
Read the rest of this entry »

I wrote an article previously “IE6: Object doesn’t support this property or method”. Now this time I met an issue more or less like this but in different format. So here we go.

Firstly, let’s look at the following code snippet.

$(document).ready(function(){
    page_title = $('#page_title');
    page_title.html("updated_title");
});

If you run the above code in Firefox or chrome, everything is fine, the html element with id ‘page_title’ will be updated to ‘updated_title’. However, if you run the above code in IE, then you will see an error ‘Object Doesn’t Support this property or Method’. Remember last time I said in IE, you can’t name a javascript function the same as a HTML element ID? This is the same case, you can’t name the javascript global variables the same as a HTML element ID. If you change the above code to the following, then it should work.

$(document).ready(function(){
    var page_title = $('#page_title');
    var page_title.html("updated_title");
});

Of course, using global variable at this circumstance is always a bad idea. You should try to avoid using javascript global variables which may cause naming conflicts and make your scripts buggy.

So the real reason behind this is that in IE, it create a global object that matches every DOM element based on their ID. And it turns out that this global object is unable to be reassigned. Somewhat protected. Here is how you can prove that these global object really exists in IE.

$(document).ready(function(){
    alert(page_title.id);
});

Of course, you should have a HTML element with ID ‘page_title’. Then you should be seeing ‘page_title’ pop up in IE while in firefox it complains that page_title is undefined.

So try avoid using element ID as global variables / function names in your javascript.

Read the rest of this entry »

Recently I have done a project using prototype. However, the performance of jQuery seems much faster than prototype although the difference is not very huge. (check out Dojo vs JQuery vs MooTools vs Prototype Performance Comparison) The other reason is that jQuery community is so huge that more solutions to a problem can be easily found. So I listed out some comparison in methods between prototype and jQuery.

compare prototype and jQuery

prototype method jQuery method comments
$('manager') $('#manager') Prototype $(selector), selector default is the id of the element
$$('#manager') $('#manager') prototype $$ returns an array of prototype element. jQuery $() selector returns a jQuery object reference those matching elements
new Element('input', {'class': 'digit'}) $("< input class='digit' >")  
$('manager').removeClassName('red'); $('#manager').removeClass('red')  
$('manager').addClassName('red'); $('#manager').addClass('red')  
$$('#manager').invoke('addClassName', 'red'); $('#manager').addClass('red') jQuery will automatically apply the method to all the matching elements
$$('#manager').each(function(ele){ele.addClassName('red')}) $('#manager').addClass('red') You don't have to iterate through an array for jQuery
$('manager').observe('click', function(){alert('clicked')}) $('#manager').click(function(){alert('clicked')});  
$$('#manager').each(function(ele){alert(ele.readAttribute('id')}) $.each($('#manager'), function(){alert($(this).attr('id')}) In jQuery earch iterator, the 'this' always refers to the DOM element, in order to use jQuery object method, you should add the jQuery wraper around 'this'
$('manager').readAttribute('name') $('#manager').attr('name')  
$('manager').update("the name") $('#manager').html("the name")  
$('manager').down('div'); $('#manager').find('div')  
$('manager').up('div'); $('#manager').parents('div') In jQuery, .parent() only travels one level up the DOM tree, however parents() will travels all the way up to DOM root

Most of the time, when you are using Ajax, you need to do some interaction between the javascript and html. For example, you have a list of entries in a table, each row of a table represents some information(buy, sell volume, last done price etc) relating to a stock. When user click on a row, you want to trigger an Ajax request to retrieve some more information about this stock and displayed as a pop up. So the question now is how do you know what is the stock code on the row that the user has clicked? There are a few options for you to do so:

1. Put the data in the id attribute.

Whenever the link or a tag is clicked, you retrieve the id of the tag, and send the id along with the Ajax request. This is easier to achieve, however, sometimes you only wants to use a fix id for the tag, which is easier for you to retrieve the element later by directly passing the id to the jQuery selector. Then you have a problem, and the best practice is to try best to avoid using duplicate id for different tags. If the data you want to save is the same for some tags, then probably, this is not the best solutions as well.

2. Put the data in the arbitrary attribute

When I say arbitrary attribute, it means that you can define your own attribute and put it in the html tag. e.g.

Straight Times Index

The code here in the a tag is an arbitrary attribute. With this, you can put any kind of data in any tag. On the other hand, it makes the data meaningful as well. Then, using javascript readAttribute method, you can easily retrieve the data. However, there are some problems with this as well. The problem is that this breaks the HTML standard, most of browsers will simply ignores this arbitrary attribute if it is not defined as a standard attribute for the tag. If you use firefox to validate the html page according to W3C, you will fail in the validation.

One thing to note is that, in HTML5, it is valid to put your custom attributes but must be prefixed with data-.e.g

click me

But this may only be viable when HTML5 becomes a universal standard.

3. Put the data in class attribute

This method may not seems elegant to some purists, however, it is universally supported and standard compliant. You can define you own syntax rules in the class name attribute.e.g.

In the above example, I define the rule as data-your_data. The class names should start with data, anything that follows in this class name is the data. Then you can easily use javascript to read the class name and extract the data out. However, if you are using Jquery, the plugin metadata maybe your choice. This plugin allows you to define some data in json format in the html tag.

  • ...
  • With the above html, you can simply do the following:

    var data = $('li.someclass').metadata();
    if ( data.some && data.some == 'data' )
        alert('It Worked!');
    4. Put your data in another tag

    You may want to wrap the html tag with a tag which contains the data, but with style “display:none”. e.g.

    {"id" : 1, "name" : "shanison"}click me

    However, I personally don’t like this solutions. It makes the html contents messy.

    Read the rest of this entry »