Forum Moderators: open
<script language="JavaScript">
function openMenu(xcoord,ycoord){
if (ycoord < 200){
//td1.innerHTML = ycoord;
table1.style.left = xcoord;
table1.style.top = ycoord;
table1.style.position = 'absolute';
ycoord = ycoord + 1;
setTimeout("openMenu(" +xcoord+","+ycoord+")",10);
}
}
</script>
</head>
<body>
<table border="1" style="position:absolute;left:200px;top:40px;">
<tr>
<td onmouseover="openMenu(0,0)">First Item</td>
</tr>
</table>
<table bgcolor="#dedede" border="1" id="table1" style="position:absolute;left:0px;top:0px;border-collapse:collapse;">
<tr>
<td>test 1st link</td>
</tr>
<tr>
<td>test 2nd link</td>
</tr>
<tr>
<td>test 2nd link</td>
</tr>
</table>
</body>
</html>
=========================================
It should be cut and dry.
1) Add the variable to the function call
<td onmouseover="openMenu(0,0,'table1')">
2) Add the argument to the function
function openMenu(xcoord,ycoord,table_id){
if (ycoord < 200){
//td1.innerHTML = ycoord;
table_id.style.left = xcoord;
table_id.style.top = ycoord;
table_id.style.position = 'absolute';
ycoord = ycoord + 1;
setTimeout("openMenu(" +xcoord+","+ycoord+",table_id)",10);
}
}
I imagine that would do what you want.
I've already been down that road. I gave you only the code that WORKS, without the additional variables. Once the table1, table_id argument var is instituted, it crashes. There are some syntactical differences between what you suggested, and my attempts, but I've tried it both ways without success.
I've written entire apps with this style of coding, so I'm baffled.
I'll post mine anyway. There's a couple of changes.
Esp. that you need to use getElementById, otherwise it'll only work in IE (can't reference elements using id alone)
..and stricter browsers will want "px" on the positions.
-- html --
<td onmouseover="openMenu(0,0,'table1')">First Item</td>-- script --
function openMenu(xcoord,ycoord, elmId)
{
if (ycoord >=200) returnvar style = document.getElementById(elmId).style
style.left = xcoord+"px";
style.top = ycoord+"px";
// style.position = 'absolute'; // X not needed. It's already in the css
ycoord += 1;
setTimeout("openMenu(" +xcoord+","+ycoord+",'"+elmId+"')",10);
}
Here's a different take on it, that avoids those strings.
function openMenu(xcoord,ycoord, elmId)
{
var style = document.getElementById(elmId).style
repeat()
function repeat()
{
ycoord += 1
if (ycoord>=200) return
style.top = ycoord+"px"
setTimeout(repeat,10)
}
}// 1. Inner function has access to outer function's local vars.
// 2. setTimeout can accept a function reference.
The function call itself:
<td onmouseover="openMenu(0,0,table1)">First Item</td>
...shouldn't need single quotes around the table1 object (it works well with that object alone as the argument, if I take away the movement); nor should I need quotes around the table_id reference in the setTimeout() function; should be like this:
setTimeout("openMenu(" +xcoord+","+ycoord+ "," +table_id+ ")",10);
...but it doesn't work either way.
You guys ARE ON THE RIGHT TRACK though. I'm convinced this is a String issue in the setTimeout() call...but I'm really familiar with this type of string/var manipulation and syntax. I know when I figure this out, I'm gonna be really embarrassed...but until then, if anyone has the answer, please share it with me.
Thanks again
(as above)
setTimeout("openMenu(" +xcoord+","+ycoord+ "," +table_id+ ")",10);
(with arbitrarily chosen var values) this will produce:
setTimeout("openMenu(100,200,table1)",10) setTimeout is asked to execute the statement:
openMenu(100,200,table1)// in a global context In those args there is a variable, table1.
In most browsers, that variable is undefined.
In IE it will hold a reference to the right element, but openMenu doesn't take an object reference parameter, it takes an id string.
What you need (if you don't want the nested-function version)is:
setTimeout("openMenu(" +xcoord+","+ycoord+ ",'" +table_id+ "')",10);
No, if you try the substitution you gave me, you'll see it doesn't work.
True, I didn't take the time to test it. If you tried the substitutions Bernard gave, you'll see that they BOTH work.
This works for me:
<script type="text/JavaScript">
function openMenu(xcoord,ycoord,tid){
t = document.getElementById(tid);
if (ycoord < 200){
t.style.left = xcoord;
t.style.top = ycoord;
t.style.position = 'absolute';
ycoord = ycoord + 1;
setTimeout("openMenu("+xcoord+","+ycoord+", '"+tid+"')",10);
}
}
</script>
<td onmouseover="openMenu(0,0,'table1')">First Item</td>
shouldn't need single quotes around the table1 object
You do need the quotes. It is not an object, it is a string. It will not be an object until you use that string in a javascript assignment:
function openMenu(xcoord,ycoord,tid){ // tid is a string
t = document.getElementById(tid); // t is an object
nor should I need quotes around the table_id reference in the setTimeout() function;
Once again, it's just a simple string so it needs quotes
setTimeout("openMenu("+xcoord+","+ycoord+", '"+tid+"')",10);
Notice I put the string variable as the last arg, not the object(t). Why, because the function is expecting a string at first and then creates the object with that string.
Hope that helps straighten things out.
I made 2 changes:
1. Netscape didn't want to move a table today, so I put it in a DIV and moved that instead.
2. When running #1, if you mouseover again strange things start to happen, because the function doubles up. #2 has a facility to block further calls until running has stopped. This can be done to #1 as well, but I think it would require a global variable.
<html>
<head>
<script language="JavaScript">function openMenu(xcoord,ycoord, elmId)
{
if (ycoord >=200) returnvar style = document.getElementById(elmId).style
style.top = ycoord+"px";ycoord += 1;
setTimeout("openMenu(" +xcoord+","+ycoord+",'"+elmId+"')",10);
}function XXopenMenu(xcoord,ycoord, elmId)
{
var elm = document.getElementById(elmId)
if(elm.openMenuRunning) return
elm.openMenuRunning = truerepeat()
function repeat()
{
ycoord += 1
if (ycoord>=200){
elm.openMenuRunning = false
return
}
elm.style.top = ycoord+"px"
setTimeout(repeat,10)
}
}</script>
</head>
<body><table border="1" style="position:absolute;left:200px;top:40px;">
<tr><td onmouseover="openMenu(0,0,'table1')" >First Item</td></tr>
</table><div id="table1" style="position:absolute;left:0px;top:0px;border-collapse:collapse;">
<table bgcolor="#dedede" border="1">
<tr><td>test 1st link</td></tr>
<tr><td>test 2nd link</td></tr>
<tr><td>test 2nd link</td></tr>
</table>
</div></body>
</html>
If it means anything, it's really great knowing there are sharp minds and good people out there willing to help.
Having said that, maybe you can explain the apparently basic principle I'm overlooking (or never learned) here...why can I reference table1 in the function call below without quotes and without getElementByID (I've always used the latter ONLY for Netscape compatibility). This works when I'm simply applying style properties to it. I've removed the extra arguments for demonstration and taken away the movement...the function simply moves the table to the 200px location.
Again...much thanks to you both.
<head>
<script language="JavaScript">
var ycoord=200;
var xcoord=0;
function openMenu(table_id){
table_id.style.left = xcoord;
table_id.style.top = ycoord;
table_id.style.position = 'absolute';
}
</script>
</head>
<body>
<table border="1" style="position:absolute;left:200px;top:40px;">
<tr>
<td onmouseover="openMenu(table1)" >First Item</td><td id="td1"> </td>
</tr>
</table>
<table bgcolor="#dedede" border="1" id="table1" style="position:absolute;left:0px;top:0px;border-collapse:collapse;">
<tr>
<td>test 1st link</td>
</tr>
<tr>
<td>test 2nd link</td>
</tr>
<tr>
<td>test 2nd link</td>
</tr>
</table>
</body>
If your application development has been intranet-based, then you will have been in the nice cosy world of internet explorer (I presume).IE (at present) keeps backward compatibility with it's previous proprietary - sometimes just plain easier - element referencing methods. This does lead to some confusion when moving into cross-browser territory.
I'll just cover elements in general, as there are even more ways of referencing images, and forms/form elements.
<div id="table1">
1. Using the element's id alone (your 'usual practice'):[IE]
table1.style.left This is IE-only ; Still supported.
It can lead to a conflict, when using XB methods.
..........................................................................
Put simply, you might want to put an element into a global variable for easy reference, using the id for a variable name to make things easy ( and emulating your practice):
var table1 = document.getElementById('table1') This will cause an error in IE (only with a global var). For some reason, if you declare the variable first it's OK
var table1
table1 = document.getElementById('table1') document.all.table1
document.all['table1'] // when using variables
document.all('table1') // also accepts ()
Again, IE-only; Still supported..
Every element has an all collection (not just doc), of all the elements it contains. Elements can be referenced by id, name, or source-order index. A collection is returned when elements share the same name.
3. Ref'ing as a member of the document's layers collection:[NS 4]
document.layers.table1
document.layers['table1']
Netscape 4 only; no longer supported
This can only reference
<layer> which is NS-only
<div> only when absolutely positioned
The important thing is that, in the NS4 DOM, each layer/pos:div is a sub-document. So, to ref nested layers, you need to recursively loop through all the layers.
Modern Standard
4. document.getElementById('table1')
IE5+, NS6+, Moz, most other things.
This is the one to use, and we can educate IE4, and NS4 (assuming no nesting) to use it:
// ¦¦ to pipesif(!document.getElementById)
document.getElementById = document.all ¦¦ function(id){return this.layers[id]}
var DHTML = (document.getElementById ¦¦ document.all ¦¦ document.layers);function getObj(nm)
{
if (document.getElementById)
{
this.obj = document.getElementById(nm);
}
else if (document.all)
{
this.obj = document.all[nm];
}
else if (document.layers)
{
this.obj = document.layers[nm];
}
return this.obj;
}function fObj(nm){
this.obj = document.forms[0].elements[nm];
return this.obj;
}
I saved this script as cross_browser_object.js and then pull it in before running any js scripts.
<script type="text/javascript" src="/includes/cross_browser_object.js"></script>
<script type="text/javascript">
//In this script, I can access any object by it's ID like this:
myVar = getObj("id_of_some_element").innerHTML;
myVar2 = getObj("id_of_some_element").style.position;
etc...
//If it's a form element, I use the fObj() function
myVar3 = fObj("name_of_some_form_element").value;
myVar4 = fObj("name_of_some_form_element").checked;
etc...
</script>
There's nothing wrong with having a general function for referencing objects, like getObj, but I was trying to up the ante. There are a couple of features in my method that "up it" a bit.
1. It's more efficient, since the code is only executed once. From then on, calls to getElementById involve no code branching.
2. Allows you to (at least attempt to) write modern standard code.
3. It's a tad shorter.
You have a global variable, DHTML, which you haven't used. The funny thing is that, if NS4 allowed access to the document layers collection via round brackets, then you could use DHTML as an accessor:
var myElm = DHTML('elmId') (I think, since the context,
document., is preserved) I'm not trying to wind you up, but there is an issue with the current form of
getObjand fObj - although you won't notice it when you run them. Since the functions are called globally, the keyword,
this, refers to the window, so obj is being set as a window property (aka global variable). This is a little less efficient, and will conflict you are trying to use a global variable called, obj (unlikely, I know). In both functions, declare
obj at the top as a local var, then remove this..