Undefined

T

Tom de Neef

I have following code:
{code}
function initialize(){
prepareHelp(JAARCBIWCL,"Header","Body");
}

function prepareHelp(el,title,txt) {
if (!el) {return}
el.hlpTitle = title;
el.hlpText = txt;
}
{code}

initialize() is called in body.onload.
JAARCBIWCL is a combobox on the form. Sometimes such control is not present
and FF hangs on the prepareHelp function call.
I have solved this by changing that line in initialize to

if (typeof(JAARCBIWCL)!="undefined")
prepareHelp(JAARCBIWCL,"Header","Body");

and that works OK, also when the element is not rendered.
My question is: can I move the test into the body of the prepareHelp
function?
Tom
 
L

Lasse Reichstein Nielsen

Tom de Neef said:
I have following code:
{code}
function initialize(){
prepareHelp(JAARCBIWCL,"Header","Body");
}

function prepareHelp(el,title,txt) {
if (!el) {return}
el.hlpTitle = title;
el.hlpText = txt;
}
{code}

initialize() is called in body.onload.
JAARCBIWCL is a combobox on the form. Sometimes such control is not present
and FF hangs on the prepareHelp function call.

It probably fails and throw an exception rather than hanging (but the
symptom is still that it doesn't continue executing).

Accessing a form element by using its name as a global variable isn't
standardized, and only works in some browsers. Instead you should use
the DOM functions.
I have solved this by changing that line in initialize to

if (typeof(JAARCBIWCL)!="undefined")
prepareHelp(JAARCBIWCL,"Header","Body");

and that works OK, also when the element is not rendered.
My question is: can I move the test into the body of the prepareHelp
function?

function initialize() {
prepareHelp("JAARCBIWCL", "Header", "Body");
}

function prepareHelp(elName, title, text) {
var element = document.getElementById(elName);
if (element) {
// Insert standard warnings against using expando-properties
// on host-objects here.
element.hlpTitle = title;
element.hlpText = txt;
}
}

/L
 
E

Evertjan.

Lasse Reichstein Nielsen wrote on 16 apr 2011 in comp.lang.javascript:
It probably fails and throw an exception rather than hanging (but the
symptom is still that it doesn't continue executing).

Accessing a form element by using its name as a global variable isn't
standardized, and only works in some browsers. Instead you should use
the DOM functions.


function initialize() {
prepareHelp("JAARCBIWCL", "Header", "Body");
}

where initialize() should be called "body.onload=" or after the
construction of the element.
function prepareHelp(elName, title, text) {
var element = document.getElementById(elName);
if (element) {
// Insert standard warnings against using expando-properties
// on host-objects here.
element.hlpTitle = title;
element.hlpText = txt;

text, not txt
 
T

Tom de Neef

Lasse Reichstein Nielsen said:
It probably fails and throw an exception rather than hanging (but the
symptom is still that it doesn't continue executing).

Accessing a form element by using its name as a global variable isn't
standardized, and only works in some browsers. Instead you should use
the DOM functions.


function initialize() {
prepareHelp("JAARCBIWCL", "Header", "Body");
}

function prepareHelp(elName, title, text) {
var element = document.getElementById(elName);
if (element) {
// Insert standard warnings against using expando-properties
// on host-objects here.
element.hlpTitle = title;
element.hlpText = txt;
}
}

Very good. Thank you.
Does your comment "// Insert standard warnings against using
expando-properties on host-objects here." imply that I should not add these
properties?
I do that so that I can show hints on mouse-over, like here:
http://www.qolor.nl/spelling/ww.htm
Is there another way if this is not OK?
Tom



Tom
 
T

Thomas 'PointedEars' Lahn

Tom said:
Does your comment "// Insert standard warnings against using
expando-properties on host-objects here." imply that I should not add
these properties?

Yes. For an explanation, see various discussions and, of course, the
ECMAScript Language Specification, Edition 5 Final, section 8.6.2, Object
Internal Properties and Methods. Pay particular attention to the [[Put]]
method.
I do that so that I can show hints on mouse-over, like here:
http://www.qolor.nl/spelling/ww.htm

That works well in my currently favorite browser, but is doomed to fail
nevertheless thanks to the excessive host object augmentation and lack of
proper feature tests to begin with. They also became victim of the common
addEventListener-attachEvent-equivalence misconception.
Is there another way if this is not OK?

Yes, several.


PointedEars
 
L

Lasse Reichstein Nielsen

Tom de Neef said:
Very good. Thank you.
Does your comment "// Insert standard warnings against using
expando-properties on host-objects here." imply that I should not add these
properties?

It'll probably work, but there is no guarantee. Host objects,
including DOM objects, doesn't have to follow the same rules as your
own objects.
I do that so that I can show hints on mouse-over, like here:
http://www.qolor.nl/spelling/ww.htm
Is there another way if this is not OK?

I would put the text in a separate dictionary object, e.g., indexed by
the element name:
var helpDictionary = {
JAARBIWCL: { title: "Header", text: "Body" }
};
and then where you need it, instead of doing
element.hlpTitle
use
helpDictionary[element.name].title

/L
 
T

Thomas 'PointedEars' Lahn

Lasse said:
I would put the text in a separate dictionary object, e.g., indexed by
the element name:

That should be _ID_.
var helpDictionary = {
JAARBIWCL: { title: "Header", text: "Body" }
};
and then where you need it, instead of doing
element.hlpTitle
use
helpDictionary[element.name].title

The `title' attribute of the element could be (re)used as well, allowing for
a help feature that degrades gracefully and conforms with accessibility.


PointedEars
 
T

Tom de Neef

Thomas 'PointedEars' Lahn said:
Lasse said:
I would put the text in a separate dictionary object, e.g., indexed by
the element name:

That should be _ID_.
var helpDictionary = {
JAARBIWCL: { title: "Header", text: "Body" }
};
and then where you need it, instead of doing
element.hlpTitle
use
helpDictionary[element.name].title

The `title' attribute of the element could be (re)used as well, allowing
for
a help feature that degrades gracefully and conforms with accessibility.

Thank you all.
I have implemented the dictionary as an array of records and it works as
intended.
The help can be turned off. There will be other - in depth - help via the
menu.
Gracefull degradation is not necessary in this case, albeit a good
user-oriented approach in general.
Tom
 
L

Lasse Reichstein Nielsen

Thomas 'PointedEars' Lahn said:
That should be _ID_.

Not if it's the name attribute that holds the key.
In this case, we are talking form controls, assumably ones that are
to be submitted, so they will have a name property.
They may or may not have an id property that may or may not be the
same as the control name.
It might even be a feature to have the same help on all the elements
that share the control name.
var helpDictionary = {
JAARBIWCL: { title: "Header", text: "Body" }
};
and then where you need it, instead of doing
element.hlpTitle
use
helpDictionary[element.name].title

The `title' attribute of the element could be (re)used as well, allowing for
a help feature that degrades gracefully and conforms with accessibility.

Absolutely. I assumed this was in addition to the element title.
/L
 
T

Thomas 'PointedEars' Lahn

Lasse said:
Not if it's the name attribute that holds the key.
In this case, we are talking form controls, assumably ones that are
to be submitted, so they will have a name property.
They may or may not have an id property that may or may not be the
same as the control name.
It might even be a feature to have the same help on all the elements
that share the control name.

Assumptions, assumptions … If I were to make an assumption about form
controls, it would be that each one has its own purpose and that therefore
the help displayed for each one would be *different*, *regardless* of the
`name' attribute value.


PointedEars
 
D

Dr J R Stockton

In comp.lang.javascript message <[email protected]
I have following code:
{code}
function initialize(){
prepareHelp(JAARCBIWCL,"Header","Body");
}

function prepareHelp(el,title,txt) {
if (!el) {return}
el.hlpTitle = title;
el.hlpText = txt;
}
{code}

initialize() is called in body.onload.
JAARCBIWCL is a combobox on the form. Sometimes such control is not present
and FF hangs on the prepareHelp function call.
I have solved this by changing that line in initialize to

if (typeof(JAARCBIWCL)!="undefined")
prepareHelp(JAARCBIWCL,"Header","Body");

and that works OK, also when the element is not rendered.
My question is: can I move the test into the body of the prepareHelp
function?

You have not said anything about what the error console said - even if
it said nothing, that is important. Nor have you said which version of
Firefox, and which OS. When testing code in Firefox 3, always have what
menu "Tools, error console" gives visible on screen, unless using
something better; Firefox 4 *ought* to have something similar.

Even if the message itself is incomprehensible, the line number is
generally useful.


Without testing, ISTM that the failure is before making the call, and is
that your Firefox JavaScript has never heard of JAARCBIWCL in that
context. There is a real difference between "never heard of it" and "I
can see nothing written there", the latter being value undefined.

You can perhaps get round it by passing the literal string "JAARCBIWCL",
which necessarily exists, and using that as an index within the
function. If A is an Object, ISTM that A, where S is any string,
always gives a value, possibly the value undefined.
 
T

Tom de Neef

Thomas 'PointedEars' Lahn said:
Assumptions, assumptions . If I were to make an assumption about form
controls, it would be that each one has its own purpose and that therefore
the help displayed for each one would be *different*, *regardless* of the
`name' attribute value.
In my case that is the way it is. A mouse-over text box is specific for a
control and there is one for every control on every form.
The forms are generated server side, by IntraWeb. It gives every control a
name and a related id. So I can use both and then id seems the better
choice.
Tom
 
T

Tom de Neef

Dr J R Stockton said:
... the failure is before making the call, and is
that your Firefox JavaScript has never heard of JAARCBIWCL in that
context.

Thanks for your response.
My problem is solved, but the question remains. I rely on another script to
define JAARCBIWCL and others. And I want to protect my code against that.
Any function call with JAARCBIWCL as argument will raise an exception, so I
can't move the test inside the function. To get around that, you can use
if (typeof(JAARCBIWCL)!="undefined") foo(JAARCBIWCL);
if (typeof(MONTHCBIWCL)!="undefined") foo(MONTHCBIWCL);
if (typeof(DAYCBIWCL)!="undefined") foo(DAYCBIWCL);
etc.
or put the function calls in try except blocks.

These approaches work but they did not appeal. Hence my question about
alternatives. The solution (to use the element.id instead of the element) is
practical. But as I said, it does not answer the underlying question about
how to elegantly handle the situation where a variable can be undefined
(because another script did not run).
Tom
 
L

Lasse Reichstein Nielsen

Tom de Neef said:
These approaches work but they did not appeal. Hence my question about
alternatives. The solution (to use the element.id instead of the element) is
practical. But as I said, it does not answer the underlying question about
how to elegantly handle the situation where a variable can be undefined
(because another script did not run).

In that case, the typeof test is actually the best thing to do.
It's the safe way to detect whether a variable exists without throwing
an exception if it doesn't. It beats a try/catch wrapper in readability
too.

Ofcourse, it doesn't distinguish a non-existing variable from one holding
the undefined value, but in your case, I guess both would lead to failures
anyway.

If the variable is global, you can also try getting a reference to the
global object, and test it for having the property you want, i.e.,
...
var global = function(){return this;}();
if ("JAARCBIWCL" in global) { ... }
I prefer the typeof test to treating the global object as an object.

/L
 
T

Thomas 'PointedEars' Lahn

Tom said:
"Thomas 'PointedEars' Lahn" schreef […]:
Lasse said:
var helpDictionary = {
JAARBIWCL: { title: "Header", text: "Body" }
};
and then where you need it, instead of doing
element.hlpTitle
use
helpDictionary[element.name].title

The `title' attribute of the element could be (re)used as well, allowing
for a help feature that degrades gracefully and conforms with
accessibility.

Thank you all.

You're welcome.
I have implemented the dictionary as an array of records and it works as
intended.

What is "an array of records" for you?


PointedEars
 
T

Tom de Neef

Thomas 'PointedEars' Lahn said:
What is "an array of records" for you?

As below. I am a Pascal man; my translation of concepts to js will often be
(formally) incorrect.
I don't mind to be corrected/educated. However, this is my last post before
I go on holiday. It will be weeks before I see an answer.
Tom

var hlpDictionary = new Array();

function hlpRecord(title,txt) {
// creator for an element of hlpDictionary
this.hlpTitle = title;
this.hlpText = txt;
this.hlpColor = nextColor();
}

function prepareHelp(id,title,txt) {
// based on known id of the control
// prepare for mouseover help: store title & text
// to be called for all elements with help via AddToInitProc in IW
hlpDictionary[id] = new hlpRecord(title,txt)
}
 
T

Thomas 'PointedEars' Lahn

Tom said:
"Thomas 'PointedEars' Lahn" […] schreef […]:
What is "an array of records" for you?

As below. I am a Pascal man; my translation of concepts to js will often
be (formally) incorrect.
I don't mind to be corrected/educated. […]

var hlpDictionary = new Array();

function hlpRecord(title,txt) {
// creator for an element of hlpDictionary
this.hlpTitle = title;
this.hlpText = txt;
this.hlpColor = nextColor();
}

function prepareHelp(id,title,txt) {
// based on known id of the control
// prepare for mouseover help: store title & text
// to be called for all elements with help via AddToInitProc in IW
hlpDictionary[id] = new hlpRecord(title,txt)
}

Given that element IDs cannot be numeric (that would be an [X]HTML syntax
error), you are _not_ using "an array of records". You are using an object
as container for `hlpRecord' instances (which really should be `HlpRecord'
or `HelpRecord', referring to a constructor.) The object's properties with
non-numeric name that you are setting allow access to the referred
instances.

Therefore, you should use `new Object()' or simply `{}' instead, unless you
need Array methods (which does not appear to be so here):

var hlpDictionary = {};

There is also the possibility to skip prepareHelp():

var hlpDictionary = {
foo: new Helprecord('x', 'y'),
bar: …
};

or even skip the constructor altogether:

var hlpDictionary = {
foo: {hlpTitle: 'baz', hlpText: 'bla', color: nextColor()},
bar: …
};

In any case, you might want to consider giving the properties of `hlpRecord'
(or whatever) instances simpler names:

this.title = title;

is allowed, for example.
[…] However, this is my last post before I go on holiday. It will be weeks
before I see an answer.

Never mind, other people might benefit from answers while you are away :)

Happy holiday!


PointedEars
 

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

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,073
Latest member
DarinCeden

Latest Threads

Top