473,224 Members | 1,333 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,224 software developers and data experts.

Dynamically generated functions with variable-based payload


I'm trying to generate dynamic functions to use as separate
callbacks for an AJAX API call.

The API doesn't seem to allow for the inclusion of any parameters
in the callback, so I can't associate the call with the handling
routine (for reference purposes, I'm calling the Google Language
Translation API). As a work-around, I thought I'd dynamically
generate a unique callback function for each API call.

Right now, I'm stuck hobbling the API calls by running them
synchronously, since they don't seem to allow parameterizing the
callback function. This rather slows things down.

Of course, since I haven't gotten my work around running, I can't
prove that it will have the desired effect of parellizing the API
calls for me.
I'm running into what are probably some fairly basic issues when
generating the function definitions (and probably the initial calling
API code, but since I haven't gotten that far, I'm not sure yet).

For example:

for (i = 0; i < 10; i++) {
var text = 'Test [' + eval( i ) + ']';
window[ 'alerter' + i ] = function () { alert ( text ); }
}

This code generates my ten functions (alerter0(), alerter1(),
alerter2(), etc) but the body of the functions seems to be getting the
variable reference to 'i', instead of the string literal value of 'i'
during that loop iteration. So when I execute any of the 'alerterX()'
functions, they /all/ pop up alert boxes using the referenced value of
'i' at the end of the loop, instead of the intended effect where
'alerter0()' would have the text 'Test [0]', 'alerter1()' would have
the text 'Test [1]', etc.

The goal is to build an arbitrary number of unique callback
functions of the model:

// myelements[] is a global array of html elements where the text is
being replaced with the returned value
function callBackXX(result) {
if (result.translation) {
myelements[XX].innerHTML = result.translation;
} else {
myelements[XX].innerHTML = '';
}
}

With calls along the model of:

google.language.translate(text, 'en', 'es', callBack0 );

google.language.translate(text, 'en', 'es', callBack1 );

google.language.translate(text, 'en', 'es', callBack2 );

With these calls, obviously, being dynamically generated in the
loop as well.
Any pointers on how to generate the required static strings for
the function bodies, instead of getting variable references would be
appreciated. I'd like to avoid using eval() (Yes, I know my example
used it!), as well.

Thanks in advance.

-Joe
Sep 25 '08 #1
9 1850
Dahak wrote:
I'm trying to generate dynamic functions to use as separate
callbacks for an AJAX API call.

The API doesn't seem to allow for the inclusion of any parameters
in the callback, so I can't associate the call with the handling
routine (for reference purposes, I'm calling the Google Language
Translation API). As a work-around, I thought I'd dynamically
generate a unique callback function for each API call.
Use an object.
Right now, I'm stuck hobbling the API calls by running them
synchronously, since they don't seem to allow parameterizing the
callback function. This rather slows things down.
Bad idea.
>
Of course, since I haven't gotten my work around running, I can't
prove that it will have the desired effect of parellizing the API
calls for me.
I'm running into what are probably some fairly basic issues when
generating the function definitions (and probably the initial calling
API code, but since I haven't gotten that far, I'm not sure yet).

For example:

for (i = 0; i < 10; i++) {
var text = 'Test [' + eval( i ) + ']';
window[ 'alerter' + i ] = function () { alert ( text ); }
}

This eval:

eval( i )

- is completely useless. The approach is not going to work, so it's
almost not even relevant because you'll be scrapping it anyway, but in
the future, don't use eval. The way you used it here is only going to
add inefficiency.

This code generates my ten functions (alerter0(), alerter1(),
alerter2(), etc) but the body of the functions seems to be getting the
variable reference to 'i', instead of the string literal value of 'i'
during that loop iteration. So when I execute any of the 'alerterX()'
functions, they /all/ pop up alert boxes using the referenced value of
'i' at the end of the loop, instead of the intended effect where
'alerter0()' would have the text 'Test [0]', 'alerter1()' would have
the text 'Test [1]', etc.
Why is that?

Here's what's happening:

You have created 10 properties on the window object, window['alerter' +
i] points to a unique function. Each function has the same FunctionBody
code and scope. They're essentially equivalent functions, but different
objects*.

So, window.alerter1() will find and then call the window's |alerter1|
property. Function |alerter1|'s function body has a reference to the
identifier |text|.

That identifier is resolved in the containing scope. This resolution
happens when the function is called, after the loop has terminated.
After the loop is completed, |text| has the value "Text [9]".
* No implementation appears to support joined functions.
The goal is to build an arbitrary number of unique callback
functions of the model:

