setTimeout() causing slowdown and not exiting properly - javascript

Clarification: The parent frame is Page X, the child frame resides within page X.
The issue is the slow behavior and never hitting the section of code that clears the interval.
I have a parent and chilframe. An object is created in the parent then I used setTimeout() in the childframe to call the parent object to add itself to an internal collection within the parent object.
The code doesn't seem to behave as intended with really slow response from the browser. Any thoughts on the issue?
Parent frame
<script type="text/javascript">
var Cert = new Parent();
</script>
Child frame
<script type="text/javascript">
var c;
var id = setInterval("Create()", 1000);
function Create()
{
if (parent.Cert != null && parent.Cert != undefined)
{
c = new Child(parent.Cert, 1, null);
clearInterval(id);
}
}
</script>

Don't pass a string to setTimeout/Interval. Pass it a function reference instead!
var id = setInterval(function () {
Create();
}, 1000);
From the code you've given here, parent is window. Is this what you intend? There seems to be some relevant code missing here...
As for the slowdown, perhaps the function interval is too short, or it is never being satisfied? There could also be an error in the constructor for the Child class, which would make it so the clearInterval line won't ever be called. You could consider putting a limiter out there, or wrapping your instantiation in a try...catch block, or moving the clearInterval statement above the line where you're creating your object.
Or, do all of those things:
var c = null;
var id = setInterval(function () {
Create();
}, 1000);
var itr = 0;
function Create() {
// if it has looped more than 20 times, forget it
if (itr > 20) {
/* show an error message? */
clearInterval(id);
return false;
}
if (parent.Cert != null && typeof parent.Cert != 'undefined') {
// clear the interval first
clearInterval(id);
// safely create object
try {
c = new Child(parent.Cert, 1, null);
} catch (e) {
/* handle exception here */
}
} else {
// incrementing the interval counter
itr++;
}
}

Related

How can I change this into a loop instead of a recursive function?

So I have a piece of code like
var barlen = $('#SSWEprogressbar').width(),
$elems = $('[data-srcurl]'),
k = 0,
n = $elems.length;
LoadImage();
function LoadImage()
{
var $elem = $($elems[k]);
var img = new Image(),
url = $elem.attr('data-srcurl');
$(img).load(function(){
$('#SSWEloaderfront').attr('src',url);
$('#SSWEloadprogress').width((k+1)/n*barlen + "px");
var srctgt = $elem.attr('data-srctgt');
// change url to src attribute or background image of element
if ( srctgt == "srcattr" ){ $elem.attr('src',url); }
else if ( srctgt == "bgimg" ) { $elem.css('background-image',"url("+url+")"); }
// decide whether to exit the
if ( ++k == n ) { AllyticsSSWEPlayerShow(); }
else { LoadImage(); }
});
img.src = url;
}
and the reason I have it written that way is because load callback needs to be called before the stuff in the function can be executed again. If possible, I'd like to change this from a recursive function to a loop, but I don't know how to do that because there's no way to make a for or while loop "wait" before going on to the next iteration. Or is there?
As I mentioned in the comment you can easily resolve your problem, by using setTimeout(LoadImage, 100); in the else instead of calling the function directly. The 2nd parameter is the delay in ms.
If you understand why setTimeout(LoadImage, 0); is not stupid and not the same as calling the function directly then you understood setTimeout. It puts the function call in the queue, this means other events like clicks or keys that were pressed can be processed before the function is called again and the screen doesn't freeze. It's also impossible to reach max recursion like this, the depth is 1.

Using "this" in a constructor

