poeticcode

October 10, 2008

DHTML: removeChild or div.innerHTML?

Filed under: DHTML, javascript — S @ 12:15 am

I ended up with a strange issue today, a difference in behavior between IE and FF (tell me something new huh?).

I have some dom nodes and they are dynamically inserted into a popup div as needed. So, before they are inserted, I first need to clear the popup div itself. I was doming (made a typo for doing but thought this is appropriate as well, “doming”) like

div.innerHTML = ”;
// add the existing nodes by context

This worked in Firefox. In IE, it did work, but subsequent popups started not showing the inner nodes being added. So, I changed the above to

for(var i=div.childNodes.length-1;i>=0;i–) div.removeChild(div.childNodes[i]);
// add the existing nodes by context

And this started working. So, it looks like when div.innerHTML is set to blank, or may be some other value for that matter, the existing nodes in the div and their content is being cleared up by IE, while firefox doesn’t clear up the contained nodes.

October 7, 2008

JavaScript Associative Arrays (HashMaps) & Prototype.js & Object

Filed under: javascript — S @ 10:28 pm

Today I spent a lot of time figuring out what’s going on with the for loop over an Array. Finally realized what’s going on and hence this post.

In JavaScript, if you need to create associative arrays (hashmaps), then there are two ways to do it. Actually, there is only one way, but I will get to that in a minute.

var hmap = new Array();
hmap[0] = “hello”;
hmap[1] = “world”;

Here, the hmap array is used as a normal array.

var hmap = new Array();
hmap["abc"] = “hello”;
hmap["def"] = “world”;

is perfectly valid. Here, the hmap is used as an associative array. So far so good.

I had a bit of code where I loop through the keys of the hashmap and need to make use of both the keys and the values. So, the code was something like

for(var key in hmap) {
// do something with key and hmap[key]
}

I remember doing this several times in the past without any problem. But today, when using this pattern along with prototype.js, I ended up getting, in addition to the keys I put in, additional keys starting with “each”. Where the heck is this “each” and a whole bunch of other keys coming from? After a bit of digging I found Array @ prototypejs.org article that the prototype.js script actually adds several useful methods to the Array. And the right way to access the elements in the Array is to use the hmap.each method that enumerates all the elements. But in my case, I want both the key and value, so I couldn’t use this method.

After some more reading, I finally realized that it’s actually the Objects that are associative arrays in JavaScript. That means, rather than using Array for the hmap, I could simply use Object. So, by changing the code from

var hmap = new Array();

to

var hmap = new Object();

I could use the regular

for(var key in hmap) { /* do something with key and hmap[key] */ }

without any problem inspite of using prototype.js

Interesting how things could go wrong with prototype based languages, no pun intended.

February 23, 2008

Stack overflow at line: … in IE

Filed under: IE, javascript — S @ 4:35 pm

I recently came across a strange issue with IE. All of a sudden one of my pages started giving “Stack overflow at line: 0″ and I had no idea why that was happening. This didn’t happen in Firefox though. After a bit of searching, didn’t really come across any valid solution other than some microsoft support page talking about too many modal windows causing such an issue.

He is what I finally found with my page. I have the following code

<body onload="onload(event);">

In one flow, this dynamically generated page has the onload javascript function and that works fine. However, in another flow of the same page, the onload javascript function is not implemented. So, in case of IE, it looks like it’s ending up in recursive loop on itself and hence the stack overflow. Had I written the code to

<body onload="onloadfunc(event);">

then in the second flow, it would have simply thrown a regular javascript error that the function doesn’t exist. Hopefully now this mystery is solved for you!

January 30, 2008

Bringing A Marker To The Top

Filed under: DHTML, Maps, javascript — S @ 8:37 pm

In maps and charts, where there are several markers, there is a likelihood of a overlap depending on how dense the data is. In such cases, it would be good to be able to bring the marker that has been selected using the mouse to the top and display the details and push the rest of the neighboring points to the bottom. And then when a mouse is placed over one of those neighboring points, then the current point should go down and the other point should come up.

So, how to achieve this in HTML using Javascript? Below is a way to do this.

Say each marker is a div element. You can do the following. First have a depth variable.

var depth = 1001;

Now, have the following code for the div.

div.onmouseover = function(event) { div.style.zIndex = depth++; }

That’s it! What this does is, every time the mouse is placed over a div, it sets it’s depth to be one more than the current maximum depth ensuring that the element is the top-most element. Isn’t this simple and elegant?

January 18, 2008

User Input Sanitizing Before Using In Regular Expression

Filed under: Tech - Tips, javascript, perl, regular expressions — S @ 6:33 pm

Say you want to take the input from a user and filter any set of text (titles/descriptions) and show the reduced list to the user. Assuming the users are not sophisticated enough to write regular expressions, the requirement is simply to ensure that whatever the user typed in is available some where within the text.

A simple way to do this is just look for the exact substring and see if the index is greater than or equal to 0 (something like str.indexOf(input) >= 0).