// myelements[] is a global array of html elements where the text is
being replaced with the returned value
function callBackXX(result) {
if (result.translation) {
myelements[XX].innerHTML = result.translation;
} else {
myelements[XX].innerHTML = '';
}
}

With calls along the model of:

google.language.translate(text, 'en', 'es', callBack0 );

google.language.translate(text, 'en', 'es', callBack1 );

google.language.translate(text, 'en', 'es', callBack2 );

With these calls, obviously, being dynamically generated in the
loop as well.
In the case of passing methods as callbacks, you'll often want to pass
in a context argument.

You can use a closure to resolve the context.
>
Any pointers on how to generate the required static strings for
the function bodies, instead of getting variable references would be
appreciated. I'd like to avoid using eval() (Yes, I know my example
used it!), as well.
Custom FunctionBody can be achieved with the Function constructor. Do
not do this.

It looks like you're using a service to get translated text. I don't
know what this has to do with generating unique FunctionBody.

function AcmeAbominator(i) {
this.i = i;
}
AcmeAbominator.instances = [];

AcmeAbominator.prototype.abmoniate = function() {
alert('Abominating Road Runner ' + this.i);
};

for(var i = 0; i < 10; i++) {
AcmeAbominator.instances[i] = new AcmeAbominator( i );
}
Garrett
Thanks in advance.

-Joe
Sep 25 '08 #2
On Sep 25, 11:15 am, Dahak <Dahak...@theXOUTfifthimperium.com.invalid>
wrote:
<snip>
I'm running into what are probably some fairly basic issues when
generating the function definitions (and probably the initial calling
API code, but since I haven't gotten that far, I'm not sure yet).

For example:

for (i = 0; i < 10; i++) {
var text = 'Test [' + eval( i ) + ']';
window[ 'alerter' + i ] = function () { alert ( text ); }
}
You seem to misunderstand how closures work. There are several ways to
correctly use closures to do this. The easiest to grok is probably to
use a "factory" function that generates the function you want:

function makeAlerter (text) {
return function () {
alert(text);
}
}
for (var i=0;i<10;i++) {
window['alerter'+i] = makeAlerter('Test['+i+']');
}

Once you realise what's happening with the code above you'll realise
that you can also code it like this:

for (var i=0;i<10;i++) {
window['alerter'+i] = (function(text){
return function () {
alert(text);
}
})('Test['+i+']')
}

And once you realise that you can use closures with anonymous function
you realise you don't need to create named functions at all to pass to
the callback:

google.language.translate(text, 'en', 'es', function (result) {
if (result.translation) {
myelements[0].innerHTML = result.translation;
}
else {
myelements[0].innerHTML = result.translation;
}
});

Or better yet, encapsulate the logic into a factory function:

function makeCallback (htmlElement) {
return function (result) {
if (result.translation) {
htmlElement.innerHTML = result.translation;
}
else {
htmlElement.innerHTML = result.translation;
}
}
}
google.language.translate(text,'en','es',makeCallb ack(myelements[0]));
google.language.translate(text,'en','es',makeCallb ack(myelements[1]));
google.language.translate(text,'en','es',makeCallb ack(myelements[2]));
Sep 25 '08 #3
On Sep 25, 8:15 am, Dahak <Dahak...@theXOUTfifthimperium.com.invalid>
wrote:
I'm trying to generate dynamic functions to use as separate
You can try the object oriented way:

//class MyTranslationDiv
function MyTranslationDiv(elemId){
this.div = document.getElementById(elemId);
}

MyTranslationDiv.prototype.translate = function(result){
if (!result.error) {
this.div.innerHTML = result.translation;
}else{
this.div.innerHTML = "Error happened";
}
}

//instance of MyTranslationDiv
var myTranDiv = new MyTranslationDiv("translation");
google.language.translate(
"have a nice day", "en", "fr",
function(result){ myTranDiv.translate(result) }
);

- Kiran Makam
Sep 25 '08 #4
On Wed, 24 Sep 2008 21:37:55 -0700, an orbiting mind-control laser
made dhtml <dh**********@gmail.comwrite:
>Dahak wrote:
> Right now, I'm stuck hobbling the API calls by running them
synchronously, since they don't seem to allow parameterizing the
callback function. This rather slows things down.

Bad idea.
Yes, I know... While it works, it stinks, thus the hideous
attempts to work around it.