I am attempting to make a project which does two way data binding on two specified variables. However, when I tried it out, the project did not seem to be working.
I'm pretty sure that what I did wrong is that I specified a constructor, and then inside, I created a variable using "this," a function using "this," and then I tried to use the first variable inside the function using "this." Is this allowed?
The code for my project is in the snippet below.
function glue(varOne, varTwo, interval = 60) {
this.varOne = varOne;
this.varTwo = varTwo;
this.varOneClone = this.varOne;
this.varTwoClone = this.varTwo;
this.interval = interval;
this.onChange = function(changedVar) {
if (changedVar == this.varOne) {
this.varTwo = this.varOne;
} else if (changedVar == this.varTwo) {
this.varOne = this.varTwo;
}
this.varOneClone = this.varOne;
this.varTwoClone = this.varTwo;
};
this.intervalID = setInterval(function() {
if (this.varOne != this.varTwo) {
if (this.varOne != this.varOneClone) {
this.onChange(this.varOne);
} else if (this.varTwo != this.varTwoClone) {
this.onChange(this.varTwo);
}
}
}, this.interval);
this.clearUpdate = function() {
clearInterval(intervalID);
};
this.changeUpdate = function(newInterval) {
this.interval = newInterval;
clearInterval(intervalID);
this.intervalID = setInterval(function() {
if (this.varOne != this.varTwo) {
if (this.varOne != this.varOneClone) {
this.onChange(this.varOne);
} else if (this.varTwo != this.varTwoClone) {
this.onChange(this.varTwo);
}
}
}, this.interval);
};
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Glue</title>
</head>
<body>
<input id="input" type="text"></input>
<p id="output"></p>
<script>
var input = document.getElementById("input");
var output = document.getElementById("ouput");
var glue = new glue(input, output, 60);
</script>
</body>
</html>
Thank you!
Edit:
I've tried using the var self = this; method which two people recommended, but it still refuses to work. The error from the console is TypeError: glue is not a constructor, but I'm not sure why this happens. I want glue to be a constructor. Please help! The new code is below.
function glue(varOne, varTwo, interval = 60) {
var self = this;
self.varOne = varOne;
self.varTwo = varTwo;
self.varOneClone = self.varOne;
self.varTwoClone = self.varTwo;
self.interval = interval;
self.onChange = function(changedVar) {
if (changedVar == self.varOne) {
self.varTwo = self.varOne;
} else if (changedVar == self.varTwo) {
self.varOne = self.varTwo;
}
self.varOneClone = self.varOne;
self.varTwoClone = self.varTwo;
};
self.intervalID = setInterval(function() {
if (self.varOne != self.varTwo) {
if (self.varOne != self.varOneClone) {
self.onChange(self.varOne);
} else if (self.varTwo != self.varTwoClone) {
self.onChange(self.varTwo);
}
}
}, self.interval);
self.clearUpdate = function() {
clearInterval(intervalID);
};
self.changeUpdate = function(newInterval) {
self.interval = newInterval;
clearInterval(intervalID);
self.intervalID = setInterval(function() {
if (self.varOne != self.varTwo) {
if (self.varOne != self.varOneClone) {
self.onChange(self.varOne);
} else if (self.varTwo != self.varTwoClone) {
self.onChange(self.varTwo);
}
}
}, self.interval);
};
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Glue</title>
</head>
<body>
<input id="input" type="text"></input>
<p id="output"></p>
<script>
var input = document.getElementById("input");
var output = document.getElementById("ouput");
var glue = new glue(input, output, 60);
</script>
</body>
</html>
Thanks for your help!
There are few problems that you could fix, as you said, you're using this everywhere. this might not always point to the same object in some context so if you want to use the same object, you could use a variable accessible from the scope.
Usually, people use a variable named self:
var self = this
Then the self variable should be used everywhere where you want to access specifically that object. So in your onChange and setInterval, it would be a better idea to access this by using the self object.
One other way, would be to instead bind a bounded function. In this case, the this object will be the one you bound the function to.
this.onChange = (function () {
// here this will be equal to context
}).bind(context)
In this case, you can set context to this and within the function you can still use this without worrying which object will be this.
You can also make sure to call method using this.func.call(this, params...) or this.func.apply(this, paramArray).
There are a lot of ways to fix this, but if you search about bind, apply and call. It will be enough to understand how to make more complex construction for your code.
To give you an idea of how bind works, take this example:
function bind(method, obj) {
// Create a callable
return function () {
// Pass the arguments to the method but use obj as this instead
return method.apply(obj, arguments);
}
}
function func(a, b, c) {
console.log(this, a, b, c)
}
var bound1 = bind(func, {a: 1})
var bound2 = bind(func, {a: 2})
func(1,2,3)
bound1(3,4,5)
bound2(6,7,8)
You'll see that when func isn't called, this defaults to window. But in case of bound1 and bound2, it will be using the second parameter of bind.
All that to say that you can control which object will be used as this but if you don't specify which object is going to be used, then you might end up using window as this like in a setInterval. In other words, the keyword this isn't scoped like other variables. It depends of the context, not of its place in the code.
The problem is that the setInterval callback is made in a different context, so this will no longer be your glue object. Since you're running within a browser, it will be the window object. I'm pretty sure that all the other times you use this, it is referencing the correct object.
There are a few options to handle this. The first is to use the .bind() method. It is definitely the cleanest, and requires the least amount of "tweaking". However, it's not supported by IE8. Hopefully you don't have to support that browser, considering MS has dropped support for it, except for in embedded systems. Here's how it would work:
this.intervalID = setInterval(function(self) {
if (this.varOne != this.varTwo) {
if (this.varOne != this.varOneClone) {
this.onChange(this.varOne);
} else if (this.varTwo != this.varTwoClone) {
this.onChange(this.varTwo);
}
}
}.bind(this), this.interval);
Another option is to create a variable that holds the value of this before you call setInterval and then rely on the closure to give you access to that variable:
function glue(varOne, varTwo, interval = 60) {
var self = this;
//...
this.intervalID = setInterval(function() {
if (self.varOne != self.varTwo) {
if (self.varOne != self.varOneClone) {
self.onChange(self.varOne);
} else if (self.varTwo != self.varTwoClone) {
self.onChange(self.varTwo);
}
}
}, this.interval);
//...
}
Finally, you could also use an immediately-invoked function to pass in the value of this without creating a closure:
this.intervalID = setInterval((function(self) {
return function() {
if (self.varOne != self.varTwo) {
if (self.varOne != self.varOneClone) {
self.onChange(self.varOne);
} else if (self.varTwo != self.varTwoClone) {
self.onChange(self.varTwo);
}
}
}
})(this), this.interval);
EDIT:
Everything said above is a problem and the options given for solving it should fix that problem. However, it's one of only a few problems in your code sample.
There's also a problem with the line var glue = new glue(input, output, 60);. You can't have a variable with the same name as a function. If the function is declared first, as it should be in this case, then the variable overwrites it, so the function essentially no longer exists by the time you call new glue(). This is why you are getting the glue is not a constructor error.
I see that in your jsbin you've changed the variable name to tape. That fixes the problem. However, jsbin puts all the code from the JavaScript pane at the bottom of your body. You need the function to be declared before the var tape = new glue(input, output, 60); line, since that line is calling the function. You can tell jsbin where to put the code from the JS pane, by putting %code% where you want it in in the HTML pane. So, if you put a line like <script>%code%</script> before your existing script block, it should fix that. This is totally just a quirk of using jsbin, and won't apply to code you have running in a standalone website (although, even on your standalone site, you need to make sure that the code declaring the glue function comes before the code calling it).
Now, that gets rid of all the errors that are being thrown, but still, the code isn't actually DOING anything. This is because near the beginning of the constructor you have:
this.varOneClone = this.varOne;
this.varTwoClone = this.varTwo;
So varOne starts out equal to varOneClone, and varTwo starts out equal to varTwoClone. The only other place you set them is inside the onChange method, but you only call onChange if varOne != varOneClone or varTwo != varTwoClone. It's like you're saying "Make these 2 values the same, then if they're different, call onChange." Obviously, in that case, onChange is never going to be called.
I realize that it's possible you have more code than you've included here, that IS changing those properties, but I think your goal is to check if the text WITHIN varOne or varTwo has changed, and if so, update the other one, rather than checking if the elements themselves have changed. Since the text can be changed by the user (at least for varOne, since that's an input), it can be changed outside of code. If assumption is correct, you need something like this:
function glue(varOne, varTwo, interval = 60) {
this.varOne = varOne;
this.varTwo = varTwo;
this.varOneCurrentText = this.varOne.value;
this.varTwoCurrentText = this.varTwo.textContent;
this.interval = interval;
this.onChange = function(changedVar) {
if (changedVar == this.varOne) {
this.varTwo.textContent = this.varOneCurrentText = this.varTwoCurrentText = this.varOne.value;
} else if (changedVar == this.varTwo) {
this.varOne.value = this.varOneCurrentText = this.varTwoCurrentText = this.varTwo.textContent;
}
};
this.intervalID = setInterval(function() {
if (this.varOne.value != this.varTwo.textContent) {
if (this.varOne.value != this.varOneCurrentText) {
this.onChange(this.varOne);
} else if (this.varTwo.textContent != this.varTwoCurrentText) {
this.onChange(this.varTwo);
}
}
}.bind(this), this.interval);
//...
}
A couple things to note about this. First, notice that I'm using .value for varOne but .textContent for varTwo. This is because you're passing in a form element (an input) for varOne and a non-form element (a paragraph) for varTwo. These types of elements have different ways of getting their current text. If you can design it so that only form elements will ever be passed in, it will make things easier. But if not, since you probably won't know in advance what type of elements are passed in, you'd need to add a check at the beginning, so you can use the correct property.
Also, while this should work, it would really be better to use events rather than having a continuous loop in the setInterval looking to see if the text has changed. The input has a change event that will be fired anytime its value is changed. You could just update varTwo whenever that event is fired. I don't think there's a similar event for the paragraph element, but you could create a custom event for it. I'm assuming that you're planning on having some other code that will update the text inside the paragraph, since that's not something the user can do directly. If so, then you could fire your custom event at the same time that you update its text. Then when that event is fired, you could update varOne.
I just noticed a typo in a line you have, as well:
var output = document.getElementById("ouput");
The element ID should of course be "output".

clearInterval Not being set

I am trying to create a button that will toggle setInterval/clearInterval. The setInterval will function correctly, but when the button is clicked again, clearInterval is not done. Is this a variable scope issue or a problem with how the functions are setup?
http://jsfiddle.net/BxLps/1/
$(function () {
var int;
var onrepeat;
$('button[id^=temp]').click(function () {
window.id = $(this).attr("value");
var int = setInterval(doAjax, 3000);
if (onrepeat == false) {
$(this).find('i').addClass("fa-spin");
doAjax();
int;
onrepeat = true;
} else {
clearInterval(int);
$(this).find('i').addClass("fa-spin");
onrepeat = false;
}
});
});
function doAjax() {
$.ajax({
type: "GET",
url: "ajax.php",
data: "a=cur-temp&id=" + id,
success: function (msg) {
$("#cur-temp").html(msg);
}
})
};
Is this a variable scope issue?
Yes. You've used var int twice, with the second one introducing a local variable where you did want to access to outer one.
However, you still might get problems with having a single int variable for all the elements with that selector. I have now created an object which stores the interval ids per id of the element on an object, you might as well use an each loop to create an extra variable per element.
Also, your global variable id is horrible, better use a parameter for the doAjax function.
$(function () {
var ints = {};
$('button[id^=temp]').click(function () {
var id = $(this).attr("value");
if (id in ints) {
$(this).find('i').removeClass("fa-spin");
clearInterval(ints[id]);
delete ints[id];
} else {
$(this).find('i').addClass("fa-spin");
doAjax(id);
ints[id] = setInterval(function() {
doAjax(id);
}, 3000);
}
});
});
The real issue is it's creating new intervals each time. Think about it, every "click" is running that code (so it's doing a setInterval).
Solution is to declare int once (and only once) outside the click. Then move the setInterval inside the condition
var int;
var onrepeat;
$('button[id^=temp]').click(function () {
window.id = $(this).attr("value");
if (onrepeat == false) {
$(this).find('i').addClass("fa-spin");
doAjax();
int = setInterval(doAjax, 3000);
onrepeat = true;
} else {
clearInterval(int);
$(this).find('i').addClass("fa-spin");
onrepeat = false;
}
});
Just remove the second declaration of int.
$(function () {
var int;
$('button[id^=temp]').click(function () {
window.id = $(this).attr("value");
int = setInterval(doAjax, 3000); //remove var to prevent new declaration
if (onrepeat == false) {
$(this).find('i').addClass("fa-spin");
doAjax();
int;
onrepeat = true;
} else {
clearInterval(int);
$(this).find('i').addClass("fa-spin");
onrepeat = false;
}
});
});
JS Fiddle: http://jsfiddle.net/9tkU2/
Your problem is the scope of your variable int. You are declaring it inside the function and by the time you think are clearing the interval the original variable int has been destroyed.
so just remove the var from the var int =... you have inside the function
if the problem persists continue to read below.
Ok, I have suffered this same problem too many time and usually I just let it be,
But most times I realize that after clearing interval the interval continues to run, and this might affect the performance of the device (it's like having an infinite loop).
So I did a little bit of research and I found out what the problem was and I wrote a simple code to solve it.
Now when you start an interval (most likely triggered by an event) in most cases, more than one instance of that interval is declared (for whatever reason)...
So when you clear the interval later, you only clear the *top-level interval, and the next level interval sets in.
(top-level might not be the correct word)
So to truly clear the interval I used the method below:
Setting the interval:
if(!timer)
timer =setInterval(myFunction, 1000);
Clearing the interval:
clearInterval(timer);
timer=null;
while (timer!== null){
timer=null;
}
you might decide to clear the interval inside the while loop, but I found that this works for me and it's quite efficient than that.
Make sure you check the scope of the interval variable (i.e timer in the case above)

cannot access function within function in javascript

I need to know what I am doing wrong because I cannot call the internal functions show or hide?
(function()
{
var Fresh = {
notify:function()
{
var timeout = 20000;
$("#notify-container div").get(0).id.substr(7,1) == "1" && (show(),setTimeout(hide(),timeout));
var show = function ()
{
$("body").animate({marginTop: "2.5em"}, "fast", "linear");
$("#notify-container div:eq(0)").fadeIn("slow");
},
hide = function()
{
$("#notify-container div").hide();
}
}//END notify
}
window.Fresh = Fresh;
})();
Fresh.notify();
thanks, Richard
UPDATE
If you wanted to be able to do something like: Fresh.notify.showMessage(), all you need to do is assign a property to the function notify:
var Fresh = {notify:function(){return 'notify called';}};
Fresh.notify.showMessage = function () { return this() + ' and showMessage, too!';};
Fresh.notify();//notify called
Fresh.notify.showMessage();//notify called and showMessage, too!
This will point to the function object here, and can be called as such (this() === Fresh.notify();). That's all there is too it.
There's a number of issues with this code. First of all: it's great that you're trying to use closures. But you're not using them to the fullest, if you don't mind my saying. For example: the notify method is packed with function declarations and jQuery selectors. This means that each time the method is invoked, new function objects will be created and the selectors will cause the dom to be searched time and time again. It's better to just keep the functions and the dom elements referenced in the closure scope:
(function()
{
var body = $("body");
var notifyDiv = $("#notify-container div")[0];
var notifyDivEq0 = $("#notify-container div:eq(0)");
var show = function ()
{
body.animate({marginTop: "2.5em"}, "fast", "linear");
notifyDivEq0.fadeIn("slow");
};
var hide = function()
{//notifyDiv is not a jQ object, just pass it to jQ again:
$(notifyDiv).hide();
};
var timeout = 20000;
var Fresh = {
notify:function()
{
//this doesn't really make sense to me...
//notifyDiv.id.substr(7,1) == "1" && (show(),setTimeout(hide,timeout));
//I think this is what you want:
if (notifyDiv.id.charAt(6) === '1')
{
show();
setTimeout(hide,timeout);//pass function reference
//setTimeout(hide(),timeout); calls return value of hide, which is undefined here
}
}//END notify
}
window.Fresh = Fresh;
})();
Fresh.notify();
It's hard to make suggestions in this case, though because, on its own, this code doesn't really make much sense. I'd suggest you set up a fiddle so we can see the code at work (or see the code fail :P)
First, you're trying to use show value when it's not defined yet (though show variable does exist in that scope):
function test() {
show(); // TypeError: show is not a function
var show = function() { console.log(42); };
}
It's easily fixable with moving var show line above the point where it'll be called:
function test() {
var show = function() { console.log(42); };
show();
}
test(); // 42
... or if you define functions in more 'traditional' way (with function show() { ... } notation).
function test() {
show();
function show() { console.log(42); };
}
test(); // 42
Second, you should use this instead:
... && (show(), setTimeout(hide, timeout) );
... as it's the function name, and not the function result, that should be passed to setTimeout as the first argument.
You have to define show and hide before, also change the hide() as they said.
The result will be something like this:
(function()
{
var Fresh = {
notify:function()
{
var show = function()
{
$("body").animate({marginTop: "2.5em"}, "fast", "linear");
$("#notify-container div:eq(0)").fadeIn("slow");
},
hide = function()
{
$("#notify-container div").hide();
},
timeout = 20000;
$("#notify-container div").get(0).id.substr(7,1) == "1" && ( show(), setTimeout(hide,timeout) );
}//END notify
}
window.Fresh = Fresh;
})();
Fresh.notify();
I think order of calling show , hide is the matter . I have modified your code . It works fine . Please visit the link
http://jsfiddle.net/dzZe3/1/
the
(show(),setTimeout(hide(),timeout));
needs to at least be
(show(),setTimeout(function() {hide()},timeout));
or
(show(),setTimeout(hide,timeout));

Write a wrapper object in Javascript

First off, let me apologize if my question isn't worded correctly - I'm not a professional coder so my terminology might be weird. I hope my code isn't too embarrassing :(
I have a fade() method that fades an image in and out with a mouse rollover. I would like to use a wrapper object (I think this is the correct term), to hold the image element and a few required properties, but I don't know how to accomplish this. fade() is called from the HTML, and is designed to be dropped into a page without much additional setup (so that I can easily add new fading images to any HTML), just like this:
<div id="obj" onmouseover="fade('obj', 1);" onmouseout="fade('obj', 0);">
The fade(obj, flag) method starts a SetInterval that fades the image in, and when the pointer is moved away, the interval is cleared and a new SetInterval is created to fade the image out. In order to save the opacity state, I've added a few properties to the object: obj.opacity, obj.upTimer, and obj.dnTimer.
Everything works okay, but I don't like the idea of adding properties to HTML elements, because it might lead to a future situation where some other method overwrites those properties. Ideally, I think there should be a wrapper object involved, but I don't know how to accomplish this cleanly without adding code to create the object when the page loads. If anyone has any suggestions, I would greatly appreciate it!
Here's my fader method:
var DELTA = 0.05;
function fade(id, flag) {
var element = document.getElementById(id);
var setCmd = "newOpacity('" + id + "', " + flag + ")";
if (!element.upTimer) {
element.upTimer = "";
element.dnTimer = "";
}
if (flag) {
clearInterval(element.dnTimer);
element.upTimer = window.setInterval(setCmd, 10);
} else {
clearInterval(element.upTimer);
element.dnTimer = window.setInterval(setCmd, 10);
}
}
function newOpacity(id, flag) {
var element = document.getElementById(id);
if (!element.opacity) {
element.opacity = 0;
element.modifier = DELTA;
}
if (flag) {
clearInterval(element.dnTimer)
element.opacity += element.modifier;
element.modifier += DELTA; // element.modifier increases to speed up fade
if (element.opacity > 100) {
element.opacity = 100;
element.modifier = DELTA;
return;
}
element.opacity = Math.ceil(element.opacity);
} else {
clearInterval(element.upTimer)
element.opacity -= element.modifier;
element.modifier += DELTA; // element.modifier increases to speed up fade
if (element.opacity < 0) {
element.opacity = 0;
element.modifier = DELTA;
return;
}
element.opacity =
Math.floor(element.opacity);
}
setStyle(id);
}
function setStyle(id) {
var opacity = document.getElementById(id).opacity;
with (document.getElementById(id)) {
style.opacity = (opacity / 100);
style.MozOpacity = (opacity / 100);
style.KhtmlOpacity = (opacity / 100);
style.filter = "alpha(opacity=" + opacity + ")";
}
}
You are right, adding the handlers in your HTML is not good. You also loose the possible to have several handlers for event attached to one object.
Unfortunately Microsoft goes its own way regarding attaching event handlers. But you should be able to write a small wrapper function to take care of that.
For the details, I suggest you read quirksmode.org - Advanced event registration models.
An example for W3C compatible browsers (which IE is not): Instead of adding your event handler in the HTML, get a reference to the element and call addEventListener:
var obj = document.getElementById('obj');
obj.addEventListener('mouseover', function(event) {
fade(event.currentTarget, 1);
}, false);
obj.addEventListener('mouseout', function(event) {
fade(event.currentTarget, 0);
}, false);
As you can see I'm passing directly a reference to the object, so in you fade method you already have a reference to the object.
You could wrap this in a function that accepts an ID (or reference) and every time you want to attach an event handler to a certain element, you can just pass the ID (or reference) to this function.
If you want to make your code reusable, I suggest to put everything into an object, like this:
var Fader = (function() {
var DELTA = 0.05;
function newOpacity() {}
function setStyle() {}
return {
fade: function(...) {...},
init: function(element) {
var that = this;
element.addEventListener('mouseover', function(event) {
that.fade(event.currentTarget, 1);
}, false);
element.addEventListener('mouseout', function(event) {
that.fade(event.currentTarget, 0);
}, false);
}
};
}())
Using an object to hold your functions reduces pollution of the global namespace.
Then you could call it with:
Fader.init(document.getElementById('obj'));
Explanation of the above code:
We have an immediate function (function(){...}()) which means, the function gets defined and executed (()) in one go. This function returns an object (return {...};, {..} is the object literal notation) which has the properties init and fade. Both properties hold functions that have access to all the variables defined inside the immediate function (they are closures). That means they can access newOpacity and setStyle which are not accessible from the outside. The returned object is assigned to the Fader variable.
This doesn't directly answer your question but you could use the jQuery library. It's simple, all you have to do is add a script tag at the top:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js">
Then your div would look like:
<div id="obj" onmouseover="$('#obj').fadeIn()" onmouseout="$('#obj').fadeOut()">
jQuery will handle all the browser dependencies for you so you don't have to worry about things like differences between firefox and mozilla etc...
If you want to keep your HTML clean, you should consider using JQuery to set up the events.
Your HTML will look like this:-
<div id="obj">
Your JavaScript will look "something" like this:-
$(document).ready(function() {
$("#obj").mouseover(function() {
Page.fade(this, 1);
}).mouseout(function(){
Page.fade(this, 0);
});
});
var Page = new function () {
// private-scoped variable
var DELTA = 0.05;
// public-scoped function
this.fade = function(divObj, flag) {
...
};
// private-scoped function
var newOpacity = function (divObj, flag) {
...
};
// private-scoped function
var setStyle = function (divObj) {
...
};
};
I introduced some scoping concept in your Javascript to ensure you are not going to have function overriding problems.

Categories

Resources