IE6: setInterval, this==window arrgh

  • Thread starter Richard A. DeVenezia
  • Start date
R

Richard A. DeVenezia

At line
this.timerId = setInterval (function(){this.step()}, 100)
I get error dialog
Error:Object doesn't support this property or method.
If I change it to
this.timerId = setInterval (function(){this==window}, 100)
I see true, the sad fact that 'this' is window and not an anim.

What are some proper ways ?
I would like to avoid
this.timerId = setInterval ("Anim.step ( ' "+ this.o.id + " ' ) ", 100)
and avoiding the need for a global hash array (Anim.anims) to keep tracking
of my anims (key:td id, value:anim instance) that would have to be looked up
during each step.

--------
function X (s,cp) {
// cp - cell id prefix
document.write (
'<P>' + s + '</P>'
+'<TABLE BORDER="1">'
+ '<TR>'
+ '<TD ID="cell_1"'
+ ' onMouseOver="X.over(this)"'
+ ' onMouseOut="X.out(this)"'
+ '>this cell gets handled</TD>'
+ '<TD ID="cell_2"'
+ ' onMouseOver="X.over(this)"'
+ ' onMouseOut="X.out(this)"'
+ '>me too</TD>'
+ '</TR></TABLE>'
)

}

function X.over (o) { o.style.background='Black' }
function X.out (o) {
o.anim = new Anim(o);
o.anim.start();
}

var Anim = function (o)
{
this.o = o
this.count=0
}
Anim.prototype.start = function ()
{
this.step();
this.timerId = setInterval (function(){this.step()}, 100)
}
Anim.prototype.step = function ()
{
this.count += 4
if (this.count > 15)
this.stop()
else {
level = anim.count * 16 - 1
anim.o.style.background = 'rgb('+level+','+level+','+level+')'
}
}
Anim.prototype.stop = function ()
{
clearTimeout (this.timerId)
}
-----
 
R

Richard A. DeVenezia

Richard A. DeVenezia said:
At line
this.timerId = setInterval (function(){this.step()}, 100)
I get error dialog
Error:Object doesn't support this property or method.
If I change it to
this.timerId = setInterval (function(){this==window}, 100)
I see true, the sad fact that 'this' is window and not an anim.

What are some proper ways ?
I would like to avoid
this.timerId = setInterval ("Anim.step ( ' "+ this.o.id + " ' ) ", 100)
and avoiding the need for a global hash array (Anim.anims) to keep tracking
of my anims (key:td id, value:anim instance) that would have to be looked up
during each step.

Bad form writing to myself ?
I found the answer to be that setinterval function (anonymous or otherwise)
can't use this reference but can use local copy of object's this.
http://www.faqts.com/knowledge_base/view.phtml/aid/2311/fid/128


X.Anim.prototype.start = function ()
{
dit = this // homage to Nederlanders
dit.step()
this.timerId = setInterval (function() {dit.step()}, 100)
}



-----
function X (s) {
document.write (
'<P>' + s + '</P>'
+'<TABLE BORDER="1">'
+ '<TR>'
+ '<TD ID="cell_1"'
+ ' onMouseOver="X.over(this)"'
+ ' onMouseOut="X.out(this)"'
+ '>this cell gets handled</TD>'
+ '<TD ID="cell_2"'
+ ' onMouseOver="X.over(this)"'
+ ' onMouseOut="X.out(this)"'
+ '>me too</TD>'
+ '</TR></TABLE>'
)

}

function X.over (o) { o.style.background='Black' }
function X.out (o) {
o.anim = new X.Anim(o);
o.anim.start();
}

X.Anim = function (o)
{
this.o = o
this.count=0
}

X.Anim.prototype.start = function ()
{
dit = this
dit.step()
this.timerId = setInterval (function() {dit.step()}, 100)
}
X.Anim.prototype.step = function ()
{
anim = this

anim.count++
if (anim.count > 16)
anim.stop()
else {
level = anim.count * 16 - 1
anim.o.style.background = 'rgb('+level+','+level+','+level+')'
}
}
X.Anim.prototype.stop = function ()
{
clearTimeout (this.timerId)
}

X('Hello')
 
D

Dom Leonard

Richard said:
function X.over (o) { o.style.background='Black' }
function X.out (o) {
o.anim = new X.Anim(o);
o.anim.start();
}
These declarations are generating errors in Mozilla ("X.over" and
"X.out" are not identifiers and failing ECMA syntax checks for a
function declaration)

X.over =function (o) { o.style.background='Black' }
X.out = function (o) {
o.anim = new X.Anim(o);
o.anim.start();
}

seems to fix it,

Cheers,
Dom
 
R

Richard A. DeVenezia

