Generic JavaScript functions for generic DOM exploration – leveraging the JavaScript dyamic function creation

Lucas Jellema 4
0 0
Read Time:4 Minute, 5 Second

Often there is a need for client side (JavaScript) DOM oriented manipulation in Web Applications. To achieve a higher degree of user interactivity, more productivity or simply a more visually appealing user interface. And such client side operations come almost invariably with a lot of DOM manipulation – direct interaction with the nodes of the browser in memory representation of the HTML document. This blog discusses an example of such manipulation and introduces a little generic code that may be of use to many people

The example I have to work on is shown below:

 

In this entry form, the user can enter two sorts of values: amounts (in euros) and percentage for each quarter in the current year. Occasionally, the user must also enter a specific date value. However, since that is relatively rare and this matrix can easily contain dozens of rows, it is deemed better to only show those date fields when they are actually needed.

Toggling the view – aka client side detail disclosure – should unveil the date fields in the table row in which the disclose icon was clicked. The icon should change its appearance into a close date fields icon. Something like:

 

The main requirements in terms of DOM interaction....
:

  • from the toggle icon, find its enclosing TR (table row) ancestor (since the disclose acts on all fields in the same row)
  • from the Table Row, find all descendants that are a SPAN and satisfy a certain naming condition
  • hide the disclose icon/show the close icon; unveil the date fields (and later on hide them again)

The third requirement – hiding and displaying elements – is one I have solved many times, so that’s not the issue. The other two are not really much of an issue, except for the fact that I do not do this sort of thing often enough, so I keep reinventing the same wheel. Now for my own benefit – in order to find this code when next I have a need for it, in six months time or so – the more or less generic functions that help me implement these two requirements:

Find an Element’s Ancestor of a specific type (tag):

function findParentWithTag(el, tagName) {
var parent = el.parentNode;
if (parent)
if (parent.tagName ==tagName)
return parent;
else
return findParentWithTag(parent, tagName);
else
return null;
}//findParentWithTag

 

Find all descendants – at all levels in the tree – for a given element that satisfy the given condition

function findChildrenWithTagAndCondition( el, tagName, evalfunction) {
var children = new Array();
if (tagName) {
descendants = el.getElementsByTagName(tagName);
for (var j =0; j < descendants.length;j++) {
if ( evalfunction(descendants[j]))
{ children.push(descendants[j]);
} //if
} //for
}
else {
for( var i = 0; i < el.childNodes.length; i++ ) {
if (el.childNodes[i].tagName==tagName ) {
if ( evalfunction(el.childNodes[i]))
{ children.push(el.childNodes[i]);
} //if
} //if
// investigate the children of this element
descendants = findChildrenWithTagAndCondition( el.childNodes[i], tagName, evalfunction);
if (descendants && descendants.length > 0) {
// add all children found (including descendants further down the tree) to the list of qualifying children
for (var j =0; j < descendants.length;j++) {
children.push( descendants[j]);
} //for
}//if
}//for
}
return children;
}// findChildrenWithTagAndCondition

This latter function can be called with the element itself, an optional tag name and the function that should be called to find out whether or not a certain child element qualifies. Here we can use the fun characteristic of JavaScript that allows us to create functions on the fly.

  var evaldiv = new Function("div",  "result = div.id.indexOf('VerplichtingDatum'); return result > -1;");
divs = findChildrenWithTagAndCondition( tr, "DIV", evaldiv);
 

This example shows the creation of an evaluation function that has a single input parameter (called div) and executes the evaluation "div.id.indexOf(‘VerplichtingDatum’)" : all div children whose id attribute contain the string VerplichtingDatum qualify.

Hide/Display elements dynamically 

To make the story complete – even though this is most trivial part – I will show how to hide/display element through DOM Manipulation.

First of all, I have included the following CSS style in my stylesheet:

.invisible {display:none} 

Next, to hide an element, I simply apply this style to it. To make it visible, I set the style to nothing at all. For example, to unveil the Date Fields that are contained in DIV element whose styleClass is initially set to invisible:

function showDateFields(icon) {
// hide the unveil icon
icon.className='invisible';
// show the hide (again) icon
el = document.getElementById(icon.id.replace("show","hide"));
// set its classname to null
el.className='';

// find and unveil DateFields
// find parent TR
tr = findParentWithTag(icon, "TR");
var evaldiv = new Function("div", "result = div.id.indexOf('VerplichtingDatum'); return result > -1;");
divs = findChildrenWithTagAndCondition( tr, "DIV", evaldiv);
for( var i = 0; i < divs.length; i++ ) {
divs[i].className='';
}
}

About Post Author

Lucas Jellema

Lucas Jellema, active in IT (and with Oracle) since 1994. Oracle ACE Director and Oracle Developer Champion. Solution architect and developer on diverse areas including SQL, JavaScript, Kubernetes & Docker, Machine Learning, Java, SOA and microservices, events in various shapes and forms and many other things. Author of the Oracle Press book Oracle SOA Suite 12c Handbook. Frequent presenter on user groups and community events and conferences such as JavaOne, Oracle Code, CodeOne, NLJUG JFall and Oracle OpenWorld.
Happy
Happy
0 %
Sad
Sad
0 %
Excited
Excited
0 %
Sleepy
Sleepy
0 %
Angry
Angry
0 %
Surprise
Surprise
0 %

Average Rating

5 Star
0%
4 Star
0%
3 Star
0%
2 Star
0%
1 Star
0%

4 thoughts on “Generic JavaScript functions for generic DOM exploration – leveraging the JavaScript dyamic function creation

  1. Hi Lucas,
    about findChildrenWithTagAndCondition():
    1) all “” have a bad editing, so appear as “>” and so on.
    2) the function seems to allow the parameter tagName as optional:
    if(tagname) do this,
    else do that
    but in else case, the function still wants tagname few lines after.

    did I miss something ?

  2. Jeroen,

    Thanks for the tip! I will go and rewrite my code using JQuery. Better do this rightaway before I become attached to my own code. And I like the speed promised with JQuery! (and the fact that it is code that has been tested).

    Lucas

  3. Have you looked into jQuery? I’m afraid you rewrote some of the jQuery functions.

    Code sample 1 (http://docs.jquery.com/DOM/Traversing):
    Find an Element’s Ancestor of a specific type (tag):
    $(“span”).parents(“p”)
    Find all parent elements of each span that is a paragraph.

    For the second sample you can use
    find(expr) (though I’m not sure about that, but I think it can do what you want)

    For showing and hiding you can use show() and hide():
    $(“p”).show() will hide all ‘s

    jQuery is a really great Javascript library and is only 20KB. Ajaxian recently pointed to an article to show that jQuery also is one of the fastests libraries out there:
    http://ajaxian.com/archives/jquery-113-800-faster-still-20kb
    It’s usually more efficient to write your own methods (you only write what you need), but I think it’s very hard to write faster code than jQuery.

    But still a very nice article, seems I’m not the only Mr. Dojo at AMIS 😉

Comments are closed.

Next Post

My rediscovery of vi

I am sure I am one of those humans that are using something for a long long time, and suddenly find out they have been doing things in a not so optimal way… One easily gets used to a personal style of working with (software) tools or devices. Nothing wrong […]
%d bloggers like this: