[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.javascript

Dynamically add/remove code in browsers

Leonardo Azpurua

1/12/2015 8:52:00 AM

Hi,

I am planning to implement a Web interface for a rich/fat client Windows
business system.

In its current implementation, the system allows searching whenever the Id
of an entity is required, and new entities can be created "in-line" by
provided a valid, non-existant id.

Now, in some forms, there may several kinds of entitites (items, customers,
payment conditions, pricing profiles, salesmen).

It doesn't sound practical to clutter the basic HTML page with all the divs,
code and controls required to manage all the possible creations.

So I am trying to find a way to dynamically add a DIV, give it a "standard
look", populate it with input controls, show it as a sort of modal dialog,
close it and restore the browser to its original state.

As for code, this is a very basic test of an approach:

var sc;

function addHandler() {
var el = document.getElementById("test");
sc = document.createElement("script");
sc.id = "dynScript";
sc.type = "text/javascript";
// the value assigned to the script will be a rather large chunk of
code imported by an httpRequest
sc.text = "function handleClick() { window.alert('Test clicked') }";
document.getElementsByTagName("head")[0].appendChild(sc);
el.onclick = handleClick;
}

function removeHandler() {
var el = document.getElementById("test");
el.onclick = null;
document.getElementsByTagName("head")[0].removeChild(sc);
sc = null;
}

That is:
On Creation:
Have the document create an SCRIPT element, and append it to the HEAD
element (is this necessary?).
Assign the functions to the event handlers of the appropriate controls
(this would be handled by the new code itself)
On Disposing
Remove all the event handlers
Remove the SCRIPT element from the document
Dispose of the script element itself.

Does this sound like a right approach, or am I totally missing it?


9 Answers

Thomas 'PointedEars' Lahn

1/12/2015 4:22:00 PM

0

Leonardo Azpurua wrote:

> var sc;
>
> function addHandler() {
> var el = document.getElementById("test");
> sc = document.createElement("script");
> sc.id = "dynScript";
> sc.type = "text/javascript";
> // the value assigned to the script will be a rather large chunk of
> code imported by an httpRequest
> sc.text = "function handleClick() { window.alert('Test clicked') }";

You should not clutter the global namespace. Any global handleClick()
function in the document or in memory will be overwritten/shadowed by that
code. Consider instead a user-defined globally accessible object that you
use as namespace:

var leo = {};

(â??leoâ? then refers to that object.)

And in the script to be loaded:

leo.handleClick = function () { window.alert('Test clicked') };

It may even be better if you have a property for each use-case. Otherwise
you would fill heap memory with inaccessible Function instances as the same
propertyâ??s value is replaced. Also consider JSONP.

In any case, you should move the part that inserts the â??scriptâ? element to a
separate function/method.

> document.getElementsByTagName("head")[0].appendChild(sc);
> el.onclick = handleClick;

You cannot assume that the script has been loaded and executed once you
inserted the â??scriptâ? element in the document.

You need to listen to and handle the â??loadâ? event of the â??scriptâ? element:

sc.onload = function () {
el.onclick = handleClick;
};

But it is presently unknown to me where this feature now standardized in
HTML5 is supported. Thus, it may be necessary to use setTimeout()-based
polling to determine if execution has reached the end of the loaded script
before you continue.

Also, you can use the â??document.headâ? property if it is available:

(document.head || document.getElementsByTagName("head")[0])
.appendChild(sc);

It might be easier to use the backwards-compatible â??document.bodyâ? property
instead:

document.body.appendChild(sc);

> }
>
> function removeHandler() {
> var el = document.getElementById("test");
> el.onclick = null;
> document.getElementsByTagName("head")[0].removeChild(sc);

If you are accessing the â??scriptâ? element by object reference, so it does
not need an ID.

> Does this sound like a right approach,

Only if the script you are loading is large and you can ensure that you can
determine when execution has reached the end of the script.

--
PointedEars
FAQ: <http://PointedEars.... | SVN: <http://PointedEars.de...
Twitter: @PointedEars2 | ES Matrix: <http://PointedEars.de/es-...
Please do not cc me. / Bitte keine Kopien per E-Mail.

JR

1/12/2015 6:44:00 PM

0

On 12/01/2015 14:21, Thomas 'PointedEars' Lahn wrote:
> Leonardo Azpurua wrote:
>
>> var sc;
>>
>> function addHandler() {
>> var el = document.getElementById("test");
>> sc = document.createElement("script");
>> sc.id = "dynScript";
>> sc.type = "text/javascript";
>> // the value assigned to the script will be a rather large chunk of
>> code imported by an httpRequest
>> sc.text = "function handleClick() { window.alert('Test clicked') }";
>
> You should not clutter the global namespace. Any global handleClick()
> function in the document or in memory will be overwritten/shadowed by that
> code. Consider instead a user-defined globally accessible object that you
> use as namespace:
>
> var leo = {};
>
> (â??leoâ? then refers to that object.)
>
> And in the script to be loaded:
>
> leo.handleClick = function () { window.alert('Test clicked') };
>
> It may even be better if you have a property for each use-case. Otherwise
> you would fill heap memory with inaccessible Function instances as the same
> propertyâ??s value is replaced. Also consider JSONP.
>
> In any case, you should move the part that inserts the â??scriptâ? element to a
> separate function/method.
>
>> document.getElementsByTagName("head")[0].appendChild(sc);
>> el.onclick = handleClick;
>
> You cannot assume that the script has been loaded and executed once you
> inserted the â??scriptâ? element in the document.
>
> You need to listen to and handle the â??loadâ? event of the â??scriptâ? element:
>
> sc.onload = function () {
> el.onclick = handleClick;
> };
>
> But it is presently unknown to me where this feature now standardized in
> HTML5 is supported. Thus, it may be necessary to use setTimeout()-based
> polling to determine if execution has reached the end of the loaded script
> before you continue.
>
> Also, you can use the â??document.headâ? property if it is available:
>
> (document.head || document.getElementsByTagName("head")[0])
> .appendChild(sc);
>
> It might be easier to use the backwards-compatible â??document.bodyâ? property
> instead:
>
> document.body.appendChild(sc);
>
>> }
>>
>> function removeHandler() {
>> var el = document.getElementById("test");
>> el.onclick = null;
>> document.getElementsByTagName("head")[0].removeChild(sc);
>

ACK.


> If you are accessing the â??scriptâ? element by object reference, so it does
> not need an ID.
>

However, what if there are other scripts in the document? And what if
the new script element already exists? Then, an ID would be of great
value to optimization.

All those questions would be better addressed by the following approach:
<http://calendar.perfplanet.com/2014/the-pain-of-duplicate-sc...

(function(d, s, id){
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {return;}
js = d.createElement(s); js.id = id;
//js.src = "//localhost/test.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'dynScript'));


--
Joao Rodrigues

Leonardo Azpurua

1/12/2015 6:51:00 PM

0


"Thomas 'PointedEars' Lahn" <PointedEars@web.de> escribió en el mensaje
news:11460823.sCPipJV62P@PointedEars.de...
>> Does this sound like a right approach,
>
> Only if the script you are loading is large and you can ensure that you
> can
> determine when execution has reached the end of the script.

Thank you very much.

A most precise answer and useful comments.



Thomas 'PointedEars' Lahn

1/12/2015 9:01:00 PM

0

Joao Rodrigues wrote:

> On 12/01/2015 14:21, Thomas 'PointedEars' Lahn wrote:
>> If you are accessing the â??scriptâ? element by object reference, so it does
>> not need an ID.
>
> However, what if there are other scripts in the document?

Then a dynamically inserted â??scriptâ? element with an ID would be an
additional problem because IDs must be unique.

> And what if the new script element already exists? Then, an ID would be of
> great value to optimization.

On the contrary. You would need to determine if the ID was already used by
an element and try a different one until you find an unused one. And for
what? If you have a reference to the object that represents the â??scriptâ?
element that you inserted before, you can simply reuse that reference (if
you think you need to remove it). No ID necessary, and no
document.getElementById() calls necessary.

> All those questions would be better addressed by the following approach:
> <http://calendar.perfplanet.com/2014/the-pain-of-duplicate-sc...
>
> (function(d, s, id){
> var js, fjs = d.getElementsByTagName(s)[0];
> if (d.getElementById(id)) {return;}
> js = d.createElement(s); js.id = id;
> //js.src = "//localhost/test.js";
> fjs.parentNode.insertBefore(js, fjs);
> }(document, 'script', 'dynScript'));

This code is addressing a different use-case, and it is adressing it most
poorly. Do not believe everything you read.

Please trim your quotes to the relevant minimum.

--
PointedEars
FAQ: <http://PointedEars.... | SVN: <http://PointedEars.de...
Twitter: @PointedEars2 | ES Matrix: <http://PointedEars.de/es-...
Please do not cc me. / Bitte keine Kopien per E-Mail.

Thomas 'PointedEars' Lahn

1/12/2015 9:03:00 PM

0

Leonardo Azpurua wrote:

> Thank you very much.
>
> A most precise answer and useful comments.

You are welcome.

--
PointedEars
FAQ: <http://PointedEars.... | SVN: <http://PointedEars.de...
Twitter: @PointedEars2 | ES Matrix: <http://PointedEars.de/es-...
Please do not cc me. / Bitte keine Kopien per E-Mail.

Joao Rodrigues

1/13/2015 12:06:00 AM

0

On 01/12/2015 07:01 PM, Thomas 'PointedEars' Lahn wrote:
> Joao Rodrigues wrote:
>
>> On 12/01/2015 14:21, Thomas 'PointedEars' Lahn wrote:
>>> If you are accessing the â??scriptâ? element by object reference, so it does
>>> not need an ID.
>>
>> However, what if there are other scripts in the document?
>
> Then a dynamically inserted â??scriptâ? element with an ID would be an
> additional problem because IDs must be unique.

Oops. In fact, I was pondering your suggestion about using
document.getElementsByTagName("head")[0], instead of
document.getElementsByTagName("script")[0].


>> And what if the new script element already exists? Then, an ID would be of
>> great value to optimization.
>
> On the contrary. You would need to determine if the ID was already used by
> an element

Exactly!

> and try a different one until you find an unused one. And for
> what? If you have a reference to the object that represents the â??scriptâ?
> element that you inserted before, you can simply reuse that reference (if
> you think you need to remove it). No ID necessary, and no
> document.getElementById() calls necessary.

The intention was to avoid duplicate scripts, not to reuse the same script:

if (document.getElementById(id)) { return; }


--
Joao Rodrigues

Thomas 'PointedEars' Lahn

1/13/2015 12:12:00 AM

0

Joao Rodrigues wrote:

> On 01/12/2015 07:01 PM, Thomas 'PointedEars' Lahn wrote:
>> Joao Rodrigues wrote:
>>> On 12/01/2015 14:21, Thomas 'PointedEars' Lahn wrote:
>>>> If you are accessing the â??scriptâ? element by object reference, so it
>>>> does not need an ID.
>>> However, what if there are other scripts in the document?
>> Then a dynamically inserted â??scriptâ? element with an ID would be an
>> additional problem because IDs must be unique.
>
> Oops. In fact, I was pondering your suggestion about using
> document.getElementsByTagName("head")[0], instead of
> document.getElementsByTagName("script")[0].

I have not suggested such a nonsense.

>>> And what if the new script element already exists? Then, an ID would be
>>> of great value to optimization.
>> On the contrary. You would need to determine if the ID was already used
>> by an element
>
> Exactly!

Which is unnecessary in this case and most other cases. Objects have built-
in identity.

>> and try a different one until you find an unused one. And for
>> what? If you have a reference to the object that represents the â??scriptâ?
>> element that you inserted before, you can simply reuse that reference (if
>> you think you need to remove it). No ID necessary, and no
>> document.getElementById() calls necessary.
>
> The intention was to avoid duplicate scripts, not to reuse the same
> script:
>
> if (document.getElementById(id)) { return; }

AISB, a different use-case. And handled most poorly.

--
PointedEars
FAQ: <http://PointedEars.... | SVN: <http://PointedEars.de...
Twitter: @PointedEars2 | ES Matrix: <http://PointedEars.de/es-...
Please do not cc me. / Bitte keine Kopien per E-Mail.

JR

1/13/2015 2:17:00 PM

0

Thomas Lahn wrote:

> You cannot assume that the script has been loaded and executed once you
> inserted the â??scriptâ? element in the document.
>
> You need to listen to and handle the â??loadâ? event of the â??scriptâ? element:
>
> sc.onload = function () {
> el.onclick = handleClick;
> };
>
> But it is presently unknown to me where this feature now standardized in
> HTML5 is supported. Thus, it may be necessary to use setTimeout()-based
> polling to determine if execution has reached the end of the loaded script
> before you continue.

onload is not supported in IE8 and below. So, in this case, one could
use the readystatechange event. E.g.:

// IE8 and below
if (sc.readyState) {
sc.onreadystatechange = function () {
if (sc.readyState == "loaded" || sc.readyState == "complete") {
script.onreadystatechange = null;
el.onclick = handleClick;
}
};
} else { // FF, Chrome, Safari, Opera, etc.
sc.onload = function () {
el.onclick = handleClick;
};
}

An alternate method would be XMLHttpRequest() which works in all modern
browsers. A caveat is the same-origin policy, which prevents downloading
the script from CDNs for instance.

>
> Also, you can use the â??document.headâ? property if it is available:
>
> (document.head || document.getElementsByTagName("head")[0])
> .appendChild(sc);
>
> It might be easier to use the backwards-compatible â??document.bodyâ? property
> instead:
>
> document.body.appendChild(sc);
>

document.body.appendChild(sc) could be problematic in older versions of
IE. See
<http://www.nczonline.net/blog/2008/03/17/the-dreaded-operation-aborted-...

--
Joao Rodrigues

Thomas 'PointedEars' Lahn

1/13/2015 7:50:00 PM

0

Joao Rodrigues wrote:

> Thomas Lahn wrote:
>> Also, you can use the â??document.headâ? property if it is available:
>>
>> (document.head || document.getElementsByTagName("head")[0])
>> .appendChild(sc);
>>
>> It might be easier to use the backwards-compatible â??document.bodyâ?
>> property instead:
>>
>> document.body.appendChild(sc);
>
> document.body.appendChild(sc) could be problematic in older versions of
> IE. See
> <http://www.nczonline.net/blog/2008/03/17/the-dreaded-operation-aborted-...

That does not apply here:

,-<http://support2.microsoft.com/kb/927917...
|
| [â?¦]
| This problem occurs because a child container HTML element contains script
| that tries to modify the parent container element of the child container.
| The script tries to modify the parent container element by using either
| the innerHTML method or the appendChild method.

Also:

| Answer: Internet Explorer 7 cannot display a particular element on a Web
| page on that Web site.
|
| [â?¦]
| How do I fix this problem?
|
| The easiest way for you to fix the problem is to upgrade to Internet
| Explorer 8. This problem no longer occurs in Internet Explorer 8.

--
PointedEars
FAQ: <http://PointedEars.... | SVN: <http://PointedEars.de...
Twitter: @PointedEars2 | ES Matrix: <http://PointedEars.de/es-...
Please do not cc me. / Bitte keine Kopien per E-Mail.