J
Jake Barnes
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 "backgroundColorPicker" 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
"backgroundColorPicker" div, then I could do this:
refToCommunicationBox.removeChild(refToBackgroundColorPicker);
But now, as I understand it, the div "backgroundColorPicker" 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 "backgroundColorPicker" 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 refToBackgroundColorPicker =
document.getElementById("refToBackgroundColorPicker");
then I could create a function like this:
function getRefToBackgroundColorPicker() {
var newRefToBgColorPicker = refToBackgroundColorPicker.cloneNode();
return newRefToBgColorPicker;
}
Then I just have to use this function whenver I want a reference to the
div "backgroundColorPicker". 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 storeReferencesToHTMLSafely() {
var arrayOfReferencesToHtmlBlocks = new Object();
var setAndGetReferenceToHtml = new Object();
setAndGetReferenceToHtml.get = function (idOfHtmlBlock) {
var htmlBlockRef = arrayOfReferencesToHtmlBlocks[idOfHtmlBlock];
if (!htmlBlockRef || htmlBlockRef == "" || htmlBlockRef == undefined)
{
arrayOfReferencesToHtmlBlocks[idOfHtmlBlock] =
document.getElementById(idOfHtmlBlock);
var htmlBlockRef = arrayOfReferencesToHtmlBlocks[idOfHtmlBlock];
}
var newHtmlBlockRef = htmlBlockRef.cloneNode(true);
return newHtmlBlockRef;
}
return setAndGetReferenceToHtml;
}
then I could have this line in global space:
var allHtmlReferencesObject = storeReferencesToHTMLSafely();
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 arrayOfReferencesToHtmlBlocks 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 allHtmlReferencesObject, 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?
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 "backgroundColorPicker" 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
"backgroundColorPicker" div, then I could do this:
refToCommunicationBox.removeChild(refToBackgroundColorPicker);
But now, as I understand it, the div "backgroundColorPicker" 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 "backgroundColorPicker" 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 refToBackgroundColorPicker =
document.getElementById("refToBackgroundColorPicker");
then I could create a function like this:
function getRefToBackgroundColorPicker() {
var newRefToBgColorPicker = refToBackgroundColorPicker.cloneNode();
return newRefToBgColorPicker;
}
Then I just have to use this function whenver I want a reference to the
div "backgroundColorPicker". 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 storeReferencesToHTMLSafely() {
var arrayOfReferencesToHtmlBlocks = new Object();
var setAndGetReferenceToHtml = new Object();
setAndGetReferenceToHtml.get = function (idOfHtmlBlock) {
var htmlBlockRef = arrayOfReferencesToHtmlBlocks[idOfHtmlBlock];
if (!htmlBlockRef || htmlBlockRef == "" || htmlBlockRef == undefined)
{
arrayOfReferencesToHtmlBlocks[idOfHtmlBlock] =
document.getElementById(idOfHtmlBlock);
var htmlBlockRef = arrayOfReferencesToHtmlBlocks[idOfHtmlBlock];
}
var newHtmlBlockRef = htmlBlockRef.cloneNode(true);
return newHtmlBlockRef;
}
return setAndGetReferenceToHtml;
}
then I could have this line in global space:
var allHtmlReferencesObject = storeReferencesToHTMLSafely();
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 arrayOfReferencesToHtmlBlocks 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 allHtmlReferencesObject, 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?