-SNIP-
>This eval:

eval( i )

- is completely useless. The approach is not going to work, so it's
almost not even relevant because you'll be scrapping it anyway, but in
the future, don't use eval. The way you used it here is only going to
add inefficiency.
Yep. I'll admit that. It's a holdover from earlier attempts to
evaluate the variable. It failed just as badly as simply using the
variable i. Since it didn't fail any worse, I never bothered removing
it as I looked at other things.

-SNIP-
>Why is that?

Here's what's happening:

You have created 10 properties on the window object, window['alerter' +
i] points to a unique function. Each function has the same FunctionBody
code and scope. They're essentially equivalent functions, but different
objects*.

So, window.alerter1() will find and then call the window's |alerter1|
property. Function |alerter1|'s function body has a reference to the
identifier |text|.
Which I already knew... I'm trying to determine how to get it to
resolve as a string literal, not a variable reference.

-SNIP-
>In the case of passing methods as callbacks, you'll often want to pass
in a context argument.

You can use a closure to resolve the context.
-SNIP-
>Custom FunctionBody can be achieved with the Function constructor. Do
not do this.
Why not? I was planning on trying this approach in the morning.
>It looks like you're using a service to get translated text. I don't
know what this has to do with generating unique FunctionBody.
If I had a single string to translate, it would be trivial.

