portable dictionary class

N

nagylzs

Hi All,

Can you show me an example of a working dictionary object that is
portable? I would like to have something like:

d = new PortableDict()

d.setValue('a',12)
d.setValue('b',-3)

subd = new PortableDict()
d.setValue(subd,51)

d.hasKey('a') // true
d.hasKey('c') // false
d.hasKey(subd) // true
d.getValue('a') // 12

etc.

Alternatively, is there a programming scheme that allows me to assign
custom properties/attributes to DOM elements? I can do it with
FireFox, but not with IE - it throws an error telling that the given
attribute is not supported. Which is strange because AFAIK in
JavaScript you can freely modify objects, add attributes and methods
on the fly. But it looks like that in IE, HTML DOM elements are not
real JavaScript objects.

Thanks,

nagylzs
 
T

Thomas 'PointedEars' Lahn

nagylzs said:
Can you show me an example of a working dictionary object that is
portable? I would like to have something like:

d = new PortableDict()

`d' should be declared:

var d = ...
d.setValue('a',12) d.setValue('b',-3)

subd = new PortableDict() d.setValue(subd,51)

d.hasKey('a') // true d.hasKey('c') // false d.hasKey(subd) // true
d.getValue('a') // 12

Why, write it yourself. You can also use an object literal to define the
object (but since you need it portable, that would not be an option,
depending on the degree of portability). You can use type-converting tests
and typeof tests to determine whether the object has the property etc. That
is really beginner's knowledge. Read the FAQ: http://jibbering.com/faq/
Alternatively, is there a programming scheme that allows me to assign
custom properties/attributes to DOM elements? I can do it with FireFox,
but not with IE - it throws an error telling that the given attribute is
not supported.

It would be possible to encapsulate the element object reference in a
property of a user-defined object. That user-defined object would be
native, and so could have any number of user-defined properties.
Which is strange because AFAIK in JavaScript you can freely modify
objects, add attributes and methods on the fly.

That applies to native objects, not to host objects.
But it looks like that in IE, HTML DOM elements are not real JavaScript
objects.

Any DOM object is a host object, not "a real JavaScript object".
J(ava)Script/ECMAScript is only the used interface language. And some
DOMs are more "forgiving", a feature that should not be relied on.


PointedEars
 
N

nagylzs

`d' should be declared:

var d = ...

Unless I want it to be assigned to the Global Object ;-)
Why, write it yourself.

Of course. In fact I already started to write it. However, my problem
is a very common problem. I was hoping that there is a very popular
open source JavaScript library that I could use. I do not want to re-
implement the wheel unless I have to.
That is really beginner's knowledge. Read the FAQ:http://jibbering.com/faq/

I will read that. :)
Thank you,

nagylzs
 
B

Bart Van der Donck

nagylzs said:
Can you show me an example of a working dictionary object that is
portable? I would like to have something like:

d = new PortableDict()

d.setValue('a',12)
d.setValue('b',-3)

subd = new PortableDict()
d.setValue(subd,51)

d.hasKey('a') // true
d.hasKey('c') // false
d.hasKey(subd) // true
d.getValue('a') // 12

It looks like you're a surviving topdown coder :) Seriously, if you're
coming from a non-OO background (BTW, like me), perhaps the following
coding style looks familiar. Most common operations:

var string = 'three'
var numbers = new Object()

// 3 assignment methods
numbers['one'] = 'uno'
numbers.two = 'dos' // previous is better habit
numbers[string] = 'tres'

// delete an entry
delete numbers.two

// walk through
for (var i in numbers) {
document.write ('<br>' + i + ' -> ' + numbers)
}

Hope this helps,
 
T

Thomas 'PointedEars' Lahn

nagylzs said:
Unless I want it to be assigned to the Global Object ;-)

Variables should *always* be declared, of course within the desired context.
Of course. In fact I already started to write it.

Then it would have been wise for you to mention that, and perhaps to post
some snippets of it for review.
However, my problem is a very common problem.

As common as homework assignments are.
I was hoping that there is a very popular open source JavaScript library
that I could use. I do not want to re-implement the wheel unless I have to.

What gave you the idea that this group is about how to use search engines?


PointedEars
 
N

