This is not so much a problem, since I have already managed to find a solution, but my solution requires the use of the eval() function, which I just hate to use.
The problem is this.
I have an object that has a function. This function needs to call itself in a setTimeout call. Using the "this" keyword from within the callback function will obviously not work, seeing as it would reference the new function rather than the object instance.
So, in an attempt to solve that, I create a reference to "this" before I create the callback function and use that inside the callback function, like so:
Expand|Select|Wrap|Line Numbers
- // Minimized the code to get to the point
- function Updater(pTargetElement, pMaxValue)
- {
- this.update = function(pCurrent)
- {
- self = this;
- window.setTimeout(function(){
- self.update(pCurrent);
- }, 50);
- }
- }
The object is meant to manipulate an element, taking an initial value and counting up until the max value is reached, displaying the current value in the given target element.
And this does exactly that... if I have only one instance of the object running at a time.
Once a second instance is in play, the two will be fighting over the "self" variable, which is apparently created in a scope that both instances use.
As a result, if a first instance sets the "self" value to itself and fires of the setTimeout, a second instance may be called before the timeout is reached, altering the "self" variable, which is then reflected in the timeout calls from both objects.
This effectively doubles the effect on the second instance, while the first instance is left unchanged.
And this is my problem. How do I create the "self" variable in a scope that is unique to each object instance? So when the second instance is called, it will not alter the variable created by the first instance.
But, like I said, I managed to find a solution by using the eval() function.
My thinking was that the main problem is the second instance re-using the same variable. So I created a "dynamic" variable by creating a random number and turning that into a variable by running it through the eval function.
Like so:
Expand|Select|Wrap|Line Numbers
- function Updater(pTargetElement, pMaxValue)
- {
- this.update = function(pCurrent)
- {
- rand = Math.floor(Math.random() * 10000);
- eval("self_" + rand + " = this;\
- window.setTimeout(function(){\
- self_" + rand + ".update(" + pCurrent + ");\
- }, 50);");
- }
- }
This can be used, and my use of it will be limited so the potential of problems is minimal, but there just has to be a better way.
This is the full code I am using to test this, just in case:
Expand|Select|Wrap|Line Numbers
- function Updater(pTargetElement, pMaxValue){
- this.targetElement = pTargetElement;
- this.maxValue = pMaxValue;
- this.update = function(pCurrent){
- if (pCurrent >= this.maxValue) {
- return;
- }
- ++pCurrent;
- this.targetElement.innerHTML = pCurrent.toString();
- rand = Math.floor(Math.random() * 10000);
- eval("self_" + rand + " = this;\
- window.setTimeout(function(){\
- self_" + rand + ".update(" + pCurrent + ");\
- }, 50);");
- }
- }
- function bodyOnLoad(){
- for (i = 1; i <= 3; i++) {
- eval("window.setTimeout(function(){\
- updater = new Updater(document.getElementById(\"Counter" + i.toString() + "\"), 50);\
- updater.update(0);\
- }, (250 * " + i.toString() + "));");
- }
- }
And (shockingly) this work in all my browsers except IE.
Any input would be greatly appreciated.
Thanks,
- Atli Þór