Injecting scripts through innerHTML: functions vs global - javascript

I have some HTML structured as follows
<script>
function x()
{
alert('works');
}
</script>
<table>
(...)
</table>
<script>
console.log('autoexec');
</script>
I am loading this HTML from a file in a DIV's innerHTML through an XMLHttpRequest.
Upon completion of the request, this is what I do
div.innerHTML = request.responseText;
var scripts = div.getElementsByTagName("script");
for(var i=0;i<scripts.length;i++) eval(scripts[i].text);
The bottom script, containing code outside a function, gets executed.
However the function x() in the top script isn't evaluated and remains unavailable.
What am I missing?
Thanks

Solved. Instead of eval(scripts[i].text) I now use document.head.appendChild(scripts[i]). This both correctly executes the code outside the function AND makes the function available for calling.

Related

Function of Javascript in HTML

I'm sorry if this question is too trivial. Since I'm a beginner, it is difficult for me to understand some explanation. What is the meaning of the following statement?
"To keep the browser from executing a script when the page loads, you can put your script into a function."
I think the author meant that if you do this:
<script>
alert('Hello');
</script>
The script will run when the page load. But you can wrap that in a function:
<script>
function hello() {
alert('Hello');
}
</script>
So instead of popping "Hello" the script will register the function that can be called later from another place/script to display "Hello" on the screen.
The script wont be executed until the function is called, otherwise the script will automatically execute when it the page loads. :)
Consider the following script
alert("hey");
Browser pauses html rendering and tries to download the javascript and execute it.
This code simply involves an alert message,there could be dom search ,so to avoid this you consider doing as follows
Greet();
function Greet(){
alert("hello");
}
In this, until you call greet method ,script wont execute .So html rendering does not stop.
Consider if your code has dom search, even adding functions would not help
Here, you should consider using window.onload or $(document).ready
window.onload=function(){
var div= document.getElementsByTagName('div');
div[0].innerHTML="Hello";
}
<div>
</div>

Executing script written inside the div when the div dynamically loads on to the page

I have a div which looks like
<div>
//Useful content
<script type="text/javascript">
function(){
//some useful code
}
</script>
</div>
Now am getting this div as a response of an Ajax call and appending that into body. Now when the gets appended to body, the function inside the script tag should get executed. But not.. what is the problem here?
You should be using document.createElement("script"); if you need to insert some script dynamically. This is recommended approach.
Anyway, following code is working just fine for me:
var str = "<script>alert('Hi!');</scr"+"ipt>";
$('#container').append($(str)[0]);
Make sure you escape you script properly.
Your function is not executing because it is not being called.
You should use a self-executing function that will just run as soon as it's loaded:
(function() {
alert('hello world!');
})();

Calling JQuery function from different context

This might be a very basic question but I'm trying to understand this behavior
This is my javascript code. I want to know why second call to foo does not work. Here is the JSFiddle link
$.fn.foo = function(somestring){
var $this = this;
$this.html(somestring);
}
$(function(){
$('#container').foo("within function"); //this works
});
$('#container').foo("outside"); //this does not
The DOM is not fully loaded .. Thats the reason it won't work..
So when you encase your code inside the DOM Ready handler it waits for the document to be loaded and then runs the code inside.
This makes sure the element is available before any code is run on it..
When the HTML document is parsed , it parses top down.
So if the script is included in the head section , then the scripts are loaded first and then the HTML structure.. When you try to the run the code , it obviously won't work cause the element was still not parsed..
So encasing that in the handler will make sure the element is available before calling the methods on them..
This is because $('#container').foo("outside"); is evaluated before the body is processed. $('#container') will return with a length of 0. This is demonstrated below.
$.fn.foo = function(somestring){
var $this = this;
$this.html(somestring);
}
$(function(){
$('#container').foo("within function");
});
var element = $('#container');
console.log(element.length); //prints 0
element.foo("outside");
If the script is at the beginning of the page the rest of the HTML document has not been parsed yet, so the document looks empty to the script, so there is no #container yet.
$(function() { ... });
is (roughly) equivalent to
Wait till the whole HTML file is loaded and ready
Then execute function
so #container will be there and it will work. Another way to make it work would be to put the script below the rest of the page or at least below #container.

JavaScript scope error, variables undefined