Say, you want to return a match that is case-insensitive. Then the substring approach will not work. So, you need to jump to using regular expressions. In JavaScript, this would become,

var re = new RegExp(input,"i"); // the flag i indicates case insensitive
if(re.test(str)) { /* do-some-thing-here */ }

So far, so good. Now, what happens if the user types in some special characters that are typically used in regular expressions as some special control characters? For example,

‘(‘ and ‘)’ are used for grouping and variable capturing
‘[' and ']‘ are used for character set
‘{‘ and ‘}’ are used to indicate the cardinality
‘\’ is escape character
‘*’ is used to indicate 0 or more
‘+’ is used to indicate 1 or more
‘?’ is used to indicate 0 or 1

In this scenario, if someone types in a string with any of the above characters, then the above javascript will fail. So, in order to fix this, the user input string should be first fixed to make it a valid regular expression. This can be done using

var rere = new RegExp("[({[^$*+?\\\]})]","g"); /* you need 2 '\' s to mean 1 '\' and another '\' to treat ']' as special character instead of the characters ending bracket */
var reinput = input.replace(rere,"\\$1"); /* replace the special characters with a \ before them */
var re = new RegExp(reinput,"i");
if(re.test(str)) { ... }

Now if you are generating the above JavaScript code in perl, it gets a bit more complicated. Why? Because, ‘\’s are themselves have escape semantics. Also, $ symbol has special meaning in perl. So, for each ‘\’ above, it would be doubled and also, $ would be escaped as well.

Yes, it gets confusing, but it’s doable. You can see this in action at Flat Panel Plasma/LCD HDTVs. It contains a search box on the top of the image cloud and lets the user to input a string such as Panasonic, Samsung, Sony etc or even product numbers with special characters like TH-42PZ700U to find the corresponding product on the image.

December 20, 2007

JavaScript Performance Tuning

Most server-side programming languages have tools to do performance tuning on applications written in them. With the popularity of AJAX based applications and other rich-client HTML applications on the rise, more and more code is being written in JavaScript. So, how the heck do you go about troubleshooting performance issues for these type of client-side heavy applications written in JavaScript?

I faced this issue recently in two different applications where the Javascript library was not performing fast enough causing tardy user experience. I figured out that Firebug is an extension for Firefox that can be used to do the performance tuning. The way this works is,

a) install Firebug (and restart the Firefox browser)
b) enable Firebug if not currently enabled
c) load the page that needs performance tuning
d) open up Firebug and in the console, click on Profile
e) start using the UI controls in the page that have performance problem
f) Click on the profile and see a table of all the function calls ordered by the amount of time spent

This gives you an idea of the functions that are slow. The granularity of this report is only by function (thought it would have been good if there is a way to have line level granularity for some hot-spot functions to pin-point the line number). From this, it’s possible to figure out what’s going on and go about optimizing. In my specific cases, the two things I had to do one in each app are

1) Remove regular expression object creation and comparing from an inner loop
2) Reduce the number of Math.round calls

The performance gain in case of 1) was significantly high.

November 23, 2007

JavaScript Performance – Incremental Asynchronous Processing

Filed under: DHTML, javascript — S @ 4:00 am

I have an application where the hierarchical data is displayed as a table and I need to provide the ability to expand and collapse the nodes (I explained how this can be done in my Nested TBODYs post). With large data sets this had a lot of problem and Netscape displays the standard dialog about stop/continue the script. After a bit of research, it turned out that using the setTimeout method, the long running code can be made asynchronous.

So, I thought that’s not a big deal. Just call the function in setTimeout. After doing that, I still had the same problem. Then, it appears that even with setTimeout, the code shouldn’t be running for too long or otherwise I would end up with the same stop/continue dialog.

Then it turns out, the solution is to keep calling the setTimeout multiple times and each time doing only a small part of the computation. Now, how the heck can this be done when you have a big loop? Below are the steps to do that.

Say you had code like


for(var i=0;i<rows.length;i++) {
... // some logic
}

Change this to


var i=0;
function dosomething() {
var count = 0;
for(;i<rows.length;i++) {
... // original logic
count++;
if(count == 10) // change this to an appropriate number
break;
}
if(i<rows.length)
setTimeout(dosomething,0);
}

This is pretty much it!

Now, say you want to do something at the end of such long logic in loop. How can this be done? You can do this by using a callback function. So, the above code would be changed to


var i=0;

function dosomething(callbackf) {
var count = 0;
for(;i<rows.length;i++) {
... // original logic
count++;
if(count == 10) // change this to an appropriate number
break;
}
if(i<rows.length)
setTimeout(dosomething,0);
else if(callbackf) callbackf();
}

That’s it, now at the end of this incremental asynchronous processing, you get a hook to do some additional logic. Infact, you can keep nesting these incremental-asynchronous computations each of which calling at the end of the other.

Couple of things to note:

1. The dosomething should be a function defined within the context of another function and the loop variable. This essentially creates a closure for the loop variable. Defining the function as a top level function will not work.
2. In my specific case, I had defined the dosomething function twice, once in each part of the if-else statement. For some reason, this didn’t work in IE. Giving a different name for each case worked though.
3. In the above code, where the count is incremented, if you have logic that skips doing anything for certain increments of the loop variable, i, then don’t increment the count variable. For example, in my hierarchical data expansion/collapse functionality, there are times where the rows are already hidden and I don’t have to hide them again. This improves the speed a bit more as the number of chunks of incremental processing are optimized.

November 18, 2007

Nested TBODYs

Filed under: DHTML, javascript — S @ 1:26 am

The quick answer is, this is not possible. But continue to read on a possible workaround.

As per the HTML 4.01 tables specification, a tbody consists of only TRs. So, that essentially means, it’s not possible to have nested TBODYs. Ofcourse, a cell in a row can contain a table that can contain a TBODY, but we are not talking about that type of nesting, are we?

Taking a step back, what’s the need for nested TBODYs? I have a hierarchical data that is displayed as a table and to provide the ability to expand and collapse, a quick temptation is to make the child nodes of each parent node to be put into a tbody and just hide/show that tbody element alone. Now, due to the hierarchical nature, a child node itself will need to be created as a tbody to capture it’s own children. So, this is where the need for a nested tbody arises.

So, after checking the above mentioned specification that it’s not possible to nest tbodys, I achieved the above required expand/collapse functionality using TRs itself. The trick here is to make use of the ID attribute and specify a unique ID for each TR such that the TR elements of the child nodes contain the IDs which contain the ID of the parent element in them as a prefix. For example, if the parent has an id of ‘0′, then the child 1 can contain ‘0/0′, child 2 can contain ‘0/1′ and child of child 1 can contain ‘0/0/0′ and so on. With this approach, when the user is trying to expand/collapse a node, I can loop through all the TRs of the table and identify those that have a prefix same as the id of the node being expanded/collapsed and then hide/show those rows accordingly. I tried this idea and it worked without any problems.

November 14, 2007

HTML Table Sorting Using JavaScript

Filed under: DHTML, javascript — S @ 3:20 am

One of the most common actions when viewing data in a tabular format is to be able to sort. With DHTML and JavaScript, it’s possible to sort the data on the clientside. This avoid unnecessary roundtrip to the server and improves the usability. There are a few javascript libraries that provide the sorting capability with minimal edits to the html. However, if you want to have a total control over the sorting, for features such as, sorting a column sorts against data that is different than what’s visible (for example, data is displayed as percentages while the sorting is done without the % symbol, data is displayed as yyyy/mm/dd but internally there is a date object corresponding to what is displayed), then more control is required on sorting the data. Below is a snippet of code for doing this.


function DataRow(data) {
this.data = data; // data is itself an array or other object that contains data
this.row = null;
}

var data = new Array();
// here generate/write javascript to store the rows and their data, for example,
// data[data.length] = new DataRow(new Array(1,2,3));

var table = document.getElementById('data'); // assuming there is no THEADER
if(table.firstChild.nodeName == 'TBODY') table = table.firstChild;
var rows = table.getElementsByTagName('TR');
for(var i=1;i<rows.length;i++) // assuming header is also stored as a row
data[i].row = row[i];

function sortTable(event,col) {
var header = table.firstChild; // storing both heading and data in tbody.
while(table.firstChild) table.removeChild(table.lastChild);
table.appendChild(header);
data.sort(function(a,b) { return a.data[col] - b.data[col]; });
// you can have more complex logic based on the data and requirements
for(var i=0;i<data.length;i++)
table.appendChild(data[i]);
}

Next, it’s a matter of pluging in the sortTable(event,col) call in the onclick of the header.

The key idea here is to be able to keep the data and the related UI element (the row), together as an object and do sorting on those objects.

October 24, 2007

Inline/Embedded XML in HTML

Filed under: AJAX, javascript — S @ 2:29 am

Ajax is cool, but in scenarios where it’s not needed, there is no need to use it. For example, if there is some XML data that is being rendered on the UI using Javascript, if the XML data is static, then there is no need to first load the page and then use the XMLHTTPRequest object (or Prototype.js) to get the XML and then use it.

Instead, it’s possible to simply embed the XML into the HTML document itself. What’s the benefit of this? It simply avoids an extra round-trip to the server. However, doing this required a bit of research and the typical differences with Firefox and IE. So, here is what I had researched and did to make it work in both cases.

IE supports xml tag that can be used to embed XML into a HTML page. In Firefox, simply embed the entire content in the same xml tag. However, an extra piece of code is needed to make it work in Firefox.

The syntax is


<xml id='xmldata' style='display:none;'>
any piece of xml
</xml>

The style=’display:none’ is needed in Firefox. Otherwise, any content within this tag is going to be displayed. Finally, in the code following javascript is required

var xml = document.getElementById(‘xmldata’);
if(xml.documentElement == null)
xml.documentElement = xml.firstChild; /* This is required for Firefox. Make sure there is no gap between the xml tag and the root node */

That’s it!

Next Page »

Blog at WordPress.com.