nagylzs

d.setValue('a',12) d.setValue('b',-3)
Then it would have been wise for you to mention that, and perhaps to post
some snippets of it for review.

Here it is. It works on FireFox. It does not work on IE and it does
not throw up the "Error on page" message. :-(

<html>
<head>
<script>

function PortableDict() {
var that = this;
that.keys = new Array();
that.values = new Array();

that.hasKey = function(akey) {
return (that.keys.indexOf(akey)>=0);
}
that.hasValue = function(avalue) {
return (that.values.indexOf(avalue)>=0);
}
that.valueOf = function(akey) {
var idx = that.keys.indexOf(akey);
if (idx>=0) {
return that.values[idx];
} else {
return undefined;
}
}
that.keyOf = function(avalue) {
var idx = that.values.indexOf(akey);
if (idx>=0) {
return that.keys[idx];
} else {
return undefined;
}
}
that.add = function(akey,avalue) {
that.keys.push(akey);
that.values.push(avalue);
}
that.remove = function(akey) {
var idx = that.keys.indexOf(akey);
if (idx>=0) {
that.keys.splice(idx,1);
that.values.splice(idx,1);
}
}
that.toString = function() {
var res = "PortableDict(";
for (var i=0;i<that.keys.length;i++) {
res += "'" + that.keys.toString() + "':'" +
that.values.toString();
if (i<that.keys.length-1) {
res += ",";
}
}
res += ")";
return res;
}
}

</script>
</head>
<body bgcolor="#ccccff">
<span id="log"></span>

<script>
function print(s) {
var log = document.getElementById("log");
log.innerHTML = log.innerHTML + s.toString() + "<br>";
}

var d = new PortableDict();
var o = Object();

d.add('a',12);
d.add('b',13);
d.add(o,'Who am I?');
d.add('Meaning of Live, Universe and Everything',42);

print(d);

print("Now we remove key 'a'");
d.remove('a');
print(d);

print("Value of the object:");
print(d.valueOf(o));

print("Now we remove the object key as well.");
d.remove(o);
print(d);

print("Do we still have key 'b'?");
print(d.hasKey('b'));

print("Do we still have key o?");
print(d.hasKey(o));

</script>
As common as homework assignments are.

Well, this is not a homework assignment but I cannot prove it, can I?
What gave you the idea that this group is about how to use search engines?

I must also be a newbie to search engines, because I could not find
any useful. I tried "javascript dictionary", "javascript hash object"
and similar things, before I wrote here.
 
N

nagylzs

It looks like you're a surviving topdown coder :) Seriously, if you're
coming from a non-OO background (BTW, like me), perhaps the following
coding style looks familiar. Most common operations:

var string = 'three'
var numbers = new Object()

// 3 assignment methods
numbers['one'] = 'uno'
numbers.two = 'dos' // previous is better habit
numbers[string] = 'tres'

This would be perfect, except that "numbers" is a host object in my
case. :-(
 
N

nagylzs

I found out that the problem was the indexOf method. Cannot be used in
IE 6. So now I'm using this custom array:

function AdvArray() {
var that = this;
that = new Array(arguments);
that.indexOf = function(avalue) {
for (var i = 0; i<that.length ; i++ ){
if (that == avalue) {
return i;
}
}
return -1;
}
return that;
}

Functionally it is okay but I do not like it. I'm going to store some
1000 elements in a dict and call indexOf() frequently. Is there a
better way to implement this? I'm thinking about using a hash table to
find the index but how?

Thanks,

nagylzs
 
T

Thomas 'PointedEars' Lahn

nagylzs said:
Here it is. It works on FireFox. It does not work on IE and it does
not throw up the "Error on page" message. :-(

<html>

The DOCTYPE declaration is missing.
<head>
<script>

The required `type' attribute is missing. http://validator.w3.org/
function PortableDict() {
var that = this;

`that' is not required here, literally.
that.keys = new Array();
that.values = new Array();

It would be better if you used the key-value based architecture that is
already available through native objects (property - value). With one
property for the keys and another for the values, you have to implement
the connection always.

this.items = new Array();
that.hasKey = function(akey) {
return (that.keys.indexOf(akey)>=0);
}
that.hasValue = function(avalue) {
return (that.values.indexOf(avalue)>=0);
}

Array.prototype.indexOf() is not available before JavaScript 1.6 (Gecko
1.8b1+), and it is not available in JScript 5.x. Hence the error message in
IE, which probably says a little bit more than just "Error on page".
that.valueOf = function(akey) {
var idx = that.keys.indexOf(akey);
if (idx>=0) {
return that.values[idx];
} else {
return undefined;
}
}

`valueOf' is the name and identifier of a built-in method, inherited from
Object.prototype. It is unwise to use it for a user-defined object, unless
it does what the built-in method does: return the value of *calling object*.
that.keyOf = function(avalue) {
var idx = that.values.indexOf(akey);
^^^^^^^
if (idx>=0) {
return that.keys[idx];
} else {
return undefined;
}
}

See above.
that.add = function(akey,avalue) {
that.keys.push(akey);
that.values.push(avalue);
}

function Item(key, value)
{
this.key = key;
this.value = value;
}

PortableDict.prototype.add = function(akey,avalue)
{
this.keys.push(new Item(akey, avalue));
}

or

PortableDict.prototype.add = function(akey,avalue)
{
this.keys.push({akey: avalue});
}

See?
that.remove = function(akey) {
[...]
}
that.toString = function() {
[...]
}
}

Object.prototype.toString() is also a built-in method, but you overwrite it
in an acceptable way. However, it would be better (more efficient etc.) if
you defined all methods here as prototype methods, so that all PortableDict
objects inherit it from their prototype objects:

PortableDict.prototype.toString = function()
{
// ...
};

aso.
</script>
</head>
<body bgcolor="#ccccff">

Replace deprecated format attributes in favor of CSS. And take heed of
http://www.w3.org/QA/Tips/color
<span id="log"></span>

<script>

See above.
function print(s) {
var log = document.getElementById("log");

Methods of host objects should be feature-tested before being called:

http://www.jibbering.com/faq/faq_notes/not_browser_detect.html#bdFD
log.innerHTML = log.innerHTML + s.toString() + "<br>";

The proprietary innerHTML property is known to be error-prone and should
at least be feature-tested before being used. The toString() method is
implicitly called on string concatenation, you can as well concatenate `s'
and get the same result.
I must also be a newbie to search engines, because I could not find
any useful. I tried "javascript dictionary", "javascript hash object"
and similar things, before I wrote here.

"javascript faq OR guide OR reference" (or another combination thereof)
obviously did not come to mind.


HTH

PointedEars
 
T

Thomas 'PointedEars' Lahn

nagylzs said:
I found out that the problem was the indexOf method. Cannot be used in
IE 6.

And not in Firefox < 1.5, Netscape < 9.0b1, Opera, Konqueror, Safari, ...
So now I'm using this custom array:

function AdvArray() {
var that = this;
that = new Array(arguments);

Won't work, because that new array will have a reference to arguments as
its only element. With that approach, you will have to use

that = new Array();
for (var i = arguments.length; i--;) that = arguments;
that.indexOf = function(avalue) {
for (var i = 0; i<that.length ; i++ ){

for (var i = 0, len = that.length; i < len; i++ )
{
if (that == avalue) {


This should be a non-converting equals: ===
return i;
}
}
return -1;
}
return that;
}

if (typeof Array.prototype.indexOf != "function")
{
Array.prototype.indexOf = function(...)
{
// ...
}
}

would be simpler and more efficient. You would have to watch for it at
the `in' operation, of course.
Functionally it is okay but I do not like it. I'm going to store some
1000 elements in a dict and call indexOf() frequently. Is there a
better way to implement this? I'm thinking about using a hash table to
find the index but how?

a.b or a["b"]

RTFM.


PointedEars
 
N

nagylzs

a.b or a["b"]

It won't work because keys cannot be objects. Remember, I wanted a
dictionary where keys can be objects.

You don't need to help beginners. But if you do it, please don't be
rude. What you wrote about doctype and <script> missing "type"
attribute is not helping anybody especially other angry
comp.lang.javascript folks. Nobody starts programming by learning the
language reference before writing "Hello world".

You made very good points anyway, and I must thank you.
 
T

Thomas 'PointedEars' Lahn

nagylzs said:
a.b or a["b"]

It won't work because keys cannot be objects.
Remember, I wanted a dictionary where keys can be objects.

And why do you think a.b or a["b"] cannot be a reference to an object?
You don't need to help beginners. But if you do it, please don't be
rude.

I am not. I expect nothing more from you that I would expect from anyone
else, including me: to try very hard to get informed about the basics before
you consume the (free) time of others with your questions. And then, to ask
questions the smart way.

http://catb.org/~esr/faqs/smart-questions.html (it's also in the FAQ Notes)
What you wrote about doctype and <script> missing "type" attribute is not
helping anybody especially other angry comp.lang.javascript folks.

It is helping you and other uninitiated people, because I included the
Validator URL.
Nobody starts programming by learning the language reference before writing
"Hello world".

I seriously doubt that. I did, at least partially. After I have searched
for existing examples. BTW, the JavaScript Reference is not the ECMAScript
Language Specification; the former and the JavaScript Guide is especially
written for beginners, while the latter is not.
You made very good points anyway, and I must thank you.

You're welcome. But please provide proper attribution of quoted material,
as (at least) I have demonstrated numerous times now.


PointedEars
 
N

nagylzs

nagylzs said:
It won't work because keys cannot be objects.
Remember, I wanted a dictionary where keys can be objects.

And why do you think a.b or a["b"] cannot be a reference to an object?

I'm talking about an associative array where __keys__ can be objects.
You are talking about an associative array where __values__ can be
objects.

BTW I was searching for answers and I found this:

http://groups.google.com/group/comp...gst&q=object+as+a+key&rnum=2#46ff53bdebf25ce3

Others had the same problem on comp.lang.javascript. I found no real
answer. The answer in that thread was that it is a design pitfall to
try to use objects as keys in an associative array. But I see no other
way to implement custom attributes in JavaScript, do you?

Here is what I use now (and it works with IE 5.x):

var hA = new Dict(); // global storage
function getCustomAttrs(aobj) {
if (hA.hasKey(aobj)) {
return hA.getValue(aobj);
} else {
var dict = new Dict();
hA.setValue(aobj,dict);
return dict;
}
}

function hasCustomAttr(aobj,aname) {
return getCustomAttrs(aobj).hasKey(aname);
}
function setCustomAttr(aobj,aname,avalue) {
getCustomAttrs(aobj).setValue(aname,avalue);
}
function getCustomAttr(aobj,aname) {
return getCustomAttrs(aobj).getValue(aname);
}


Then I can do

var sp = document.getElementById('sp')
setCustomAttr(sp,'myAttribute',12);
alert(getCustomAttr(sp,'myAttribute');

But this definitely requires an array where keys are objects. (Or at
least I don't have a better idea.)
 
T

Thomas 'PointedEars' Lahn

nagylzs said:
nagylzs said:
a.b or a["b"]
It won't work because keys cannot be objects.
Remember, I wanted a dictionary where keys can be objects.
And why do you think a.b or a["b"] cannot be a reference to an object?

I'm talking about an associative array where __keys__ can be objects.
You are talking about an associative array where __values__ can be
objects.

There are no associative arrays. Objects can only occur in script code as a
reference to them, and object references are indeed values. The only thing
that you have to look for is that the object needs a unique string
representation. It would be quite a strange implementation that uses
objects as keys for an associative-array-like structure, but there you are.
[...]
Here is what I use now (and it works with IE 5.x):

var hA = new Dict(); // global storage
function getCustomAttrs(aobj) {
if (hA.hasKey(aobj)) {
return hA.getValue(aobj);
} else {
var dict = new Dict();
hA.setValue(aobj,dict);
return dict;
}
}

function hasCustomAttr(aobj,aname) {
return getCustomAttrs(aobj).hasKey(aname);
}
function setCustomAttr(aobj,aname,avalue) {
getCustomAttrs(aobj).setValue(aname,avalue);
}
function getCustomAttr(aobj,aname) {
return getCustomAttrs(aobj).getValue(aname);
}


Then I can do

var sp = document.getElementById('sp')
setCustomAttr(sp,'myAttribute',12);
alert(getCustomAttr(sp,'myAttribute');

But this definitely requires an array where keys are objects. (Or at
least I don't have a better idea.)

As I said in the very beginning:

/**
* @see http://PointedEars.de/scripts/types.js
*/
function isMethodType(s)
{
return /\b(function|object)\b/i.test(s);
}

function hasHasOwnProperty(o)
{
return isMethodType(typeof o.hasOwnProperty) && o.hasOwnProperty;
};

function MyHTMLElement(o)
{
this.elemObj = o;
this.foo = "bar";
}

MyHTMLElement.prototype.getProperty =
function myHTMLElement_getProperty(sProperty)
{
var h = hasHasOwnProperty(this);
if ((h && this.hasOwnProperty(sProperty))
|| (!h && typeof this[sProperty] != "undefined"))
{
return this[sProperty];
}

return this.elemObj[sProperty];
};

MyHTMLElement.prototype.setProperty =
function myHTMLElement_setProperty(sProperty, value)
{
if (typeof this.elemObj[sProperty] != "undefined")
{
this.elemObj[sProperty] = value;
}
else
{
this[sProperty] = value;
}
};

var sp = new MyHTMLElement(document.getElementById('sp'));
sp.setProperty("myAttribute", 12);
window.alert(sp.getProperty("myAttribute"));

You can (and should) even rewrite the constructor or add a (prototype)
method so that it wraps document.getElementById() (and its fallbacks).
Maybe not as pretty as augmenting host objects, but at least mostly reliable.


PointedEars
 
N

nagylzs

As I said in the very beginning:
....


var sp = new MyHTMLElement(document.getElementById('sp'));
sp.setProperty("myAttribute", 12);
window.alert(sp.getProperty("myAttribute"));

You can (and should) even rewrite the constructor or add a (prototype)
method so that it wraps document.getElementById() (and its fallbacks).
Maybe not as pretty as augmenting host objects, but at least mostly reliable.

I thought I made myself clear. I really need to access custom
attributes using the host object. I see your point but it will not
work for me. You suggested to create a special native object that
belongs to a host object. But knowing the host object only, you cannot
tell the native object that belongs to it. Background: I want to
write an event handler that gets called with different host objects as
parameters. The host object can be anything, for example "the first
'tr' child of the first 'table' element in the document". I just want
to set an attribute for any element, and then I would like to get the
same attribute later. I cannot tell which elements will be used this
way in advance, this is why I badly need to create some kind of
associative array (or "dictionary") that can use (host) objects as
keys. (I need it to work in FireFox 2+ and IE 5+ only)
 
T

Thomas 'PointedEars' Lahn

nagylzs said:
I thought I made myself clear. I really need to access custom attributes
using the host object. I see your point but it will not work for me. You
suggested to create a special native object that belongs to a host
object. But knowing the host object only, you cannot tell the native
object that belongs to it.

Not directly.
Background: I want to write an event handler that gets called with
different host objects as parameters. The host object can be anything,
for example "the first 'tr' child of the first 'table' element in the
document". I just want to set an attribute for any element, and then I
would like to get the same attribute later.

There. Why don't you just say so? You have asked for a solution using your
approach. You should have presented the actual problem (what you call only
"background") in the first place. Now don't blame your readers for that,
please.

Event bubbling may help here, depending on the event (the description is
still too vague for a definitive answer). But setting user-defined
attributes/properties on element objects may simply fail (as they are host
objects), and there is nothing you can do about that if it happens.

However, I find it unlikely that you need additional attributes here.
I cannot tell which elements will be used this way in advance, this is
why I badly need to create some kind of associative array (or
"dictionary") that can use (host) objects as keys.

There cannot be any, as host objects do not need to implement ECMAScript 3
algorithms the way they are specified.
(I need it to work in FireFox 2+ and IE 5+ only)

In that case, if you *really* need additional attributes/properties
(be *very* sure of that!), and are not happy with any solution presented
so far (including yours) you should try augmenting the element objects.

You still don't provide proper attribution, please take heed of
http://www.jibbering.com/faq/faq_notes/clj_posts.html


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
474,159
Messages
2,570,883
Members
47,415
Latest member
SharonCran

Latest Threads

Top