Please look at this code:
<script>
var mygrid;
function lock(){
for (var i=1; i<15; i++)
{
var cur_row=i + "";
mygrid.lockRow(cur_row,true);
mygrid.setRowColor(i,"#E5E5E5");
}
}
function doInitGrid(){
mygrid = new SomeClass;
}
</script>
</head>
<body onload="doInitGrid()" dir=rtl>
<div id="mygrid_container" style="width:905px;height:550px;"></div>
<script>lock();</script>
<button onclick="addRow()">Add Row</button>
<button onclick="removeRow()">Remove Row</button>
<button onclick="lock()">lock Row</button>
</body>
Why when I run lock function (Without the button), my var is undefined, and when I click on the button everything is ok?
This is a timing issue, not a scope issue.
You call doInitGrid() only onload so it won't assign a value to mygrid until after the document has finished loading.
When you call lock() inline, you do so as the document loads.
Presumably you have waited until the document has finished loading before clicking on the button.
If by "my var is undefined" you mean that the variable mygrid is undefined, that's because you initialise it inside the function doInitGrid() which is not called until onload of the page. The onload event happens after the whole page has finished loading. Other inline script runs when the browser encounters it as it parses the document.
I am not sure when you have called the lock function without clicking button. But it appears that that the doInitGrid function was not executed when you have executed the lock function. The below code may work
function lock(){
if(!mygrid){
doInitGrid();
}
for (var i=1; i<15; i++)
{
var cur_row=i + "";
mygrid.lockRow(cur_row,true);
mygrid.setRowColor(i,"#E5E5E5");
}
}
You are calling load() before the document gets loaded completely. So your variable is not assigned as doInitgrid is not yet called.(it gets called only after document is fully loaded)
You are instantiating mygrid inside the function doInitGrid() which is called only on onload. But your script statement <script>lock();</script> executes before the page is loaded as it is part of the page HTML. When this script block executes, the value of mygrid is undefined which is the default value set by JS for all variables declared without an initial value.
If you want to call lock() when the page loads up, call it on onload after the call to doInitGrid() like this:
<body onload="doInitGrid(); lock();" dir=rtl>
Quentin has answered your question, But I'd like to add that it would be better to clean up your code a bit. Something like this.
<script>
function lock(mygrid){ //pass in the grid var
for (var i=1; i<15; i++)
{
var cur_row=i + "";
mygrid.lockRow(cur_row,true);
mygrid.setRowColor(i,"#E5E5E5");
}
}
function getInitGrid(){
//some initialization code here maybe. Otherwise just take this out
return new SomeClass;//return an instance
}
var mygrid = getInitGrid();
//and then pass in the mygrid variable wherever you call lock
lock(mygrid);
</script>

Jquery manage local script with full ajax site

Basically my app work like that :
Index.php manage call to other pages.
Each page contains 2 function onLoad() and onClose() which are redefined in each page
Index.php call the pages and execute the onLoad
Basically, i preload the page in a hidden div, i execute the predefined $.onLoad function and the i put the loaded content into a visible div
My question is only about the onLoad() scope, i want to remove code from the jquery eval seq when i change page, but i need a way to define it in the page.php file without knowing the container
The eval/seq is probably the eval queue of jquery, can't found info about that, just obtain with firebug...
In 2 words, i would like to be able to remove injected dom and script when i change context (pages)
index.php
$.onLoad = function() {}
$("#blabla").onChange(function() {
$("#data_iframe").load(chaineUrl, {}, function(responseText, textStatus, XMLHttpRequest) {
$("#data_iframe").ready(function() {
$("#data_div").children().remove();
$.onLoad();
$("#data_iframe").children().hide().appendTo($("#data_div")).show(); $("#data_iframe").children().remove();
$.onLoad = undefined;
}
});
});
page.php
<script>
$.onClose = (function(){
$('#container').blablabla();
//alert("test");
});
$.onLoad = (function(){
$('#container').blablabla();
}
</script>
The problem is that the jquery EVAL/SEQ keep growing each time a page is opened
and there are some side-effect like calling multiple time a function...
I guess its a scope problem so can you help me correct my code
(i've try with or without the $ but doesn't change anything)
just for information
<div id="data_div"></div>
<div id="data_iframe"></div>
Thanks
I usually use $(document).ready instead of onload. No need to do the "onload" trigger in load complete function. The ready function within the page.php will do the same job.
And how about direct load into data_div?
index.php
$("#blabla").onChange(function() {
$("#data_div").load(page.php);
});
page.php
<script>
$(document).ready(function() {
$('#container').blablabla();
});
</script>
I didn't try page close function before, may be it is not what you want. But you can try:
<script>
$(document).ready(function() {
$('#container').blablabla();
$(window).unbind('unload');
$(window).unload(function(){
$('#container').blablabla();
//alert("test");
})
});
</script>

Categories

Resources