I have an arbitrary number of text strings to translate. The API
evidently (I could be wrong, I'm still trying to determine this) does
not allow the passing of parameters to the callback function. If it
did, my search would be over and I could skip the silliness of unique
callback functions.
-Joe
Sep 25 '08 #5
On Wed, 24 Sep 2008 22:18:07 -0700 (PDT), an orbiting mind-control
laser made slebetman <sl*******@gmail.comwrite:
>On Sep 25, 11:15 am, Dahak <Dahak...@theXOUTfifthimperium.com.invalid>
-SNIP-
>You seem to misunderstand how closures work.
Oh, no doubt. I've never had the need for something like this
before.
There are several ways to
correctly use closures to do this. The easiest to grok is probably to
use a "factory" function that generates the function you want:

function makeAlerter (text) {
return function () {
alert(text);
}
}
That seems pretty straightforward.
>for (var i=0;i<10;i++) {
window['alerter'+i] = makeAlerter('Test['+i+']');
}

Once you realise what's happening with the code above you'll realise
that you can also code it like this:

for (var i=0;i<10;i++) {
window['alerter'+i] = (function(text){
return function () {
alert(text);
}
})('Test['+i+']')
}

And once you realise that you can use closures with anonymous function
you realise you don't need to create named functions at all to pass to
the callback:
Thanks, I'll check into this.
>google.language.translate(text, 'en', 'es', function (result) {
if (result.translation) {
myelements[0].innerHTML = result.translation;
}
else {
myelements[0].innerHTML = result.translation;
}
});

Or better yet, encapsulate the logic into a factory function:

function makeCallback (htmlElement) {
return function (result) {
if (result.translation) {
htmlElement.innerHTML = result.translation;
}
else {
htmlElement.innerHTML = result.translation;
}
}
}
google.language.translate(text,'en','es',makeCall back(myelements[0]));
google.language.translate(text,'en','es',makeCall back(myelements[1]));
google.language.translate(text,'en','es',makeCall back(myelements[2]));
I wasn't able to get my tests to parameterize the callback to
work. If I can pass a reference to the source string through the
callback, I should be able avoid dynamic functions altogether.

Thanks.

-Joe
Sep 25 '08 #6
On Wed, 24 Sep 2008 22:25:27 -0700 (PDT), an orbiting mind-control
laser made Kiran Makam <ki*******@gmail.comwrite:
>On Sep 25, 8:15 am, Dahak <Dahak...@theXOUTfifthimperium.com.invalid>
wrote:
> I'm trying to generate dynamic functions to use as separate

You can try the object oriented way:

//class MyTranslationDiv
function MyTranslationDiv(elemId){
this.div = document.getElementById(elemId);
}
One of the problems I'm currently faced with is that I have to
deal with an arbitrary number of elements on a page. I find all
elements with a class of 'translate', then traverse that array through
the google API call, regrettably, I don't have unique identifiers.

The issue is associating the source element with the return
callback when using the asynchronous API call.

>MyTranslationDiv.prototype.translate = function(result){
if (!result.error) {
this.div.innerHTML = result.translation;
}else{
this.div.innerHTML = "Error happened";
}
}

//instance of MyTranslationDiv
var myTranDiv = new MyTranslationDiv("translation");
google.language.translate(
"have a nice day", "en", "fr",
function(result){ myTranDiv.translate(result) }
);

- Kiran Makam
Thanks for something to test out.

-Joe
Sep 25 '08 #7
On Sep 25, 6:06*pm, Dahak <Dahak...@theXOUTfifthimperium.com.invalid>
wrote:
>
* * * * One of the problems I'm currently faced with is that I have to
deal with an arbitrary number of elements on a page. *I find all
elements with a class of 'translate', then traverse that array through
the google API call, regrettably, I don't have unique identifiers.

* * * * The issue is associating the source element with the return
callback when using the asynchronous API call.
To get all elements having a particular class, you can use
getElementsByClassName (google to find implementations of
getElementsByClassName function, Prototype has one)

code:
---------------
//class MyTranslationDiv
function MyTranslationDiv(objDiv){
this.div = objDiv;
}

MyTranslationDiv.prototype.update = function(result){
if (!result.error) {
this.div.innerHTML = result.translation;
}else{
this.div.innerHTML = "Error happened";
}

}

MyTranslationDiv.prototype.translate = function(textToTranslate){
var thisTmp = this;
google.language.translate(
textToTranslate, "en", "es",
function(result){thisTmp.update(result)}
);

}

//get all elements having className as 'translate'
var elements = getElementsByClassName("translate");

//iterate and translate
for(var i=0, len=elements.length; i<len; i++){
var obj = new MyTranslationDiv( elements[i] );
obj.translate("hello world");
}
----------

- Kiran Makam
Sep 25 '08 #8
On Sep 25, 3:06*pm, Dahak <Dahak...@theXOUTfifthimperium.com.invalid>
wrote:
>
* * * * One of the problems I'm currently faced with is that I have to
deal with an arbitrary number of elements on a page. *I find all
elements with a class of 'translate', then traverse that array through
the google API call, regrettably, I don't have unique identifiers.
See http://jorgechamorro.com/cljs/017/

HTH,
Jorge.

<script>
self.onload= function () {
var d= document, e, i, xhr, url,
t= 'Lorem ipsum dolor sit amet consectetuer adipiscing elit';
t+= 'Pellentesque velit Morbi laoreet lacinia neque Sed eros';
t= t.split(' ');

//Fill the DOM with 'text' tags with className 'translate'
do {
(y('text', e= t.shift(), 1)).className= 'translate';
} while (t.length)

var toTranslate= [];
//poor man's querySelectorAll()
walkTheDOM(d.body, function (node) {
if (node.className === 'translate') { toTranslate.push(node); }
});

//debug();
for (i= 0; i<toTranslate.length; ++i) {
e= toTranslate[i];
t= e.oldValue= e.firstChild.nodeValue;
url= "xhrData.txt?"+t+Math.random();
e.innerHTML= t+': XHR posted: '+url;
xhr= new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.onreadystatechange = (function (xhr, pDOMElement) {
return function () {
var txt= pDOMElement.oldValue;
if (xhr.readyState == 4) {
txt+= ': '+xhr.responseText.substring(0, 28);
} else {
txt+= ": readyState: "+xhr.readyState;
if (xhr.readyState == 3) { txt+= ": RECEIVING." }
}
pDOMElement.innerHTML= txt;
};
})(xhr, e);
xhr.send(null);
}

function y (p, inner, br) {
var e;
if (br) { d.body.appendChild(d.createElement('br')) }
e= d.body.appendChild(d.createElement(p));
if (inner) { e.innerHTML= inner; }
return e;
};

function walkTheDOM (node, f){
f(node);
node= node.firstChild;
while (node) {
walkTheDOM(node, f);
node= node.nextSibling;
}
};
};
</script>
Sep 25 '08 #9
On Thu, 25 Sep 2008 07:25:37 -0700 (PDT), an orbiting mind-control
laser made Kiran Makam <ki*******@gmail.comwrite:

-SNIP-
>To get all elements having a particular class, you can use
getElementsByClassName (google to find implementations of
getElementsByClassName function, Prototype has one)
Thanks. I'd already gotten that aspect running fine. The call to
getElementsByClassName was returning my array of "translate" elements
fine. Though, as I indicated in a previous post, the way my earlier
code was working, I was reduced to forcing the looped API calls to
function synchronously.
>code:
---------------
//class MyTranslationDiv
function MyTranslationDiv(objDiv){
this.div = objDiv;
}

MyTranslationDiv.prototype.update = function(result){
if (!result.error) {
this.div.innerHTML = result.translation;
}else{
this.div.innerHTML = "Error happened";
}

}

MyTranslationDiv.prototype.translate = function(textToTranslate){
var thisTmp = this;
google.language.translate(
textToTranslate, "en", "es",
function(result){thisTmp.update(result)}
);

}

//get all elements having className as 'translate'
var elements = getElementsByClassName("translate");

//iterate and translate
for(var i=0, len=elements.length; i<len; i++){
var obj = new MyTranslationDiv( elements[i] );
obj.translate("hello world");
}
/Very/ nice.

This solved my problem quite neatly. It's cut execution time
(always hostage to network latency) by at least 50%.

Thank you, very much.
>- Kiran Makam
-Joe
Sep 25 '08 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: Dave Nouwens | last post by:
Hi All, Please accept my appologies in advance for what I expect will be a reasonably simple question. I have an html form (which is generated in php) which contains a number of rows (one row...
0
by: alex | last post by:
I'm new to xslt, and I am attempting to use it to produce a comma-separated-value file from a large, dynamically-generated data file formatted in xml (examples of the xml file and my xslt style...
4
by: Eric | last post by:
How can I dynamically assign an event to an element? I have tried : (myelement is a text input) document.getElementById('myelement').onKeyUp = "myfnc(param1,param2,param3)"; ...
8
by: Falc2199 | last post by:
Hi, Does anyone know how to make this work? var sectionId = 5; repeat_section_sectionId(); function repeat_section_5(){ alert("firing"); }
3
by: Kiyomi | last post by:
Hello, I create a Table1 dynamically at run time, and at the same time, I would like to create LinkButton controls, also dynamically, and insert them into each line in my Table1. I would...
5
by: Rick Spiewak | last post by:
I need to generate a "buy" button as part of an ASP.NET page - this consists of a small HTML form with hidden fields, conforming to the requirements of a merchant credit card processor. PayPal is...
1
by: npaulus | last post by:
Hi, I am trying to dynamically add user controls on to my web form but for some reason my form isnt displaying the user control. form1.cs: using System; using System.Drawing; using...
6
by: | last post by:
I have made some user controls with custom properties. I can set those properties on instances of my user controls, and I have programmed my user control to do useful visual things in response to...
9
by: Allen | last post by:
The arguments of function is variable. Given function address, argument type and data, how to dynamically call the function? The following is pseudo code. int count = 0; int offset = 0; char...
11
by: Nadeem | last post by:
Hello all, I'm trying to write a function that will dynamically generate other functions via exec. I then want to be able to import the file (module) containing this function and use it in other...
0
by: veera ravala | last post by:
ServiceNow is a powerful cloud-based platform that offers a wide range of services to help organizations manage their workflows, operations, and IT services more efficiently. At its core, ServiceNow...
3
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 3 Jan 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). For other local times, please check World Time Buddy In...
0
by: jianzs | last post by:
Introduction Cloud-native applications are conventionally identified as those designed and nurtured on cloud infrastructure. Such applications, rooted in cloud technologies, skillfully benefit from...
0
by: abbasky | last post by:
### Vandf component communication method one: data sharing ​ Vandf components can achieve data exchange through data sharing, state sharing, events, and other methods. Vandf's data exchange method...
2
by: jimatqsi | last post by:
The boss wants the word "CONFIDENTIAL" overlaying certain reports. He wants it large, slanted across the page, on every page, very light gray, outlined letters, not block letters. I thought Word Art...
0
by: fareedcanada | last post by:
Hello I am trying to split number on their count. suppose i have 121314151617 (12cnt) then number should be split like 12,13,14,15,16,17 and if 11314151617 (11cnt) then should be split like...
0
by: stefan129 | last post by:
Hey forum members, I'm exploring options for SSL certificates for multiple domains. Has anyone had experience with multi-domain SSL certificates? Any recommendations on reliable providers or specific...
0
Git
by: egorbl4 | last post by:
Скачал я git, хотел начать настройку, а там вылезло вот это Что это? Что мне с этим делать? ...
1
by: davi5007 | last post by:
Hi, Basically, I am trying to automate a field named TraceabilityNo into a web page from an access form. I've got the serial held in the variable strSearchString. How can I get this into the...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.