document.write() overwriting the document? - javascript

This:
function myFunction()
{
document.write("sup");
}
called in html like:
<div id="myDiv">
<script>myFunction();</script>
</div>t
adds a string sup to the myDiv div element. Which is what I want, exactly. However, this:
function loadFile(uri)
{
var r = new XMLHttpRequest();
document.write("trying to open: " + uri);
r.open('GET', uri, true);
r.send(null);
r.onreadystatechange = function()
{
if (r.readyState == 4)
{
myFunction();
}
}
}
function myFunction()
{
document.write("sup");
}
called like this:
<div id="myDiv">
<script>loadFile("filename.txt");</script>
</div>
seems to be overwriting my whole html file. I.e. when I run it in Firefox it shows me only the string sup (that's the whole content of the page) but the page seems to be still loading (the loading icon of FF is still there animating, apparently infinitely).
First of all, this is going to be used only locally, offline, as a fast and handy way of presenting data (using html+js and web browser instead of plain text file). What I want is to load a local text file and then put some of its content as a part of the html page. The same as in my first example but with loading the text file first.

The issue is that when you run document.write after the document has loaded, it overwrites the entire document. If it is run before that, it does not overwrite it.
What you want to do is set the innerHtml of a specific element, something like:
document.getElementById("myDiv").innerHTML="Sup";

Lets go over what a browser does when it receives an html file.
The window document is opened for writing. Imagine opening a text file.
Browser writes the contents to the document. A lot of magic happens in this step - objects get created and html rendered as boxes.
The window document closes the document. Kind of like saving the text file.
Now, modern browsers also expose a document API that allow you to do exactly those tasks using javascript.
You can open a document for writing using document.open(). You can also start writing content to the document using document.write(). Finally, you can close the document for writing using document.close(). Since the document always needs to be opened for writing before you write, calling document.write() always results in an implicit document.open().
Interspersing document.write() calls throughout an html body is a commonly used technique used to insert string contents dynamically into an html page.
For example, if you execute document.write("<p>holla</p>") in the body of an html file, the browser will do the following upon receiving the html file.
Open the document for writing.
Start writing the html contents to the document.
JavaScript engine will execute document.write() when it encounters it and then write "<p>holla</p>" into that specific line in the document, just as if the string was already part of the html file! Since document.write() is called during the parsing of an html file, it just gets parsed as part of the page.
Close the document for writing. Parsing complete.
If that's how you use document.write(), there would have been no surprise. Instead, you call document.write() after the html is parsed.
So what do you think should happen?
As I mentioned before, a document needs to be opened for writing before it is written to. In theory, we could either append to the existing content or just overwrite it. Well, if we append to the content, we'll end up with an invalid html page because the new values will appear after the closing tags. So the more sensible behavior is to overwrite the content and that's exactly what happens.

Related

What happen if an exactly the same JS dynamic load fails the second time after successful load the first time? [duplicate]

I am including some related content on misc. web pages by adding a <script> tag near the end of the <body> tag, which then loads other javascript files. The flow is a little convoluted, so I’ll try to explain it before asking my question:
A browser loads a page with our <script> element near the end of the <body> element
The src attribute of the script tag points to a javascript file which (in some cases) injects a second <script> element
The src attribute of the injected <script> element points to yet another javascript file, which finally injects some content on the appropriate part of the page.
We are using this two-stage approach to be able to do some basic processing before deciding whether to include the final content, which could take some time to load.
The problem is that IE8 (and maybe older versions) loads the last javascript twice. It appears that the act of setting the src attribute will trigger a load, but so will appending the script tag to the DOM. Is there any way to avoid this?
I have created a bare-bones demo of the problem. If you have some way of tracing the HTTP requests, you will see that IE8 loads js_test2.js twice.
The root difference is that IE executes a script element the first time it is added to a parent element's childNodes, regardless of whether the parent element is actually in the document. Other browsers only execute script when it is added to a node inside the document's tree of childNodes.
jQuery's domManip function (line 524 of jQuery 1.3.2), which is called by append and other similar jQuery methods, tries to be clever and calls evalScript for any <script> elements it finds in the final parsed HTML, to execute the script (by doing AJAX requests if necessary for external scripts). (The actual script elements have been removed from the parsed childNodes to stop them getting executed on insertion into the document, presumably so that scripts are only executed once when content containing them is appended into multiple elements at once.)
However, because the previous clean function, whilst parsing the HTML, appended the script element to a wrapper div, IE will have already executed the script. So you get two executions.
The best thing to do is avoid using domManip functions like append with HTML strings when you're doing anything with scripts.
In fact, forget putting your content in a serialised HTML string and getting jQuery to parse it; just do it the much more reliable plain DOM way:
var s= document.createElement('script');
s.type= 'text/javascript';
s.charset= 'UTF-8';
s.src= 'js_test2.js';
document.getElementById('some_container').appendChild(s);
(To be honest, after viewing the stomach-churning source code of the clean function, I'm having serious doubts about using jQuery's HTML-string-based DOM manipulations for anything at all. It's supposed to fix up browser bugs, but the dumb-regex processing seems to me likely to cause as many problems as it solves.)
Incidentally with this initial call:
document.write(unescape("%3Cscript src='js_test1.js' type='text/javascript'%3E%3C/script%3E"));
You don't need to unescape here; I don't know why so many people do. The sequence </ needs to be avoided in an inline script as it would end the <script> tag, and if you're doing XHTML < and & should be avoided too (or ]]> if you're using a CDATA wrapper), but there's an easier way of doing all that with just JavaScript string literals:
document.write('\x3Cscript src="js_test1.js" type="text/javascript">\x3C/script>"));
I've seen that behavior happening on other versions of IE under similar circumstances (such as cloning of <script> nodes) and I never got to know how to stop the script from executing twice, so what I ended up doing was adding a guard on the script code for it not to run twice. It was something like:
if (typeof(loaded) == 'undefined') {
// the whole code goes in here
var loaded = true;
}
If you can't find a way of preventing the script to execute twice, you may want to try that approach instead.
It would seem that jquery is fetching the second instance of js_test2 using XmlHttpRequest.
Why I don't know but its the behaviour of JQuery you need to investigate.
You can check to see if a script is already in the document before loading it-
function fetchscript(url, callback){
var S= document.getElementsByTagName('script'), L= S.length;
while(L){
if(S[--L].src== url) return true;
}
//create and append script and any callbacks
}
I find the same problem,only happen in IE.
jQuery‘s html() method chains is: html>append>domManip>clean
clean() method use innerHTML make string to DOM, innerHTML in IE has a bug that script tag will immediately load(first load), jQuery evalScript script tags at the end of domManip method(ajax load).then script file load twice in IE.
I think jQuery should fix this problem,update the clean() method
It's possible that this is because you use document.write when you're already in a <script> element. Have you tried appending to <head> instead of document.write?

Executing javascript in ajax response

I'm using ajax (with jQuery) to update parts of a webpage.
The queries return html to insert at various places.
However, these html blocks sometimes contain javascript that write stuff
where they're located. I mean, in some div of the html returned by AJAX, there's a script that gets included, and this script executes some document.write() instructions (typically scripts from our ads publisher we don't have any control over).
Now, if I just take the html returned by my AJAX queries and update the DOM with it, the javascript doesn't get executed.
What's the cleanest/easiest way to make sure that document.write() writes its stuff at the appropriate spots ?
You can't use document.write() with dynamically inserted content. The issue is that the current document has already been opened, parsed and closed upon the initial page load. If you now invoke document.write() from one of these scripts, it will clear the current document and start writing a new document. That will blank your browser window and write just the new content (which is certainly not what you want).
The options I can think of are:
Put the content in an iframe and load it via the .src attribute, not via ajax so the content can load into a new document and document.write() can do its normal, expected thing.
Change those scripts to not use document.write(). If you control that code, then the scripts need to be changed to insert content into a specific DOM element, not to try to write into the document stream because the document stream will not work the way you want once the original document has been parsed and the document closed.
Hack document.write() (by temporarily replacing it with a different method) so it captures the document.write() content in a different way while your dynamic content is being loaded and then you dynamically insert it into some existing DOM element rather than use the actual document.write(). This is truly a hack and it cannot be guaranteed that this will work in all browsers.
As you've no doubt discovered, document.write totally destroys the current document.
There are a few ways to handle it, the easiest one I've found is to replace document.write with a function that uses regular DOM manipulations.
document.write = function(str) {
var oldtxt = $("#destdiv").html();
oldtxt += str;
$("#destdiv").html(oldtxt);
}

Javascript onload after redirect

in my Javascript code I am loading a page, and then would like to perform some functions. I tried to use solutions like window.onload, but that is after my html (blank page with just the JS) loads, I need the function to perform after the page I am reffering to is loaded.
I am using this code:
this.document.location.href = myurl;
And after this loads, I would like to call some function. Is there a way to do so?
Thanks
EDIT:
I can not edit the target page source code.
When you change the value of document.location.href, you are essentially doing a redirect.
You can either just do whatever you want to do within the loaded page itself or if you don't have cross domain issues, do xhr of the page you're wanting to load dynamically, query the body, replace content of your current body and also replace head contents i.e. style, title and scripts etc. You could then execute any script you want.
Extra note: This is quite a tricky thing to do, I've done this a few times before - and its proven quite problematic due to the fact that you don't actually get a fully parsed document object that you can just query so simply, you only receive a huge string. One hack that I've thought of using is actually just loading everything within an iframe allowing easy querying which is actually documented - extra reading here
window.load takes forever to fire because it waits for all images and assets to load on the page.
It sounds like the best solution for you would be to poll for the document to be finished loading. Here's a simple example:
(function poll(){
if(document.readyState === "complete"
{
// Your code here
}
else
setTimeout(poll,500);
})();
Place the 'window.onload = myFunction(){...}' inside the page, which will be loaded.
this.document.location.href
will open the page like you typed it into the browser address bar and your onload-script in the old page will not be executed in the new one.
By the way, you can shortcut it to document.location = myUrl
See the Document-API at Mozilla

Why can't document.write be used to load a module using Dom-scripting?

In this question, I got the following answer:
Looking at Google's maps script it's failing to load the Geocoder module because it's using document.write to do so, a method that has to be run from a included in the HTML document at parse time, not imported by use of DOM scripting as you're doing here.
Which is a method that has to be run from a included in the html at pare time? How do I do this?
What is being imported by the use of DOM-scripting? How do I recognize DOM-scripting?
I'm pretty new to javascript and I don't really understand the reference here.
isDom scripting is when you work on an already loaded document, and manipulate the "DOM elements" (DOM = "document object model"....javascript representations of the components of a web page). You can add and remove elements, and manipulate their properties such as styles and content.
As opposed to altering the html text itself, prior to it being turned into elements, with document.write. document.write only works at the very beginning, when the page is being converted from text to web page components. It's the "old way", since in the old days of javascript it was the only way to do things. There are cases where it is still useful, but it general it is avoided these days.
Example of dom scripting:
var elem = document.getElementById("someelement");
var childElem = document.createElement ("DIV");
childElem.innerHTML = "this is a <i><b>test</b></i>";
elem.appendChild (childElem);
Note that use of "innerHTML" is a common shortcut that is somewhat in the middle ground. It's used post-page load, but it works by supplying textual html code. Depending on context, it may or may not be considered "dom scripting".
document.write is an old method that inserts HTML into the page while it is loading, at the place where the script is located. For this reason, it is commonly used in JavaScript "widgets" that can be copy-and-pasted into a web page. However, if the page has finished loading, all it does is start the creation of a new page with that HTML in it.
<div id="foo">
<script type="text/javascript">
document.write("<h1>Main title</h1>")
</script>
</div>
This is in contrast to the functions that jQuery provides or the underlying DOM methods that it uses, which have to be called after the page has loaded:
// The jQuery way
$(document).ready(function() {
$('#foo').append('<h1>Main title</h1>');
});
// The plain JS way
window.onload = function() {
var h1 = document.createElement('h1');
h1.appendChild(document.createTextNode('Main title'));
document.getElementById('foo').appendChild(h1);
};
If there is simply no way to change the widget (e.g. it is served by a third-party), and you have to, for example, load the widgets from jQuery, you could override the document.write and document.writeln functions to do what you want them to just before loading it.
Keep in mind that for this to work correctly when there are multiple widgets on a page, you would have to ensure that the first gadget has completely loaded before you even try to load the second.

Javascript document.write weird behaviour in Firefox

When I write the following code directly into my html page under a script tag, the string "test" gets appended to my page without replacing the rest of its content (1):
document.write("test");
However, if I place that same code into a separate javascript file like (2):
<script src="http://127.0.0.1/whatever.js" type="text/javascript"></script>
Suddenly that same code rewrites my entire page.
Is there a way to perform a document.write() from a remote file and get the result in (1)?
Thanks for your time.
If you use doc.write while the page page is rendering, it will insert or append the string. If you use doc.write after it's rendered, or after window.onload, it will essentially begin the rendering process again, and overwrite the page.
It's my guess that you are getting asynchronous behavior when loading the script, and it's not executing until after onload. I can't recreate your problem.
You may be including your script at the top of the page. Where it gets the document.write() stuff and thus writes the text instead of a append behaviour.
The safer solution is to append a document element to the page - that should always work

Categories

Resources