Dom Leonard said:
These declarations are generating errors in Mozilla ("X.over" and
"X.out" are not identifiers and failing ECMA syntax checks for a
function declaration)

X.over =function (o) { o.style.background='Black' }
X.out = function (o) {
o.anim = new X.Anim(o);
o.anim.start();
}

seems to fix it,

Cheers,
Dom

Dom: Thank you!

I've another question now....

I want to 'stuff' some information into the <td> i am dynamically
generating, so that it will be available to the event handler without having
to pass the value in the handler invocation.

Both these work in IE

A. <TD onmouseover='Over(this)' style="myProperty:myValue">
or
B. <TD onmouseover='Over(this)' myProperty="myValue">

and in the handler

A. function Over(o) { alert (o.style.myProperty) } // shows myValue
B. function Over(o) { alert (o.myProperty) } // shows myValue

Wondering if both techniques would work in most other browsers and if not
would A. version (style version) be more widespread applicable ?

Would it be possible to include an object literal or object reference in
generated TD ?
 
L

Lasse Reichstein Nielsen

Richard A. DeVenezia said:
I want to 'stuff' some information into the <td> i am dynamically
generating, so that it will be available to the event handler without having
to pass the value in the handler invocation.

Why not pass it? It won't take more space than putting it in the tag
in other ways, and probably will take less.
Both these work in IE

And neither work in Opera 7 or Mozilla.
However, using getAttribute works in all three:
---
<table><tr>
<TD onmouseover='Over(this)' myProperty="myValue">X</td>
</tr></table>
<script type="text/javascript">
A. <TD onmouseover='Over(this)' style="myProperty:myValue">

A browser *should* ignore CSS properties that it doesn't understand.
This is illegal CSS
B. <TD onmouseover='Over(this)' myProperty="myValue">

This is illegal HTML by any HTML standard.

