473,703 Members | 4,129 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

using javascript closures to create singletons to ensure the survival of a reference to an HTML block

Using javascript closures to create singletons to ensure the survival
of a reference to an HTML block when removeChild() may remove the last
reference to the block and thus destory the block is what I'm hoping to
achieve.

I've never before had to use Javascript closures, but now I do, so I'm
making an effort to understand them. I've been giving this essay a
re-read:

http://jibbering.com/faq/faq_notes/closures.html

Let me state the problem I face and the solution as I understand it. I
wanted to create an AJAX interface to some online software. As an
experiment, I built this page:

http://www.publicdomainsoftware.org/ajaxExperiment.htm

Click anywhere to get the controls and then click "Add paragraph" to
add some text. The communication box that appears is a bit like a modal
dialog box (except I don't yet freeze the use of everything else, so it
isn't really modal). I want to add blocks of HTML to this communication
box so that the user can add an appropriate input. When this box is
called again, I'll want to remove some of the HTML, and then add other
blocks of HTML.

Let's assume that all the HTML that I'll use starts off on the page.
The user arrives at the page and clicks somewhere to bring up the
controls, then clicks "Change Background color". The HTML block in the
div with the id of "backgroundColo rPicker" is now placed in the
communication box. The user then picks a color and the background color
changes.

Let's suppose the user then clicks "Add paragraph". If I have a
reference to the communication box and I have a reference to the
"backgroundColo rPicker" div, then I could do this:

refToCommunicat ionBox.removeCh ild(refToBackgr oundColorPicker );

But now, as I understand it, the div "backgroundColo rPicker" is gone
for good. It can not be brought back except by refreshing the page and
losing all of one's work. For the div "backgroundColo rPicker" to remain
as a thing that my script can reference, then at least one reference to
it must survive. The easiest way for me to achieve this would be, at
the top of the page, to declare a reference to it in global space, like
this:

var refToBackground ColorPicker =
document.getEle mentById("refTo BackgroundColor Picker");

then I could create a function like this:

function getRefToBackgro undColorPicker( ) {
var newRefToBgColor Picker = refToBackground ColorPicker.clo neNode();
return newRefToBgColor Picker;
}
Then I just have to use this function whenver I want a reference to the
div "backgroundColo rPicker". This is basically a workable solution. The
only problem with it is that I need a global variable for every HTML
block that I'm going to have on my page. If I hope to someday build
sophisticated software, this might lead to a very large number of
global variables. Also, there is still the risk that I might
accidentally use removeChild() on the global variable, destroying the
only reference to that block of HTML, and thus removing it from the
page for good.

I realize, though, that there is another way to do this, and, I think,
it involves Javascript closures. But I'm not sure how to quite do it.
I'd like to create a reference that is pretty much indestructible. A
singleton. But, with my limited understanding, it seems like somehow
one must always end up with a global variable for the HTML to survive
after removeChild() has been used. This seems like a bit of a hack. I
suspect that my conceptual thinking here is fuzzy. Can anyone give me
a clue about what I've got wrong?
function storeReferences ToHTMLSafely() {
var arrayOfReferenc esToHtmlBlocks = new Object();
var setAndGetRefere nceToHtml = new Object();

setAndGetRefere nceToHtml.get = function (idOfHtmlBlock) {
var htmlBlockRef = arrayOfReferenc esToHtmlBlocks[idOfHtmlBlock];
if (!htmlBlockRef || htmlBlockRef == "" || htmlBlockRef == undefined)
{
arrayOfReferenc esToHtmlBlocks[idOfHtmlBlock] =
document.getEle mentById(idOfHt mlBlock);
var htmlBlockRef = arrayOfReferenc esToHtmlBlocks[idOfHtmlBlock];
}
var newHtmlBlockRef = htmlBlockRef.cl oneNode(true);
return newHtmlBlockRef ;
}

return setAndGetRefere nceToHtml;
}

then I could have this line in global space:

var allHtmlReferenc esObject = storeReferences ToHTMLSafely();
But this is the wrong way to do things? Is there a cleaner approach? I
admit my conceptual grasp of closures is weak, and what I've done here
seems like it could be done without closures. Somehow, I've failed to
achieve my goal.

Is there a way for arrayOfReferenc esToHtmlBlocks to be a singleton and
for no variable to be needed in global space?

I suppose what I've done here does take me toward my goal. I'd never
use removeChild() on allHtmlReferenc esObject, so that would at least
take me part way toward where I want to go - the risk of accidentally
removing the last reference to a block of HTML would be greatly
reduced.

Any thoughts, feedback, comments?

Feb 11 '06 #1
2 3054
Jake Barnes wrote:
Using javascript closures to create singletons to ensure the survival
of a reference to an HTML block when removeChild() may remove the last
reference to the block and thus destory the block is what I'm hoping to
achieve.
Then you have been misinformed. removeChild does not destroy the node.
In fact, it return a reference to it.
I've never before had to use Javascript closures, but now I do,
No you don't. Not for this scenario.
[snipped remainder of perceived problems]
But this is the wrong way to do things? Is there a cleaner approach?


Yes and yes. One possible solution would be to have one global variable
where you store your references to your various nodes.

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title></title>
<style type="text/css">
*{padding:0;mar gin:0;}
html,body{heigh t:100%;}
body{font-size:100.01%;}
..tool{border:1 px solid gray;margin:10p x;padding:10px; background:#eee ;}
</style>
<script type="text/javascript">
function $(id){return document.getEle mentById(id)}

var registry = {
toggle: function(id){
if (id in registry){
registry[id].visible = !registry[id].visible;
if (registry[id].visible){
$('container'). appendChild(reg istry[id]);
} else {
$('container'). removeChild(reg istry[id]);
}
} else {
registry[id] = $('container'). removeChild($(i d));
registry[id].visible = false;
}
return false;
}
}
</script>
</head>
<body>
<div id="container" >
<div id="toolbox">
<a href="jsreq.htm " onclick="return registry.toggle ('tool1')">
Tool 1</a>
<a href="jsreq.htm " onclick="return registry.toggle ('tool2')">
Tool 2</a>
<a href="jsreq.htm " onclick="return registry.toggle ('tool3')">
Tool 3</a>
</div>
<div id="tool1" class="tool">Th is is tool one.</div>
<div id="tool2" class="tool">Th is is tool two.</div>
<div id="tool3" class="tool">Th is is tool three.</div>
</div>
</body>
</html>

Feb 11 '06 #2
Jake Barnes wrote:
Using javascript closures to create singletons to ensure the survival
of a reference to an HTML block when removeChild() may remove the last
reference to the block and thus destory the block is what I'm hoping
to achieve.

I've never before had to use Javascript closures, but now I do, so I'm
making an effort to understand them. I've been giving this essay a
re-read:

http://jibbering.com/faq/faq_notes/closures.html

Let me state the problem I face and the solution as I
understand it. I wanted to create an AJAX interface to
'AJAX interface' can mean all things to all men.
some online software. As an experiment, I built this page:

http://www.publicdomainsoftware.org/ajaxExperiment.htm
That is nice for you, and irrelevant to anyone reading news off-line.
Click anywhere to get the controls and then click
"Add paragraph" to add some text.
No thanks, re-connecting to the Internet just to look through reams of
unrelated javascript buried in masses of bloated HTML to find a tiny
pertinent fragment has not proved a worthwhile activity in the past.
The communication box that appears is a bit like a
modal dialog box ... . When this box is called again,
I'll want to remove some of the HTML, and then add
other blocks of HTML.

Let's assume that all the HTML that I'll use starts off
on the page.
Seems reasonable.
The user arrives at the page and clicks somewhere to
bring up the controls, then clicks "Change Background
color". The HTML block in the div with the id of
"backgroundColo rPicker" is now placed in the communication
box. The user then picks a color and the background color
changes.

Let's suppose the user then clicks "Add paragraph". If I
have a reference to the communication box and I have a
reference to the "backgroundColo rPicker" div, then I
could do this:

refToCommunicat ionBox.removeCh ild(refToBackgr oundColorPicker );

But now, as I understand it, the div "backgroundColo rPicker"
is gone for good.
So why do that? Why not re-append/insert the block of HTML to wherever
you got it from in the first place?
It can not be brought back except by refreshing the page
and losing all of one's work. For the div
"backgroundColo rPicker" to remain as a thing that my script
can reference, then at least one reference to it must survive.
The easiest way for me to achieve this would be, at the top of
the page, to declare a reference to it in global space, like
this:

var refToBackground ColorPicker =
document.getEle mentById("refTo BackgroundColor Picker");
The odds of successfully retrieving a reference to a DOM node with -
getElementById - at the "top of the page" (prior to the parsing of the
HTML BODY) are low.
then I could create a function like this:

function getRefToBackgro undColorPicker( ) {
var newRefToBgColor Picker =
refToBackground ColorPicker.clo neNode(); ^
Without a true boolean argument the - cloneNode - method only clones the
Node upon which it is called, rather than the DOM branch it contains.
The likelihood is that the DIV node alone does not define the required
GUI interface.
return newRefToBgColor Picker;
}
If your dialog is model why would you need more than one instance of the
DOM branch that defines it (which is the implication of cloning it,
assuming you actually were cloning the whole branch)?

Incidentally, the group's FAQ references instruction on formatting
posted code in a way that is suitable for this context; preserving
indentation, avoiding automated line wrapping and so on. If you want
people to read your code you should present it in a form that is as
readable as possible.
Then I just have to use this function whenver I want
a reference to the div "backgroundColo rPicker".
It actually returns a clone of the DOM Node not a reference to the
original.
This is basically a workable solution. The only problem with
it is that I need a global variable for every HTML block that
I'm going to have on my page. If I hope to someday build
sophisticated software, this might lead to a very large
number of global variables.
Oh yes, any system based upon the extensive use of global variables will
have become chaotic and un-maintainable by the time you get to 4000-odd
lines of code. It is a trap for the amateur, and you know enough not to
even start off down that path.
Also, there is still the risk that I might
accidentally use removeChild() on the global variable,
Ah, do I perceive a misconception about the relationship between the
DOM, and DOM methods, and javascript (from this, combined with the
unexpected cloning above)? The act of removing a Node from the DOM
with - removeChild - is not going to impact the value of a global
variable. If the global variable refers to the Node before it is removed
it will refer to it after it is removed from the DOM, and the existence
of the reference will prevent the garbage collection of the Node. Having
said that, DOMs don't seem to like Nodes to be hanging around in a freed
state for long. They are much happier if you move Nodes from place to
place in a DOM or from one document to a related document fragment and
back.
destroying the only reference to that block of HTML,
The DOM structure refers to the Node, and the global variable refers to
the Node. Using - removeChild - will remove the Node from the DOM only.
and thus removing it from the
page for good.

I realize, though, that there is another way to do this,
Probably half a dozen other ways.
and, I think, it involves Javascript closures.
For a couple of them, yes. Though you want to watch out for the circular
references including DOM Nodes problem on IE browsers as if you hide
references to DOM Nodes away in closures they may become difficult to
explicitly free later, if the need arises.
But I'm not sure how to quite do it.
I'd like to create a reference that is pretty much
indestructible.
Closures are the nearest you will get to that.
A singleton.
I am not user that is a useful label here.
But, with my limited understanding, it seems like somehow
one must always end up with a global variable for the HTML
to survive after removeChild() has been used.
As - removeChild - only acts upon references to a Node within the DOM
structure any references to the same node in javascript structures will
not be altered.
This seems like a bit of a hack. I suspect that my
conceptual thinking here is fuzzy. Can anyone give me
a clue about what I've got wrong?
function storeReferences ToHTMLSafely() {
var arrayOfReferenc esToHtmlBlocks = new Object();
var setAndGetRefere nceToHtml = new Object();

setAndGetRefere nceToHtml.get = function (idOfHtmlBlock) {
var htmlBlockRef = arrayOfReferenc esToHtmlBlocks[idOfHtmlBlock];
if (!htmlBlockRef || htmlBlockRef == "" ||
htmlBlockRef == undefined)
The NOT (- ! -) operator in the expression - !htmlBlockRef -
type-converts its operand to boolean and then evaluates as true for
false and false for true. The empty string type-converts to boolean
false, so the expression - !htmlBlockRef - will be true when -
htmlBlockRef == "" - is true. So this expression is worthless in your
logical OR expression.

Similarly - undefined - type-converts to boolean false so the
expression - !htmlBlockRef - is also true when - htmlBlockRef ==
undefined - is true. Making the third expression in your logical OR
worthless, and so the entire logical OR is redundant (The first
expression will always be true whenever either of the other two is true)
and can be replaced with:-

if(!htmlBlockRe f){
// if - htmlBlockRef - is either an empty string or undefined we
come in here anyway.
// we also come in here is - htmlBlockRef - is null and numeric zero
or NaN.
}

And references to the global - undefined - variable were one of the more
recent additions to the language (Netscape 4+, IE 5+ and error producing
in preceding implementations ), and have proved the source of much
confusion, with - if(typeof x != undefined){ ... - being a commonly
recurring mistake while learning the language (it is always true even
if - x - is undeclared and/or undefined as typeof always evaluates as a
non-empty string).
{
arrayOfReferenc esToHtmlBlocks[idOfHtmlBlock] =
document.getEle mentById(idOfHt mlBlock);
var htmlBlockRef = arrayOfReferenc esToHtmlBlocks[idOfHtmlBlock]; ^^^
Multiple declarations of the same variable are pointless (though
harmless).
}
var newHtmlBlockRef = htmlBlockRef.cl oneNode(true); ^^^ ^^^^
Dito. ||||
////
Deep cloning this time, but why clone at all?

However, if you always clone the original DOM Node, and never call -
removeChild - or move on the original (it always stays at its original
location in the DOM) then why it is a problem to be throwing away
references to the clones, as the original can then be re-cloned? (It
would not be very efficient to do that (with the inefficient browser
garbage collection you would probably be looking at quite steep and
one-way increases in memory consumption)).
return newHtmlBlockRef ;
}

return setAndGetRefere nceToHtml;
}

then I could have this line in global space:

var allHtmlReferenc esObject = storeReferences ToHTMLSafely();
But this is the wrong way to do things? Is there a
cleaner approach?
There is a great deal here that needs questioning/clarifying,
particularly all the cloning. There probably is a better approach to the
bigger problem, but that may not necessarily remove this particular
issue.
I admit my conceptual grasp of closures is weak, and what
I've done here seems like it could be done without closures.
If you look at the cited description of closures you will see that the
mechanism in javascript is based entirely around a structure of
inter-referring objects (the scope chains and the function object that
refer to them). Any language that has references to objects (or
pointers) can implement a parallel structure and do in another way what
can be done with closures, and this is true of javascript as well. The
advantage of using closures in a language that has closures is that the
mechanism is built-in, available and relatively cheep to employ (rather
than programming your own).
Somehow, I've failed to
achieve my goal.

Is there a way for arrayOfReferenc esToHtmlBlocks to be
a singleton and for no variable to be needed in global space?
You have already done that, so long as - storeReferences ToHTMLSafely -
is only called once. You can guarantee that the equivalent is only
called once by instead using the execution of a function expression to
create the closure:-

var safeStoreForHTM LReferences = (function(){
var refToHtmlBlocks = {};
return ({
get:function(id ){
var htmlBlockRef;
if(
(
(htmlBlockRef = refToHtmlBlocks[id])||
(
(htmlBlockRef =
(refToHtmlBlock s[id] = document.getEle mentById(id))
)
)
)&&
(htmlBlockRef.c loneNode)
){
return htmlBlockRef.cl oneNode(true);
}
return null;
}
});
})();

called as:-

var x = safeStoreForHTM LReferences.get ('someId');
I suppose what I've done here does take me toward my goal.
I'd never use removeChild() on allHtmlReferenc esObject,
It would error if you did at that object does not implement the method,
and cannot be used as an argument for the method of objects that do.
so that would at least take me part way toward where I
want to go - the risk of accidentally removing the last
reference to a block of HTML would be greatly reduced.

Any thoughts, feedback, comments?


Richard.

Feb 12 '06 #3

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

28
20334
by: Daniel | last post by:
Hello =) I have an object which contains a method that should execute every x ms. I can use setInterval inside the object construct like this - self.setInterval('ObjectName.methodName()', this.pinginterval); - but is there no way to do this without using the literal ObjectName? If I write 'this.methodName()' I get "Line 1 Char 1: Object doesn't support this property or method." in IE, and nothing happens in Firebird.
6
17209
by: Joe Kelsey | last post by:
When you use addEventListener (or addEvent in IE) to call an object method, does it call it with the correct this parameter? The ECMAScript reference has a lot to say about the caller using Function.prototype.call or Function.prototype.apply and passing the correct this pointer for the context, but how does addEventListener determine the correct this pointer. Or does it just punt and pass the global context, thus making it impossible to...
14
9589
by: Michael Winter | last post by:
In an attempt to answer another question in this group, I've had to resort to calling the DOM method, Node.removeChild(), using a reference to it (long story...). That is, passing Node.removeChild. In Opera (7.23/Win), the call appears to do nothing - the node remains - but no errors are shown. In Netscape (7.0/Win), an exception results. On IE (6.0/Win), the node is removed. Strangly, if I pass another function reference, say...
6
15224
by: marktm | last post by:
Hi- I am trying to use setInterval to call a method within an object and have not had any luck. I get "Object doesn't support this property or method" when I execute the following code. What I am doing wrong? Your help will be much appreciated. Thanks
10
2071
by: Emre Sevinc | last post by:
Take a look at the following snippet: <html> <head> <script> function add(elementId) { var container = document.getElementById(elementId); for (var i = 0; i < 10; i++) { var elt = document.createElement('div'); elt.innerHTML = "" + i;
7
5063
by: Darko | last post by:
Hello, I have this particular problem with eval() when using Microsoft Internet Explorer, when trying to define an event handler. This is the code: function BigObject() { this.items = new Array(); this.values = new Array();
60
5014
by: marss | last post by:
Maybe anyone know good free online JavaScript knowledge test? This not exactly a system for testing online required - it may be simply list of questions with variants of answers (I have to prepare tests for learners and I need something to be taken as basis). I was able to find only this (http://www.w3schools.com/js/ js_quiz.asp), but I need more. Thanks, Mykola
1
5409
by: p.tilhoo | last post by:
Hello there, I am a programmer mostly using c# and just started using Javascript. I am trying to use prototype to declare and use an object and having difficulties in coding for nested objects. Basically my object called layercontrol will contain and array of layergroup which in turn contains map layer objects. The layergroup and layer object should be just like any object of properties and
4
1844
by: MartinRinehart | last post by:
I've written a short article explaining closures in JavaScript. It's at: http://www.martinrinehart.com/articles/javascript-closures.html I think I've understood. I look forward to your constructive critique.
0
8761
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
8674
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
9262
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
1
6595
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5923
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4434
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
1
3127
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
2463
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2070
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.