Only one node inside div - HTML, JavaScript - javascript

I have looked something different from .appendChild() and .innerHTML but to work with Image() JavaScript objects.
I have 10 variables, img[1,2,3,4...10], created with JavaScript (new Image()) to pre-load and it's OK, now I want to insert it into my div only one at time.
innerHTML returns something like HTMLImageObject and appendChild() won't work like I want.
My solution so far is:
document.getElementById("teste").removeChild(document.getElementById("teste").firstChild);
document.getElementById("teste").appendChild(img1);
Someone have any better ideas?

If you don't want appendChild use replaceChild. For example:
div.replaceChild(imgs[i], div.firstChild);
Demo: http://jsfiddle.net/8bKy8/

your way is pretty solid but maybe like this is easier to read.. also lastChild has a marginal performance advantage
var ele = document.getElementById('teste');
while(ele.lastChild) {
ele.removeChild(ele.lastChild)
}
ele.appendChild(img1);
http://jsperf.com/innerhtml-vs-removechild/15
you could also keep a reference to the element somewhere
var ele = document.getElementById('teste'), img = ele.lastChild;
ele.removeChild(img);
ele.append(img1);
if you have jQuery available you can use
$('#teste').clear().append(img1);
depending on the browser you are using you potentially also have access to the HTML5 Selector API as well even without jquery that may be an alternative to the document.element method
document.querySelector('#tests').first();
https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Locating_DOM_elements_using_selectors

Related

What's wrong with document.write? What's a viable alternative? [duplicate]

In tutorials I've learnt to use document.write. Now I understand that by many this is frowned upon. I've tried print(), but then it literally sends it to the printer.
So what are alternatives I should use, and why shouldn't I use document.write? Both w3schools and MDN use document.write.
The reason that your HTML is replaced is because of an evil JavaScript function: document.write().
It is most definitely "bad form." It only works with webpages if you use it on the page load; and if you use it during runtime, it will replace your entire document with the input. And if you're applying it as strict XHTML structure it's not even valid code.
the problem:
document.write writes to the document stream. Calling document.write on a closed (or loaded) document automatically calls document.open which will clear the document.
-- quote from the MDN
document.write() has two henchmen, document.open(), and document.close(). When the HTML document is loading, the document is "open". When the document has finished loading, the document has "closed". Using document.write() at this point will erase your entire (closed) HTML document and replace it with a new (open) document. This means your webpage has erased itself and started writing a new page - from scratch.
I believe document.write() causes the browser to have a performance decrease as well (correct me if I am wrong).
an example:
This example writes output to the HTML document after the page has loaded. Watch document.write()'s evil powers clear the entire document when you press the "exterminate" button:
I am an ordinary HTML page. I am innocent, and purely for informational purposes. Please do not <input type="button" onclick="document.write('This HTML page has been succesfully exterminated.')" value="exterminate"/>
me!
the alternatives:
.innerHTML This is a wonderful alternative, but this attribute has to be attached to the element where you want to put the text.
Example: document.getElementById('output1').innerHTML = 'Some text!';
.createTextNode() is the alternative recommended by the W3C.
Example: var para = document.createElement('p');
para.appendChild(document.createTextNode('Hello, '));
NOTE: This is known to have some performance decreases (slower than .innerHTML). I recommend using .innerHTML instead.
the example with the .innerHTML alternative:
I am an ordinary HTML page.
I am innocent, and purely for informational purposes.
Please do not
<input type="button" onclick="document.getElementById('output1').innerHTML = 'There was an error exterminating this page. Please replace <code>.innerHTML</code> with <code>document.write()</code> to complete extermination.';" value="exterminate"/>
me!
<p id="output1"></p>
Here is code that should replace document.write in-place:
document.write=function(s){
var scripts = document.getElementsByTagName('script');
var lastScript = scripts[scripts.length-1];
lastScript.insertAdjacentHTML("beforebegin", s);
}
You can combine insertAdjacentHTML method and document.currentScript property.
The insertAdjacentHTML() method of the Element interface parses the specified text as HTML or XML and inserts the resulting nodes into the DOM tree at a specified position:
'beforebegin': Before the element itself.
'afterbegin': Just inside the element, before its first child.
'beforeend': Just inside the element, after its last child.
'afterend': After the element itself.
The document.currentScript property returns the <script> element whose script is currently being processed. Best position will be beforebegin — new HTML will be inserted before <script> itself. To match document.write's native behavior, one would position the text afterend, but then the nodes from consecutive calls to the function aren't placed in the same order as you called them (like document.write does), but in reverse. The order in which your HTML appears is probably more important than where they're place relative to the <script> tag, hence the use of beforebegin.
document.currentScript.insertAdjacentHTML(
'beforebegin',
'This is a document.write alternative'
)
As a recommended alternative to document.write you could use DOM manipulation to directly query and add node elements to the DOM.
Just dropping a note here to say that, although using document.write is highly frowned upon due to performance concerns (synchronous DOM injection and evaluation), there is also no actual 1:1 alternative if you are using document.write to inject script tags on demand.
There are a lot of great ways to avoid having to do this (e.g. script loaders like RequireJS that manage your dependency chains) but they are more invasive and so are best used throughout the site/application.
I fail to see the problem with document.write. If you are using it before the onload event fires, as you presumably are, to build elements from structured data for instance, it is the appropriate tool to use. There is no performance advantage to using insertAdjacentHTML or explicitly adding nodes to the DOM after it has been built. I just tested it three different ways with an old script I once used to schedule incoming modem calls for a 24/7 service on a bank of 4 modems.
By the time it is finished this script creates over 3000 DOM nodes, mostly table cells. On a 7 year old PC running Firefox on Vista, this little exercise takes less than 2 seconds using document.write from a local 12kb source file and three 1px GIFs which are re-used about 2000 times. The page just pops into existence fully formed, ready to handle events.
Using insertAdjacentHTML is not a direct substitute as the browser closes tags which the script requires remain open, and takes twice as long to ultimately create a mangled page. Writing all the pieces to a string and then passing it to insertAdjacentHTML takes even longer, but at least you get the page as designed. Other options (like manually re-building the DOM one node at a time) are so ridiculous that I'm not even going there.
Sometimes document.write is the thing to use. The fact that it is one of the oldest methods in JavaScript is not a point against it, but a point in its favor - it is highly optimized code which does exactly what it was intended to do and has been doing since its inception.
It's nice to know that there are alternative post-load methods available, but it must be understood that these are intended for a different purpose entirely; namely modifying the DOM after it has been created and memory allocated to it. It is inherently more resource-intensive to use these methods if your script is intended to write the HTML from which the browser creates the DOM in the first place.
Just write it and let the browser and interpreter do the work. That's what they are there for.
PS: I just tested using an onload param in the body tag and even at this point the document is still open and document.write() functions as intended. Also, there is no perceivable performance difference between the various methods in the latest version of Firefox. Of course there is a ton of caching probably going on somewhere in the hardware/software stack, but that's the point really - let the machine do the work. It may make a difference on a cheap smartphone though. Cheers!
The question depends on what you are actually trying to do.
Usually, instead of doing document.write you can use someElement.innerHTML or better, document.createElement with an someElement.appendChild.
You can also consider using a library like jQuery and using the modification functions in there: http://api.jquery.com/category/manipulation/
This is probably the most correct, direct replacement: insertAdjacentHTML.
Try to use getElementById() or getElementsByName() to access a specific element and then to use innerHTML property:
<html>
<body>
<div id="myDiv1"></div>
<div id="myDiv2"></div>
</body>
<script type="text/javascript">
var myDiv1 = document.getElementById("myDiv1");
var myDiv2 = document.getElementById("myDiv2");
myDiv1.innerHTML = "<b>Content of 1st DIV</b>";
myDiv2.innerHTML = "<i>Content of second DIV element</i>";
</script>
</html>
Use
var documentwrite =(value, method="", display="")=>{
switch(display) {
case "block":
var x = document.createElement("p");
break;
case "inline":
var x = document.createElement("span");
break;
default:
var x = document.createElement("p");
}
var t = document.createTextNode(value);
x.appendChild(t);
if(method==""){
document.body.appendChild(x);
}
else{
document.querySelector(method).appendChild(x);
}
}
and call the function based on your requirement as below
documentwrite("My sample text"); //print value inside body
documentwrite("My sample text inside id", "#demoid", "block"); // print value inside id and display block
documentwrite("My sample text inside class", ".democlass","inline"); // print value inside class and and display inline
I'm not sure if this will work exactly, but I thought of
var docwrite = function(doc) {
document.write(doc);
};
This solved the problem with the error messages for me.

Are HTML allowed inside HTML attributes?

For example, lets say you have something like this:
<div data-object="{'str': '<h1>This is a nice headline</h1>'}"></div>
Is this allowed in HTML5 and will it render properly in all browsers?
Edit:
With properly I mean that the browser will ignore and NOT render the H1 in any way ;)
Yes, it's allowed as long as it's quoted correctly.
Will it render? The H1 element? No - because it's not an element, it's just a bit of text inside an attribute of the div element.
Yes, browsers won't render any HTML tags inside attributes. This is pretty much common when you want to move the element later so it would show up. The only problem is that this is not a way to go as this does not create an element in DOM, thus, it will be much slower.
Try to find a way or ask for an alternative/better way to reuse the element which is hidden when the page is loaded.
Yes it's allowed and possible, but to make it work you have to make it valid JSON by using double quotes:
<div data-object='{"str": "<h1>This is a nice headline</h1>"}'></div>
Now to parse it just have: (jQuery will parse it to JSON all by itself)
var element = $("div").eq(0);
var rawData = element.data("object");
var rawHTML = rawData["str"];
$(rawHTML).appendTo("body");
Live test case.

jQuery append() not working on certain element

The website I'm creating is http://www.industrialmerchants.com
The problem portion of my script is the following:
var collapseAll = document.createElement('img');
collapseAll.src = collapseAllSrc;
collapseAll.className = "collapseAll";
collapseAll.style.cssFloat = "right";
imUI(".menuBrowser .sideModuleHeader").append(collapseAll);
(imUI is the noConflict variable I'm using. If you are wondering why I use this verbose method of creating a DOM element, it is because this was my last ditch effort to get this code to work.)
For some bizarre reason, nothing is appended to the selected div. The div is definitely being selected because the length property is returning 1. To make things even more confusing, I have another "module" with a nearly identical DOM structure. When I alter the selector to include the .sideModuleHeader div from both modules, the image is inserted in the second module but not the first. Any ideas?
It does get added, but a few lines later you have:
toggleButtons = imUI(".menuBrowser img").remove(".collapseAll")...
which then immediately deletes it.
Looks like you are mixing core javascript with jquery.
try:
var collapseAll = $('<img />').attr('src',collapseAllSrc).addClass("collapseAll");
collapseAll.css({'float':'right'})
-edit: i had a ':' instead of a ',' on the attr part.
Try with append Child:
imUI(".menuBrowser .sideModuleHeader").appendChild(collapseAll);

Append html to jQuery element without running scripts inside the html

I have written some code that takes a string of html and cleans away any ugly HTML from it using jQuery (see an early prototype in this SO question). It works pretty well, but I stumbled on an issue:
When using .append() to wrap the html in a div, all script elements in the code are evaluated and run (see this SO answer for an explanation why this happens). I don't want this, I really just want them to be removed, but I can handle that later myself as long as they are not run.
I am using this code:
var wrapper = $('<div/>').append($(html));
I tried to do it this way instead:
var wrapper = $('<div>' + html + '</div>');
But that just brings forth the "Access denied" error in IE that the append() function fixes (see the answer I referenced above).
I think I might be able to rewrite my code to not require a wrapper around the html, but I am not sure, and I'd like to know if it is possible to append html without running scripts in it, anyway.
My questions:
How do I wrap a piece of unknown html
without running scripts inside it,
preferably removing them altogether?
Should I throw jQuery out the window
and do this with plain JavaScript and
DOM manipulation instead? Would that help?
What I am not trying to do:
I am not trying to put some kind of security layer on the client side. I am very much aware that it would be pointless.
Update: James' suggestion
James suggested that I should filter out the script elements, but look at these two examples (the original first and the James' suggestion):
jQuery("<p/>").append("<br/>hello<script type='text/javascript'>console.log('gnu!'); </script>there")
keeps the text nodes but writes gnu!
jQuery("<p/>").append(jQuery("<br/>hello<script type='text/javascript'>console.log('gnu!'); </script>there").not('script'))`
Doesn't write gnu!, but also loses the text nodes.
Update 2:
James has updated his answer and I have accepted it. See my latest comment to his answer, though.
How about removing the scripts first?
var wrapper = $('<div/>').append($(html).not('script'));
Create the div container
Use plain JS to put html into div
Remove all script elements in the div
Assuming script elements in the html are not nested in other elements:
var wrapper = document.createElement('div');
wrapper.innerHTML = html;
$(wrapper).children().remove('script');
var wrapper = document.createElement('div');
wrapper.innerHTML = html;
$(wrapper).find('script').remove();
This works for the case where html is just text and where html has text outside any elements.
You should remove the script elements:
var wrapper = $('<div/>').append($(html).remove("script"));
Second attempt:
node-validator can be used in the browser:
https://github.com/chriso/node-validator
var str = sanitize(large_input_str).xss();
Alternatively, PHPJS has a strip_tags function (regex/evil based):
http://phpjs.org/functions/strip_tags:535
The scripts in the html kept executing for me with all the simple methods mentioned here, then I remembered jquery has a tool for this (since 1.8), jQuery.parseHTML. There's still a catch, according to the documentation events inside attributes(i.e. <img onerror>) will still run.
This is what I'm using:
var $dom = $($.parseHTML(d));
$dom will be a jquery object with the elements found

JQuery $(document).ready() and document.write()

Firstly, is there a way to use document.write() inside of JQuery's $(document).ready() method? If there is, please clue me in because that will resolve my issue.
Otherwise, I have someone's code that I'm supposed to make work with mine. The catch is that I am not allowed to alter his code in any way. The part that doesn't work looks something like this:
document.write('<script src=\"http://myurl.com/page.aspx?id=1\"></script>');
The script tag is referencing an aspx page that does a series of tests and then spits out something like so:
document.write('<img src=\"/image/1.jpg\" alt=\"Second image for id 1\">')
The scripts are just examples of what is actually going on. The problem here is that I've got a document.write() in the initial script and a document.write() in the script that get's appended to the first script and I've got to somehow make this work within JQuery's $(document).ready() function, without changing his code.
I have no idea what to do. Help?
With the requirements given, no, you can't use document.write without really hosing up the document. If you're really bent on not changing the code, you can override the functionality of document.write() like so and tack on the result later:
var phbRequirement = "";
$(function() {
document.write = function(evil) {
phbRequirement += evil;
}
document.write("Haha, you can't change my code!");
$('body').append(phbRequirement);
});
Make sure you overwrite the document.write function before it is used. You can do it at anytime.
The other answers are boring, this is fun, but very pretty much doing it the wrong way for the sake of fulfilling the requirements given.
picardo has the approach I would've used. To expand on the concept, take a read:
$('<script/>')
.attr('src', 'http://myurl.com/page.aspx?id=1')
.appendTo('body');
Alternate style:
var imgnode = $('<img alt="Second image for id 1"/>')
.attr('src', "image1.jpg");
$('#id1').append(imgnode);
Be sure to use the attr method to set any dynamic attributes. No need to escape special symbols that way.
Also, I'm not sure what the effectiveness of dynamically generating script tags; I never tried it. Though, it's expected that they contain or reference client-side script. My assumption is that what page.aspx will return. Your question is a little vague about what you're trying to do there.
jQuery has a ready substitute for document.write. All you need to use is the append method.
jQuery('<img src=""/>').appendTo('body');
This is fairly self-evident. But briefly, you can replace the with whatever html you want. And the tag name in the appendTo method is the name of the tag you want to append your html to. That's it.
picardo's answer works, but this is more intuitive for me:
$("body").append('<img src=\"/image/1.jpg\" alt=\"Second image for id 1\">');
Also, for the script part that is being inserted with document.write(), check out jQuery's getScript() function

Categories

Resources