Forum Moderators: open

Message Too Old, No Replies

Ajax classes: hardcoding the instance name

Ajax Class: Ways to avoid hardcoding instance names

         

Alberto

11:33 am on Aug 27, 2006 (gmt 0)

10+ Year Member



As far as I have seen thus far, all the Ajax codes I have seen eventually always hardcode a given name for the Ajax variable in the Ajax handlers.
Instance:

if(ajax.request.readyState==4 ¦¦ ajax.request.readyState=='complete'){

IN such a line "ajax" stands for a variable somewhere initialized with such name.

Of course, we can create Ajax classes, and encapsulate all the methods in one wrapper.
Yet, these classes are invariably singletons: only ONE instance can be initialized namely it cannot COEXIST with other instances because it is still required that in the response handlers the name of the instance is hard coded: "ajax", in the example above.

I know of one way to avoid that but it works only in Firefox.

this.echo=function(){
if(ajax.request.readyState==4 ¦¦ ajax.request.readyState=='complete'){
if(ajax.request.status==200){ blah blah

Obviously, this.echo is the method member of a class.

If you produce a snippet like:

this.assignCallingVariable=function(assignTo){
assignTo.variable=this;
}

and soon after this.echo has been defined you do:

this.assignCallingVariable(this.echo);

from that moment on you could redraw the echo method as follows:

this.echo=function(){
if(this.variable.request.readyState==4 ¦¦ this.variable.request.readyState=='complete'){
if(this.variable.request.status==200){

as you may notice, the generic placeholder this.variable has overtaken the hardcoded class instance name "ajax".
This works brilliantly with Firefox: it achieves the response going on recognizing the this.variable as a reference to the initialized instance.

However, this does not work with Internet Explorer.

I am not here moving on the plane "how bad IE is" - I am after practical results, not ideological opinions. Just to be clear.

Now, how could we persuade IE to do that?
I am VERY puzzled because IE keeps calling this.echo if the class instance name is hardcoded, so there MUST be somewhere in the engine a POINTER to it, a VALID pointer.
Yet, I cannot spot a ROUTE to take hold of it.

From within this.echo, any reference to 'this' in IE references the window. Of course, I thought to scan the window properties, say

if(!this. variable){loop window, if 'X'==windowProp then this.variable='X'}

The issue is now twofold: apparently, the window scoped variables in IE do NOT belong to the window object, or at any rate can NOT be found scanning it (!), second issue: what should 'X' be? it is obviously a reference to the ajax instance that is repeatedly calling the this.echo method, and yet I have no clue at this stage how to reference it, that is what to put in place of 'X'.

Anyone has tried to deal with this generalization issue before, successfully?

Thank you
Alberto

[edited by: jatar_k at 2:28 pm (utc) on Aug. 27, 2006]
[edit reason]
[1][edit reason] no sigs thanks [/edit]
[/edit][/1]

bird

11:56 am on Aug 27, 2006 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I'm not sure If I really understand your problem.

What's wrong with storing the request object as an instance attribute?

Alberto

12:40 pm on Aug 27, 2006 (gmt 0)

10+ Year Member



The problem is to be able to initialize a class with any name AND avoid writing down in the class, in any place, the name of the instance.

The methods that are tailored to handle the echo (this.request.onreadystatechange) trigger the echo handler. Yet, once the echo handler runs, it needs to have within it hardcoded the name assigned to the instance of the class, or won't be able to work.

Say this pseudocode;

class AJAX{
this.request=function(){} /*request CAN be stored in the class*/
this.get=function(){}
this.echoHandler=function(){} /*here we'll have an issue*/
}

var ajax=new AJAX();

Now, you must write down in the echo method the name 'ajax', or it would not work, simply (unless I am missing something, but all codes I saw seem to "suffer" of this very same lack of generalization):

this.echoHandler=function(){
if(ajax.request.readyState==4 ¦¦ ajax.request.readyState=='complete'){etc...}
}

The problem is: how to avoid writing down:
ajax.request.readyState /*see? I had to write down the NAME of the instance: 'ajax'*/
and be able to generalize with something like:

INSTANCE_NAME_WHATEVER_IT_WAS.request.readyState

As said, there is a way to do this with Firefox, but not with Explorer - for more on this see my previous post, or ask further questions if that wasn't clear enough.

Thank you

Alberto

12:43 pm on Aug 27, 2006 (gmt 0)

10+ Year Member



PS:

INSTANCE_NAME_WHATEVER_IT_WAS.request.readyState

the issue is exactly that:

this.request.readyState

will NOT work.

bird

12:55 pm on Aug 27, 2006 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



It seems you're not actually using the object oriented features of Javascript as they are meant to be used. If you're coming a different language background, then using prototypes instead of classes may be confusing at first. One way of several to define instantiable objects goes as follows.

Define the object:


function myobject(init1, init2, init3) {
this.attribute1 = init1;
this.attribute2 = init2;
this.attribute3 = init3;
}
myclass.prototype.set1 = function(value) {
this.attribute1 = value;
}
myclass.prototype.show1 = function() {
alert(this.attribute1);
}

Use the object:


var myinstance = new myobject('one', 'two', 'three');
myinstance.show1(); // alert dialog shows 'one'
myinstance.set1('first')
myinstance.show1(); // alert dialog shows 'first'

As you see, there's no need at all to hardcode any names that are external to your object. Knowing this, maybe your original problem will just disappear... ;)

Alberto

12:59 pm on Aug 27, 2006 (gmt 0)

10+ Year Member



One may wonder, why you don't write echo handlers for each class instance: after all, each echo handling is supposed to be unique in its tasks.

What I am after is a level of abstraction that seems not only more elegant, but more productive.

If I can track (both on IE and FF) from the echo handler that produces the response, the class instance that triggered it, we can produce something interesting.

class AJAX{
//bla bla
this.echoHandler(){}
}

var ajax1=new AJAX();

ajax1.INSIDEechoHadler=function(response){alert(response)}

which would mean that this.echoHandler is sort of:
this.echoHandder{
if(PLACEHOLDER.request.readyState==4 ¦¦ PLACEHOLDER.request.readyState=='complete'){
if(PLACEHOLDER.request.status==200){
PLACEHOLDER.insideechoHandler(PLACEHOLDER.request.responseText)
}
}

that is, we can avoid writing down in the echo handlers the same code again, over and over, for the readyState status checks.
This is the level of abstraction I am after, but being echoHandler an ASYNCHRONOUS method, once it is triggered one time, any reference within it made to the instance by the 'this' keyword, gets lost.

Alberto

1:04 pm on Aug 27, 2006 (gmt 0)

10+ Year Member



Bird, it's asynchronous.
Have you tried to apply that procedure to an asynchronous method? Any reference to the keyword this, disappears in the void :-(

bird

3:00 pm on Aug 27, 2006 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Ah yes, that's one of the disadvantages of prototypes vs. classes.

You need to prepare a special function that remembers "this". The process is called currying, and requires a second "factory function", which dynamically creates a wrapper function around your actual handler (it sounds more complicated than it actually is... ;))


function myobject() {
}
myobject.prototype.handler = function(arg) {
alert('this is ' + this + ' handling ' + arg);
}
myobject.prototype.create_handler = function(my_this) {
return function(arg) { my_this.handler(arg) }
}


var myinstance = new myobject('one', 'two', 'three');
var handler = myinstance.create_handler(myinstance);
// use handler as callback function

The function returned by create_handler will remember "this". The procedure is not very intutitive, but you can juse the above as a pattern that always works when you need a callback that remembers which object instance it belongs to.

Alberto

6:35 am on Aug 28, 2006 (gmt 0)

10+ Year Member



Thank you Bird,
I am going to study this thing. I just printed 30 pages about currying. Once I have digested them, maybe I will be back - or maybe not. Just keep a kind eye here in case :-)

It is amazing that after 10 years of javascript, one has still to learn about it - my only excuse, being not a mathematician, I was not really supposed to know that javascript had an implementation for... Lambda Calculus!

Alberto

7:39 am on Aug 28, 2006 (gmt 0)

10+ Year Member



Jesus....

function add(x){
return function(y){alert(x+y)}
}

add(1)(2); //alerts 3!

How many among you out there would have even thought it was possible writing down an expression like:

myfunc()()()()()()();?

Alberto

8:14 am on Aug 28, 2006 (gmt 0)

10+ Year Member



function add(x){
return function(y){alert(x+y)}
}
add(1)(2);//alerts 3!

alert(add(1));//alerts the body of add!

I have touched a metaphysical ground - WHAT is a function?
Clearly enough, it is NOT a computation.

Alberto

8:20 am on Aug 28, 2006 (gmt 0)

10+ Year Member



It's a ID-ENTITY!

bird

9:36 am on Aug 28, 2006 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



In JavaScript, there is no real difference between an object and a function. That's one of the consequences of how it implements prototype based object orientation.

Alberto

9:38 am on Aug 28, 2006 (gmt 0)

10+ Year Member



Done. The most elegant Ajax class ever! :-)

I owe you a drink, Bird. If you ever visit Italy, drop me a line.

ciao and thank you

Alberto

ps I still have to chew on that Lambda Calculus implementation in javascript and its implications - but as Kipling would say, that's another story. Bye!