I am new to Javascript, and I am trying to get this function to work, but what ever I do I can't get anonymous functions to work, when I switch to the normal function it works. I know that I can live without anonymous functions but it's really annoying me.
Example:
In the HTML file:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
</head>
<script type="text/javascript" src="ch10_2.js"> </script>
<body>
Go Searching
</body>
</html>
In the JavaScript file:
var s_link = document.getElementById("search_link");
s_link.onclick = function() {
var is_sure = window.confirm("Are you sure you want to leave?");
if (!is_sure) {
window.alert("OK. You can stay here.");
return false;
}
};
There are several problems here, each on its own would cause this script to fail:
Script tag is an illegal position in the document - between the <body> and <head> tags. It must be inside one of those.
Script tries to access a variable named 's_link' which should point to the link. For it to reference the link, you need to fetch the element using something like getElementById() or other DOM traversal methods [Edit - I see you've added that line after posting the question].
If the script is ran before the the element (link) is rendered (as it is now), it would not affect the element since it does not exist in the document yet. Either wrap it in a function that runs on document load, or place the script after the element in the document.
The link with the id search_link doesn't exist at the time the script runs, so it can't be fetched with getElementById or similar. You need to delay the execution of the code (e.g. by wrapping it in a function that executes onload or just moving the <script> element to after the link is parsed (just before </body> is often recommended).
It works for me.
Suggestion: Make sure to put your code at the end of the page just before </body>.
You should tell your script to execute after the page has loaded. To do this just wrap the code as shown below:
window.onload = function() {
// code you had before
}
The reason for this is simple. The script is currently being executed before the page is loaded. As such the document.getElementById() request is actually failing. It has nothing to do with your function being anonymous.
Just as Mr. Dorward pointed out, your script (at ch10_2.js) is executed before de DOM is ready.
The thing is, to attach an event to an element said element must exist but as javascript code is executed as soon as it is loaded the rest of the page is usually still loading. Therefore, the element you want to attach an event to does not exist yet.
I recommend this article about how jQuery (a javascript library) deals with this: http://www.learningjquery.com/2006/09/introducing-document-ready.
And here is a jsbin very simple example: http://jsbin.com/eziwu5/edit
Related
I'm learning Javascript and I'm very confused as to why I'm having issues with my javascript loading before the html when using Chrome. When I use Firefox and Edge, the page loads with the html first and then I get an alert. When I use Chrome though, I get the alert first and the background is just blank. Everything I'v learned so far seems to say that the js script should run after the html because it's at the bottom of the body tag.
Thanks!
home.html page
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>Hi, testing chrome.</h1>
<h2>Is this working?</h2>
<ul>
<li>list1</li>
<li>list 2</li>
<li>list 3</li>
</ul>
<script type="text/javascript" src="myjs.js"></script>
</body>
</html>
myjs.js page
alert("Am I working right?");
If you want to make your html load first before js make sure to wrap it with
document.addEventListener("DOMContentLoaded", function(event) {
// your code here
});
Since the JavaScript is single threaded, so when you call alert() function, it blocks other execution because it is an UI blocking function.
The web uses an event driven model to sequence actions. You are correct in assuming that if the script appears at the end of a document, it will be parsed later than if it appeared at the beginning. But the HTML spec does not specify explicitly that HTML has to be rendered before your script is executed. So parsing and rendering are different operations, and chrome may choose to execute the script as soon as it finishes parsing it.
So how can you sequence your actions correctly? The web in general and javascript in particular are event driven. Your code can listen to a variety of events and respond to them as you please. In this case, you want to execute your script after your document has loaded. Take a look at the DOMContentLoaded event.
Here's your code modified to run when the DOMContentLoaded event is fired.
document.addEventListener("DOMContentLoaded", function() {
alert("Am I working right?");
});
I have simply enclosed your alert function call in my event handler function.
An event handler function (or callback) must be registered on the element that emits the event, in our case, the document object. This is done by calling addEventListener() on that object with two arguments. The first is the event name that we want to listen to as a string, and the second is a function that must be executed when the event is fired.
There are many events defined for many different elements, and you can even define your own custom events and respond to them.
Place the code in Jquery document ready method
The function DOMContentLoaded let the browser execute a javascript code after the HTML content has loaded
document.addEventListener("DOMContentLoaded", function(event) {
/*it is verry easy now, you can write code here which will be executed when the
html content will end loading*/
});
Something you should always do in your JS files is put every direct code and DOM-related functions in a function to wait for the page to load.
In plain JavaScript :
window.onload = function() {
//Your JS here
};
Note that according to this post, you can use document.onload(function() {...});
With JQuery :
$(function() {
//Your JS here
});
In plain JavaScript, try this in myjs.js
$(window).on("load", function(){
var ss = document.createElement("script");
ss.src = "myjs.js";
ss.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(ss);
});
ELSE
Try this if jQuery is loaded.
$(function() {
alert("Am I wrong?");
});
You will need to add
<script src="https://cdn.jsdelivr.net/jquery/latest/jquery.min.js">
in the tag to include jQuery
This should make sure that the page is loaded. But please be informed that tag is also a part of the DOM
If the requirement is to execute the external JS after loading HTML, then you can try this.
$(function() {
var ss = document.createElement("script");
ss.src = "myjs.js";
ss.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(ss);
});
Consider the script..
<html>
<head>
<script type="text/javascript">
document.write('TEST');
</script>
</head>
<body>
Some body content ...
</body>
</html>
This works fine and the word 'TEST' is added to the <body>
But when
<script type="text/javascript">
window.onload = function(){
document.write('TEST');
}
</script>
is used, then the body content is fully replaced by the word 'TEST' i.e, the old body contents are removed and ONLY the word 'TEST' is added.
This happens only when document.write is called within window.onload function
I tried this in chrome. Is there any mistake made by me ? any suggestions ?
document.write() is unstable if you use it after the document has finished being parsed and is closed. The behaviour is unpredictable cross-browser and you should not use it at all. Manipulate the DOM using innerHTML or createElement/createTextNode instead.
From the Mozilla documentation:
Writing to a document that has already loaded without calling document.open() will automatically perform a document.open call. Once you have finished writing, it is recommended to call document.close(), to tell the browser to finish loading the page. The text you write is parsed into the document's structure model. In the example above, the h1 element becomes a node in the document.
If the document.write() call is embedded directly in the HTML code, then it will not call document.open().
The equivalent DOM code would be:
window.onload = function(){
var tNode = document.createTextNode("TEST");
document.body.appendChild(tNode);
}
in the first case the word is not written in the body .. it is written in the head
the first one works because the document is still open for writting.. once it has completed (DOM loaded) the document is closed, and by attempting to write to it you replace it ..
When document is full loaded, any further call to document.write() will override document content. You must use document.close() before calling document.write() to avoid overwriting.
First create an element, for example a div, than add content to the div with window.onload event.
document.write('<div id="afterpostcontent"><\/div>');
window.onload = function()
{
document.getElementById('afterpostcontent').innerHTML = '<span>TEST<\/span>';
}
You can create an external JavaScript file with this content and just call it anywhere, for example:
<script src="afterpostcontentcode.js"></script>
I would like to globally redefine a createElement method, but unfortunately it only works in a main document, and is ignored in iframes. Let's take this example code:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script>
old_createElement = document.createElement;
document.createElement = function(el_type) {
new_el = old_createElement.call(this, el_type);
new_el.style.color="red";
return new_el;
};
</script>
</head>
<body bgcolor="white">
<iframe id="iframe1"></iframe>
<script type="text/javascript">
window.setTimeout(function(){
iframe_el = document.getElementById("iframe1").contentDocument.createElement("div");
iframe_el.innerHTML = 'inside iframe';
document.getElementById("iframe1").contentDocument.body.appendChild(iframe_el);
},50);
no_iframe_el=document.createElement('div');
no_iframe_el.innerHTML = 'outside of iframe';
document.body.appendChild(no_iframe_el);
</script>
</body>
</html>
When i open in in a browser, the element created in a main document has red color, as expected, but the one in the iframe is black.
The problem is that I only have control on the script contained in the HEAD section of the document. In other words, i don't know how many iframes there will be later on in the HTML source, or how they will be names, or if they are added via user's Javascript.
My question is: how can i change the method globally, so all elements created in iframes also use this new style?
Thanks a lot!
Each frame has it's own separate Javascript context. If you want to change that frame's context, you have to do it specifically for that frame.
In your specific example, each frame has its own document object so it should be no surprise that each document has its own .createElement property.
You cannot generically change things in a way that will affect all frames. And, in fact if it's a cross-origin frame, you can't change it at all.
This question already has answers here:
Why does jQuery or a DOM method such as getElementById not find the element?
(6 answers)
Closed 8 years ago.
<html>
<head>
<title>Test javascript</title>
<script type="text/javascript">
var e = document.getElementById("db_info");
e.innerHTML='Found you';
</script>
</head>
<body>
<div id="content">
<div id="tables">
</div>
<div id="db_info">
</div>
</div>
</body>
</html>
If I use alert(e); it turns up null.... and obviously I don't get any "found you" on screen. What am I doing wrong?
The problem is that you are trying to access the element before it exists. You need to wait for the page to be fully loaded. A possible approach is to use the onload handler:
window.onload = function () {
var e = document.getElementById("db_info");
e.innerHTML='Found you';
};
Most common JavaScript libraries provide a DOM-ready event, though. This is better, since window.onload waits for all images, too. You do not need that in most cases.
Another approach is to place the script tag right before your closing </body>-tag, since everything in front of it is loaded at the time of execution, then.
How will the browser know when to run the code inside script tag? So, to make the code run after the window is loaded completely,
window.onload = doStuff;
function doStuff() {
var e = document.getElementById("db_info");
e.innerHTML='Found you';
}
The other alternative is to keep your <script...</script> just before the closing </body> tag.
Script is called before element exists.
You should try one of the following:
wrap code into a function and use a body onload event to call it.
put script at the end of document
use defer attribute into script tag declaration
The script is performed before the DOM of the body is built. Put it all into a function and call it from the onload of the body-element.
Run the code either in onload event, either just before you close body tag.
You try to find an element wich is not there at the moment you do it.
I'm attempting to call a javascript function (in our code) from a silverlight control. I'm attempting to call the function via:
HtmlPage.Window.Invoke("showPopup", new string[] { "http://www.example.com" });
and I get the error "Failed to Invoke: showPopup"
I can call HtmlPage.Window.Invoke("alert", new string[]{"test"}); without issue, but not my own function.
I can also open up the page in question in the IE developer tools and manually call showPopup("http://www.example.com") and it works as expected.
So the js function works, and the Silverlight binary can find other js functions. What am I missing here?
Additional Notes:
The function call is in a button click event handler, so it happens after the page (and the script) have been loaded)
Aha! I figured it out. Our app uses an iframe, so the rendered html looks something like this
<html>
<head></head>
<body>
Stuff
<iframe>
<html>
<head></head>
<body>Other Stuff</body>
</html>
</iframe>
<body>
</html>
And the Silverlight control in question is in the iframe. The problem was that the file that contained the showPopup function was referenced in the outer <head> (why I could call the function with the IE toolbar) but not the inner <head>. Adding a reference to the file in the in-the-iframe <head> solved the problem.
Sort of anticlimactic, but thanks for all the help.
Actually referencing the script again from the iframe is not the most efficient way to reference code contained in the parent. If your function is called "showPopup", you can insert this in your iframe:
<script type="text/javascript">
var showPopup = parent.showPopup;
</script>
And voilĂ . The explanation for this is that all "global" functions and objects are part of this "global namespace"... which is the "window" object. So if you're trying to access "global" functions from a child, you need to either call the function on the parent (e.g parent.showPopup('....')) or declare a local alias for it (which is what we do in the above example).
Cheers!
Is the showPopup javascript function on the same html or aspx page as the Silverlight control? You will normally get the "Failed to Invoke ..." error if the javascript function does not exist:
HtmlPage.Window.Invoke("functionThatDoesNotExist", new [] { "Testing" });
What browser are you using when you are getting this problem?
Are you using the latest version of Silverlight?
Are you using the ScriptableType attrbiute anywhere?
Is it possible to list the code for a short but complete program that causes this problem to happen on your machine...
Make sure your script is fully loaded before trying to invoke functions from it.
Here's how I do it. But I'm creating silverlight without visual studio. I just have raw html, xaml, and js (javascript). Notice MouseLeftButtonUp and it's value "LandOnSpace"
<Canvas x:Name="btnLandOnSpace" Background="LightGreen" MouseLeftButtonUp="LandOnSpace"
Cursor="Hand" Canvas.Top ="0" Width="70" Height="50">
<TextBlock Text="LandOnSpace" />
</Canvas>
function LandOnSpace(sender, e) { //on server
if (!ShipAnimateActive && !blnWaitingOnServer) {
blnWaitingOnServer = true;
RunServerFunction("/sqgame/getJSLLandOnSpace");
ShowWaitingBox();
};
else {
alert('Waiting on server.');
};
}
I had the same problem in VS 2010 with SL 4. I had created a few methods and put them into one single JS file. However this file had not been added to the head section of the ASPX file. Adding it solved the problem. The difference is that though I did not have a separate head section in the iframe, I had the problem and it got solved.