View Full Version : An object's properties are not accessible by its methods

06-13-2003, 06:50 AM
I've got a bit of weirdness about an object's properties not being visible to any of its methods. The intention is to override IE's handling of keystrokes for <select> dropdowns so that it behaves more like Mozilla (so the code that follows is IE-specific); FYI, IE's behaviour is to take you to the first element in the selection whose first character matches the key you just hit, while Mozilla retains a memory of the last few keys you hit (so that you can type more than just one character of the selection). In the sample list below, hitting "JS" would in IE find you selecting "superguy", while in Mozilla you'd select "jsmith".

You'll note that the entire object has four (user-defined) properties and a method. The method itself is the actual event handler, while the properties supply the object with the "more than one thing at a time" memory that it needs to perform.

I have non-OO code that does work - it uses global variables instead of properties, the search function has to have the <select> object passed to it as a parameter, and the handler is specified in an "onkeyup" attribute, but it's otherwise the same code. I can fall back on that in a pinch, but I want to be using this behaviour multiple times on multiple pages, and encapsulating seems desirable.

<script type="text/javascript" language="javascript">

function TypistDropdown(select, usevalue)
{ this.select = select; // The <select> element this binds to.
this.usevalue = usevalue || false; // Search value or text?
this.elapsed = (new Date()).valueOf(); // # of milliseconds since last keystroke
this.buffer = ''; // The most recent keystrokes in this dropdown

TypistDropdown.prototype.search = function()
{ var key = String.fromCharCode(event.keyCode);
if(key<'A' || key>'Z') return false; // Nothing to do with us (XXX other character ranges?)
var right_now = (new Date()).valueOf();
if(right_now-this.elapsed > 500) // milliseconds (XXX configurable?)
this.buffer = ''; // Been so long - flush the buffer
this.buffer += key; // Add this keystroke to the buffer
this.elapsed = right_now; // Reset the timer
var buffer_length = this.buffer.length;
var select_length = this.select.options.length;
var option;
for(var i=0; i<select_length; i++)
{ option = this.select.options[j];
option = this.usevalue ? option.value : option.text;
option = option.substr(0,buffer_length).toUpperCase();
if(option==this.buffer) // We have a match
{ this.select.selectedIndex = j;
document.getElementById('mybuffer').innerHTML = this.buffer;
return true;

<SELECT name='username' id="username" size="4">
<OPTION value="alienface">alienface</option>
<OPTION value="barry">barry</option>
<OPTION value="fredh">fredh</option>
<OPTION value="fredt">fredt</option>
<OPTION value="jblair">jblair</option>
<OPTION value="jsmith">jsmith</option>
<OPTION value="ppolly">ppolly</option>
<OPTION value="superguy">superguy</option>
<OPTION value="ttt">ttt</option>
<script type="text/javascript" language="javascript">
var username_handler = new TypistDropdown(document.getElementById('username'));
document.getElementById('username').onkeyup = username_handler.search;
</script><span id='mybuffer'></span>

To make things clear right now, the event handling itself appears to work - that is to say, key gets the value it should, and so forth. Problems begin the moment I start using the object's properties (select, usevalue and the rest). They are all (according to judicious alert()s dotted about) undefined. I've tried various alternate idioms ("this.buffer=''; this.search = function(){...}", etc.) but all fail in the same way: "right_now-this.elapsed" is meaningless because "this.elapsed" is undefined (and before you ask, yes I did check to see what this.buffer and other properties contained, including a few ("this.foo") created for the purpose; they were all undefined in the scope of the search method).

Judging from other Javascript code I've read all about the place, I really can't see what's so different about my code that makes it not work. STFW, RTFM, UTSL - I can't see the difference. If I've missed a thread in my searching that does deal with this, I'd appreciate it being pointed out. Ditto if I'm missing some much more elegant solution.

Oh yeah, mybuffer is a debugging instrument - its function should be obvious (don't see why having it would make a difference: and, surprisingly, taking it out doesn't magically make things work). (Anyone suspect I'm getting just a little peeved?)

06-13-2003, 05:01 PM
document.getElementById('username').onkeyup = username_handler.search

When the onkeyup event handler is fired the "this" object is the select object not your object.

You may be able to do this

function TypistDropdown(select, usevalue)
select.selObj = this;

this.select = select; // The <select> element this binds to.
this.usevalue = usevalue || false; // Search value or text?
this.elapsed = (new Date()).valueOf(); // # of milliseconds since last keystroke
this.buffer = ''; // The most recent keystrokes in this dropdown

and then reference YOUR object by

TypistDropdown.prototype.search = function()
{ var key = String.fromCharCode(event.keyCode);
var selObj = this.selObj;

06-13-2003, 05:12 PM
If you really want to encapsulate this for IE-only, why not make a DHTML behavior for it instead?


I can show you how to make one if you need help.

06-13-2003, 05:24 PM
don't forget about Opera - does it natively support type-ahead combos? what with IE's lack of update for the past two years, and none ever again available without a new OS or a subscription to MSN, in addition to its lack of good CSS, DOM, mime-type, etc., support, I get the feeling it'll kind of fall by the wayside amongst any in the know who still explore new browsers.

06-15-2003, 11:26 PM
RoyW: thanks for that - didn't quite realise that "this" in an event handler refers to the object firing the event even if the handler is a method of another object (is there no better way to access the object's own properties?). It didn't work for a couple of minutes - but if you look at the code you'll see why :o.

beetle: I will have a look at using DHTML behaviours when I review this. Thanks for the suggestion - I didn't know about the things (coming from an open standards environment). It will be a bonus if it simplifies the task of avoiding everything except IE whining about Javascript errors (if I don't check, Mozilla spits the dummy about "event" not being defined).

Choopernickel: To be honest I have no idea what the default behaviour for Opera is - dunno if the behaviour is even OS-sensitive or not in Moz and IE. In the present environment the number of browsers reporting themselves to be Opera however is currently running at 0% and looks unlikely to change.

To be blunt, the Powers That Be specify I have to write this for Internet Explorer, and they're the ones signing my paychecks. I still use Mozilla as a test platform though, because it has much better debugging facilities and I want to at least make a token effort at standards compliance - this just happened to be a situation where that approadch didn't work. At least I got to say "But Mozilla already does this..." again :)

06-15-2003, 11:42 PM
Originally posted by Floyd
It will be a bonus if it simplifies the task of avoiding everything except IE whining about Javascript errorsBoy does it ever! And it's seamless to apply - perhaps the best part.

<style tyle="text/css">
select {
behavior: url(js/type_ahead.htc);
Then type_ahead.htc

// HTC code here
That's it. No initialization scripting - just attach the behavior to the element via CSS (the crux of the whole thing). And since behaviors introduce their own scope, you don't even need to use OO js, although there's nothing wrong with it.