The DOM doesn't have to make attributes available as properties
of the object, except those specifically mentioned in the DOM
specification (e.g. id and name). It doesn't have to use the same
name as the attribute (e.g., class/className). It doesn't have
to make the attribute available as a string (e.g., style and any
on said:
Wondering if both techniques would work in most other browsers and if not
would A. version (style version) be more widespread applicable ?

From my sample base, I would say no.
Would it be possible to include an object literal or object reference in
generated TD ?

Easy.
<td onmouseover='Over(this,{x:42,y:10})'>
or
<td onmouseover='Over(this,objRef)'>
or
<td onmouseover='var foo=new Object();Over(this,foo);'>

It really is *much* simpler to put what you need directly in the
onmouseover javascript, than to put it into an attribute, and then
have to parse it.

/L
 
R

Richard A. DeVenezia

Richard A. DeVenezia said:
X.Anim.prototype.start = function ()
{
dit = this
dit.step()
this.timerId = setInterval (function() {dit.step()}, 100)
}
X.Anim.prototype.step = function ()
{
anim = this

anim.count++
if (anim.count > 16)
anim.stop()
else {
level = anim.count * 16 - 1
anim.o.style.background = 'rgb('+level+','+level+','+level+')'
}
}

dit=this should be var dit=this
anim=this should be var anim=this,
level=... should be var level=...
 
R

Richard A. DeVenezia

Lasse, I applaud you and other contributors excellent discourse and the
lists collective willingness to help others. Keep up the great work.
[worthy of top-post]

Lasse Reichstein Nielsen said:
Why not pass it? It won't take more space than putting it in the tag
in other ways, and probably will take less.

Yup, see that now. Can't help but think these ideas haven't been hashed to
death in the past, I just can't seem to find such prior threads.
Easy.
<td onmouseover='Over(this,{x:42,y:10})'>
or
<td onmouseover='Over(this,objRef)'>

But in keeping with oo flavour, suppose each cell had 10 runtime controlling
factors determined at table generation time; the run time data can be
effectively encapsulated in a 'parametric' object with 10 properties.
I would prefer not to pass the 10 factors, but rather the reference to the
object containing the ten properties.

So, then, is it possible to document.write html that would pass a function
var to the handler

i.e.
function foo ()
{
....
var adjunctData = { a:1, b:2, c:3, ..., j:10 }
document.write ('... <TD onmouseout="Out(this, adjunctData)" > text
</TD>...')
....
}
won't work since adjunctData would have to be global scope. I don't want to
pollute global space.

I don't think that
document.write ('... <TD onmouseout="Out(this, ' + adjunctData + ')" > text
</TD>...')
would work either. If I recall in IE adjunctData works out to something like
[Object] object

document.write ('... <TD onmouseout="Out(this, ' + function () { return
adjunctData } + ')" > text </TD>...')
might work (will try soon)? If so, at what number of 'outs' would any
appreciable degradation in browser reponse/resource utilization occur?

versus

adding and managing a function property of type array that holds references
to the 'parametric' objects and pass the index into this array

X = function () {
....
var adjunctData = { a:1, b:2, c:3, ..., j:10 }
var index = X.adjunctDatas.push ( adjunctDatas )
document.write (... <TD onmouseout="X.Out(this," + index + ")" > text
</TD>...
....
}
X.adjunctDatas = []

X.Out = function (o, index)
{
var adjunctData = X.adjunctDatas[index]
....
}


Of these is there a 'best of breed' technique, or is it more a matter of
personal style ?
 
L

Lasse Reichstein Nielsen

Richard A. DeVenezia said:
So, then, is it possible to document.write html that would pass a function
var to the handler

i.e.
function foo ()
{
...
var adjunctData = { a:1, b:2, c:3, ..., j:10 }
document.write ('... <TD onmouseout="Out(this, adjunctData)" > text
</TD>...')
...
}
won't work since adjunctData would have to be global scope. I don't want to
pollute global space.

Exactly.

This is actually similar to the problems you get when using strings
as arguments to setTimeout or using the Function constructor function.
The text that you write is "just a string", and cannot capture
the variables in the current scope the way a closure can.

What you can do, is to assign the onmouseout handler from Javascript
instead:

var adjunctData = { a:1, b:2, c:3, ..., j:10 }
document.write('<td id="foo"> .... </td>');
document.getElementById("foo").onmouseout =
function () {
Out(this,adjunctData);
};

This avoids Javascript creating more scripts as strings, which I
personlly don't like.
I don't think that
document.write ('... <TD onmouseout="Out(this, ' + adjunctData + ')" > text
</TD>...')
would work either. If I recall in IE adjunctData works out to something like
[Object] object

Yes. That would only work if the toString method returned a literal
that evaluates to the same value ... and that is equivalent to including
the entire object in each location.
document.write ('... <TD onmouseout="Out(this, ' + function () { return
adjunctData } + ')" > text </TD>...')
might work (will try soon)?

Probably not. The function is still converted to a string. That string
is then parsed again as Javascript, but in a different scope. The
scope is lost because you go through a string. Strings have no notion
of scope or evaluation context.
If so, at what number of 'outs' would any
appreciable degradation in browser reponse/resource utilization occur?

That depends on the garbage collectior. The functions you create are
lost immediately, and can be garbage collected.

My bet is that if those functions cause a significant drain on
ressources, your page is too large to build with DHTML anyway.
adding and managing a function property of type array that holds references
to the 'parametric' objects and pass the index into this array
....

This is simply the simplest way of not polluting the global namescape:
Create *one* global variable, put an object (e.g., a function) in it,
and store the rest of your variables in that object.

Building an array, and using an integer as index, is not different from
indexing an object by name ... it's just easier to come up with the
names :)
Of these is there a 'best of breed' technique, or is it more a matter of
personal style ?

Personal style goes a long way :)

I would try to not write scripts. Javascript writing Javascript just
seems like a waste to me. Why build a string and the parse it again,
when I can just write Javascript directly.

/L
 
R

Richard A. DeVenezia

Subject has been changed...

Lasse Reichstein Nielsen said:
What you can do, is to assign the onmouseout handler from Javascript
instead:

var adjunctData = { a:1, b:2, c:3, ..., j:10 }
document.write('<td id="foo"> .... </td>');
document.getElementById("foo").onmouseout =
function () {
Out(this,adjunctData);
};

I like this solution very much and is quite in step with my concept that the
adjunctData really belongs to the cell.
I don't like having to id and get, but in this approach those steps are
unavoidable.

As you stated prior it's not good practice or valid to add custom properties
to HTML tags, but how about post rendering of the HTML ? This works, but is
adding properties to existing window objects.

document.write('<td id="foo" onmouseout="Out(this)"> .... </td>');
document.getElementById("foo").adjunctData = { a:1, b:2, c:'I will appear',
d:4, e:5, f:6 }

Out = function (o)
{
o.innerHTML = o.adjunctData.c // cell innerHTML changes to 'I will
appear'
}

This avoids Javascript creating more scripts as strings, which I
personlly don't like.

concur


Probably not. The function is still converted to a string. That string
is then parsed again as Javascript, but in a different scope. The
scope is lost because you go through a string. Strings have no notion
of scope or evaluation context.

didn't work, the return was undefined ... unless it was a global ref
...

This is simply the simplest way of not polluting the global namescape:
Create *one* global variable, put an object (e.g., a function) in it,
and store the rest of your variables in that object.

Building an array, and using an integer as index, is not different from
indexing an object by name ... it's just easier to come up with the
names :)

I've done this on other pages, but get annoyed I have to id something I
already have.
Personal style goes a long way :)

After a fair amount of experimentation, I found I could build the table
without document.writing any HTML at all!
Not sure how cross-browser this is, but works for my windows IE6 and is spot
on for my personal style.
Again the question of propriety and validness is raised regarding adding
properties to window elements. I don't know.

function X (s) {
this.abc = 123

document.write (
'<P>' + s + '</P>'
+'<TABLE ID="myTable" BORDER="1" CELLPADDING="10"></TABLE>'
)

table = window.myTable;
// is document.getElementById really needed if window.<id> or
window['<id>'] seems to always work ?

row = table.insertRow (0);
cell = row.insertCell (0);

cell.innerHTML = 'Show me'
cell.foo = '123'
cell.adjunctData = { a:1, b:2, c:'I will appear', d:4, e:5, f:6 }
cell.onmouseover = function (EventSource) { X.over (this) } // during
invocation context this is the cell
}

X.over = function (o)
{
o.innerHTML = o.adjunctData.c
}

X('Hello')
 
R

Richard Cornford

A browser *should* ignore CSS properties that it doesn't
understand. This is illegal CSS
<snip>

There is some unusual Opera 7 (up to 7.11 at least) behaviour that makes
setting and reading any expando properties on a style object extremely
risky. The style object's property name resolving strategy seems to be
based on a HashTable with a very simple algorithm. Sufficient to
distinguish all of the CSS properties from each other but such that
trying to set a non-CSS property may actually end up assigning a value
to an entirely unintended existing property.

For example, on Opera 7.11 setting the "position" property and then
reading the non-CSS property "abbr" will return the value that was just
set. Similarly setting "abbr" will be interpreted as setting the
"position". Working out which property names would accidentally hash to
the same values as existing CSS properties is also hindered slightly by
the fact that revisions of Opera 7 have shown evidence of slight changes
in the hashing algorithm (probably as CSS support has been expanded).

It would definitely be safest never to add any new properties to a style
object.

Richard.
 
L

Lasse Reichstein Nielsen

Richard A. DeVenezia said:
As you stated prior it's not good practice or valid to add custom properties
to HTML tags, but how about post rendering of the HTML ? This works, but is
adding properties to existing window objects.

document.write('<td id="foo" onmouseout="Out(this)"> .... </td>');
document.getElementById("foo").adjunctData = { a:1, b:2, c:'I will appear',
d:4, e:5, f:6 }

This is quite legal.

The HTML specification is strict - it disallows attributes not in the
specification.

There is nothing in the DOM specification that recommends against
adding properties to DOM node objects. In Javascript, the DOM nodes
are just normal host objects, and they can allow you to add whatever
properties you want. However, as host objects, they could also prevent
it. Host objects are almost completely "implementation dependent" in
the ECMA 262 standard.
After a fair amount of experimentation, I found I could build the table
without document.writing any HTML at all!
Not sure how cross-browser this is, but works for my windows IE6 and is spot
on for my personal style.

You use DOM methods to add rows and cells to the table. While not the
fastest method (I find using document.createElement("td") to be a
little faster in some browsers), it is still a very valid approach.

But, be careful:
document.write (
'<P>' + s + '</P>'
+'<TABLE ID="myTable" BORDER="1" CELLPADDING="10"></TABLE>'

A valid table tag *must* include at least "<tr><td>" (and I would
include the end tags as well). If you care about invalid attributes,
you should also make sure that the HTML you document.write, is valid.
(I would also remove BORDER and CELLPADDING and use CSS instead).
table = window.myTable;
// is document.getElementById really needed if window.<id> or
window['<id>'] seems to always work ?

IE makes named elements available as global variables. Few other
browsers do.
row = table.insertRow (0);
cell = row.insertCell (0);

cell.innerHTML = 'Show me'

Now that you are using DOM, you might as well be consistent:

cell.appendChild(document.createTextNode('Show me'));
cell.foo = '123'
cell.adjunctData = { a:1, b:2, c:'I will appear', d:4, e:5, f:6 }
cell.onmouseover = function (EventSource) { X.over (this) } // during
invocation context this is the cell
}

X.over = function (o)
{
o.innerHTML = o.adjunctData.c

If we know that o contains only one text node:
o.firstChild.nodeValue = o.adjunctData.c;
Otherwise, we must clear out the contents of the node, and write
the new:
while(o.hasChildNodes()) {
o.removeChild(o.lastChild);
}
o.appendChild(document.createTextNode(o.adjunctData.c));

Enjoy
/L
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top