This question already has answers here:
Why does jQuery or a DOM method such as getElementById not find the element?
(6 answers)
Closed 7 years ago.
I have tried several methods of writing to this div, but to know avail:
The 'testing' works, but nothing else:
document.write("testing");
document.getElementById('menu2').innerHTML += "<br>Some new content!";
var node = document.getElementById("menu2");
node.innerHTML = "<p>" + "Hello" + "</p>";
(function printMsg() {
var node = document.getElementById("menu2");
node.innerHTML = "<p>" + "Hello World!" + "</p>";
})();
and in the html
<div id="menu2">x</div>
the x shows
As of this writing, this is at http://www.jchess.nyc (index page)
You problem is that you put script in the begining of the body, so it's executed before div#menu2 is avaialable in DOM.
The simplest fix is to move script tag before closing </body> tag. Also remove document.write, it's not a problem here but you don't need it.
<script>
document.getElementById('menu2').innerHTML += "<br>Some new content!";
var node = document.getElementById("menu2");
node.innerHTML = "<p>" + "Hello" + "</p>";
(function printMsg() {
var node = document.getElementById("menu2");
node.innerHTML = "<p>" + "Hello World!" + "</p>";
})();
</script>
</body>
That happens because document.write just writes the text you specify in body; it's not required for any element to be loaded to be able to document.write, but document.getElementById() searches for the element in DOM, which isn't created immediately when you begin executing your script, so your script is trying to access your element with id menu2 before it is loaded.
To be able to use document.getElementById(), you should wait for the DOM to load, by placing all your methods accessing DOM to:
window.onload=function(){
}
Related
How do I get it to not replace the text on textbox inputs? It doesn't do it while typing, but if you go to edit a document or input field that contains the replaced information it will and makes it impossible to edit.
I've tried to do it but it just turns the entire script off. xD
<script type='text/javascript'>
document.body.innerHTML = document.body.innerHTML.replace(/E0/g, '<img src="http://s31.postimg.org/5riz5vn0b/Zero.png" title="E"/>');
document.body.innerHTML = document.body.innerHTML.replace(/E10/g, '<img src="http://s31.postimg.org/6wm82qo8r/ten.png" title="E"/>');
document.body.innerHTML = document.body.innerHTML.replace(/E20/g, '<img src="http://s31.postimg.org/4j4abq9tn/twenty.png"title="E"/>');
document.body.innerHTML = document.body.innerHTML.replace(/E30/g, '<img src="http://s31.postimg.org/mzyp2jprv/thirty.png"title="E"/>');
document.body.innerHTML = document.body.innerHTML.replace(/E40/g, '<img src="http://s31.postimg.org/j4vazz6m3/forty.png"title="E"/>');
</script>
Here is an image of the problem I see on the web page:
You can use document.querySelectorAll() with selector string "body *" to select all elements except <body>; for loop; exclude <input> elements from single .replace() call by filtering INPUT .tagName property at if condition
<div>E0 E10 E20 E30 E40</div>
<input type="text" value="E40" />
<script type='text/javascript'>
var elems = document.querySelectorAll("body *");
var url = "http://s31.postimg.org/";
for (var i = 0; i < elems.length; i++) {
if (elems[i].tagName !== "INPUT") {
elems[i].innerHTML = elems[i].innerHTML
.replace(/(E0)|(E10)|(E20)|(E30)|(E40)/g
, function(match, p1, p2, p3, p4, p5) {
if (p1) return "<img src=" + url
+ "5riz5vn0b/Zero.png title=E/>";
if (p2) return "<img src=" + url
+ "6wm82qo8r/ten.png title=E/>";
if (p3) return "<img src=" + url
+ "4j4abq9tn/twenty.png title=E/>";
if (p4) return "<img src=" + url
+ "mzyp2jprv/thirty.png title=E/>";
if (p5) return "<img src=" + url
+ "j4vazz6m3/forty.png title=E/>";
})
}
}
</script>
An alternative method might be to search the document for text nodes which contain E0, E10, E20, E30, E40, skipping those which are child nodes of TEXTAREA and INPUT elements, and replace each text node that remains with an element containing text and images.
This should avoid a potential problem of replacing innerHTML of container elements which have elements inside them that need to be left unchanged. While the following code runs in IE and Firefox it has not been tested it in the full context of your application.
function textToImages() // within document.body
{
var checkAny = /E0|E10|E20|E30|E40/g;
function filter( node)
{ checkAny.lastIndex=0;
if(checkAny.test(node.nodeValue))
{ switch(node.parentNode.tagName)
{ case "INPUT":
case "TEXTAREA":
return NodeFilter.FILTER_SKIP;
}
return NodeFilter.FILTER_ACCEPT;
}
return NodeFilter.FILTER_SKIP;
}
filter.acceptNode = filter; // cross browser compatability
var scan = document.createNodeIterator(
document.body,
NodeFilter.SHOW_TEXT,
filter,
false
);
var node, replaceList=[];
document.body.normalize();
while(node = scan.nextNode())
replaceList.push(node);
if( replaceList.length)
replaceList.forEach( replaceTextNode);
function replaceTextNode( node)
{ var html = node.nodeValue;
var span = document.createElement("span");
html=html.replace(/E0/g, '<img src="http://s31.postimg.org/5riz5vn0b/Zero.png" title="E"/>');
html=html.replace(/E10/g, '<img src="http://s31.postimg.org/6wm82qo8r/ten.png" title="E"/>');
html=html.replace(/E20/g, '<img src="http://s31.postimg.org/4j4abq9tn/twenty.png" title="E"/>');
html=html.replace(/E30/g, '<img src="http://s31.postimg.org/mzyp2jprv/thirty.png" title="E"/>');
html=html.replace(/E40/g, '<img src="http://s31.postimg.org/j4vazz6m3/forty.png"title="E"/>');
span.innerHTML = html;
node.parentNode.replaceChild(span, node);
}
}
A NodeIterator is used to scan text nodes in the DOM, filtering for those which contain text to be replaced which are not child nodes of TEXTAREA or INPUT elements, and create a static list of nodes to be processed.
I had trouble with document.createNodeIteratorin IE which requires at least 4 parameters and requires its 3rd parameter to be a function. If you encounter problems in other browsers I would suggest writing custom DOM traversal and filtering code to avoid using NodeIterator altogether.
Text nodes which passed through the filter are replaced by a SPAN element containing zero or more text nodes and one or more image elements. The node replacement function basically uses the code posted in the question. While it should be possible to replace a single text node with one or more text and image nodes, without the use of a container, it would require additional coding to create and manipulate DOM elements.
I created the script below. It puts the body in a div, as desired. However, the event handler fails. I'm sure it's a simple error.
body_html = document.body.innerHTML;
new_html = "<div id='realBody'>" + body_html + "</div>";
document.body.innerHTML = new_html;
document.body.getElementById("realBody").addEventListener("mouseover", function(event) {alert('body');});
How to make the event work? (Feel free to rewrite the whole thing if there's a better (simpler) way.
Edit: This works, some comments say it's the wrong way to put the body into a div, but i see no problems:
body_html = document.body.innerHTML;
new_html = "<div id='realBody'>" + body_html + "</div>";
document.body.innerHTML = new_html;
document.getElementById("realBody").addEventListener("mouseenter", function(event) {alert('body');});
thx!
You need to change document.body.getElementById() to document.getElementById()
document.getElementById("realBody").addEventListener("mouseover", function(event) {alert('body');});
You should attach event listener like,
body_html = document.body.innerHTML;
new_html = "<div id='realBody'>" + body_html + "I am border</div>";
document.body.innerHTML = new_html;
document.getElementById("realBody").addEventListener("mouseover", function (event) {
alert('body');
});
DEMO
The error you're receiving is probably because of this line:
document.body.getElementById("realBody").addEventListener("mouseover", function (event) { alert('body'); });
you need to modify it to this:
document.getElementById("realBody").addEventListener("mouseover", function (event) { alert('body'); });
document.body.getElementById() just needs to be document.getElementByid()
A more proper way to add elements to the DOM would be to do something like below:
var divEl = document.createElement("div");
divEl.id = "realBody";
var textNode = document.createTextNode("Hover over me");
divEl.appendChild(textNode);
document.body.appendChild(divEl);
divEl.onmouseover = function (event) {
alert('body');
}
As everybody explained, you need to call the getElementById() on the document object, not in an element.
But your code will loose any event handlers attached to the elements prior to your code execution as you are clearing the html and creating a new dom structure you overwritting the innerHTML.
Instead just move the existing dom to the new element like
var wrapper = document.createElement('div');
wrapper.id = 'realBody';
while (document.body.firstChild) {
wrapper.appendChild(document.body.firstChild);
}
document.body.appendChild(wrapper);
wrapper.addEventListener("mouseover", function (event) {
console.log('body');
});
Demo: Fiddle
People on here are recommending that I use jQuery, but when I changed the code to jQuery and used .html() it is like it did nothing. I even removed half of the html code that needed to be added as someone suggested I was asking way to much of innerHTML and HTML.
In Simple task, all I want is for when a user click on the DIV that it runs the onClick event.
html += "<div onClick='loadnewsstory();' class='news'> this is a test story, for this test story we are not getting data from JSON</div>";
I have tried both
$("#activecontent").html(html);
document.getElementById("activecontent").innerHTML
The problem I have is relating to the following code.
function newsstories()
{
document.getElementById("activecontent").innerHTML = "<h1 class='newsheader'>Latest News</h1>";
xmlhttp=new XMLHttpRequest();
xmlhttp.open("POST","http://test.com/?uri=loadnews",false);
xmlhttp.send();
var newsreponse = JSON.parse(xmlhttp.responseText);
for (var i = 0, len = newsreponse.length; i < len; ++i) {
var news = newsreponse[i];
if(i % 2 == 0){
cssclass = "even";
}
else
{
cssclass = "odd";
}
// alert(news.featured_image);
document.getElementById("activecontent").innerHTML = document.getElementById("activecontent").innerHTML + "<div class='news " + cssclass + "'><div class='newstitle'><div class='newstitlecolor' id='news_"+ countstory+"'><a href='javascript:loadnewsstory();'>" + news.post_title + "</a></div></div><div class='base' style='background: url('" + news.featured_image + "');'><img src='" + news.featured_image + "' style='width:100%; height:100%;'/></div></div>";
}
}
you will see in this area i have a link
<a href='javascript:loadnewsstory();'>" + news.post_title + "</a>
it suppose to fire
function loadnewsstory()
{
navigator.notification.alert(device.uuid);
}
but I am not getting that fire.
Yes this is a web app for iOS and Cordova but I believe this is a javascript issue.
Don't use +=, as it is used in an improper instance and returns an "unexpected token" error because var html was not previously equal to anything. I removed it and it appeared to fix the problem. Fiddle
If you must use += set var html = $("#activecontent").html(), then you may afterwards use += when you re-define the variable (Fiddle 2)
If your structure looks like
html
<div id="activecontent">
<div class='news'>Story 1</div>
<div class='news'>Story 2</div>
</div>
and you want each div.news to by dynamic and clickable, you could do that like this with jQuery
javascript
$(function(){
$("#activecontent").on('click', '.news', function(){
//You clicked the div
console.log( 'Clicked', $(this) );
});
});
And if you want to append divs to your #activecontent with an ajax request. Let's assume your JSON looks like
json
[
{ "id": 1, "content": "My first story" },
{ "id": 2, "content": "Another one" },
{ "id": 3, "content": "Last story" }
]
Your javascript to load that could look like
javascript
$.getJSON( "http://url_of_json.json", function(result){
for(var i in result){
$("#activecontent").append( $("<div>").addClass('news').html(result[i].content) );
}
});
alternative javascript for the ajax which is faster on the DOM
$.getJSON( "http://url_of_json.json", function(result){
var newHtml = "";
for(var i in result){
newHtml += "<div class='news'>" + result[i].content + "</div>";
}
$("#activecontent").append( newHtml );
// Or $("#activecontent").html( newHtml );
// if you want to replace what the page loaded with
});
Now to explain. The first piece of javascript with the .on, what were doing there is binding an event listener to your parent div, #activecontent. We do that because it will always exist in your page. You will be adding and maybe removing divs from that container based on your AJAX call, so instead of having to bind a click (or inline some javascript for every div), you can bind once to the parent, and then delegate that click to '.news'. You can alternatively bind the click to each new div, but delegating is cleaner.
As for the part about loading the JSON and writing it. If you are going to add some stuff to a node's innerHTML, the jQuery way is to use .append(). It's just a shortcut to something like
//vanilla js way
var e = document.getElementById('myThing');
e.innerHTML = e.innerHTML + "Thing I want to append";
// vs jQuery way
$("#myThing").append("Thing I want to append");
//To continue this example, to replace your myThing's html
//vanilla
e.innerHTML = "my new html";
//jQuery
$("#myThing").html("my new html");
Hopefully this clears things up for you. If you are just jumping into jQuery, know that it's not always that it's faster to write than the vanilla javascript, but rather that when you do something like ..html('new stuff');, it's going to use a method that works best with all browsers. So if there's some rogue version of IE out there than wants to use .innerHTMLmsIsNeat instead of .innerHTML, jQuery will sort that for you.
<script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script>
var newvalue = '<img class="youtube_replace youtube_canvas" data-code="Wn-_MyJV37E" src="http://img.youtube.com/vi/Wn-_MyJV37E/0.jpg" />';
var abc = $('<div>' + newvalue + '</div>').find('*').each(function() {
}).html();
alert(abc);
</script>
I want abc to equal "newvalue". But in my current code, abc is empty. Why?
This is what I truly want to do, but for example purposes, I left this blank above:
var whitelist = ['a','div','img', 'span'];
var abc = $('<div>' + newvalue + '</div>').find('*').each(function() {
if($.inArray(this.nodeName.toLowerCase(), whitelist)==-1) {
$(this).remove();
}
}).html(); //abc is now sanitized!!!
Breaking it down:
var abc = $('<div>' + newvalue + '</div>') //Creates a div with an img element inside it
.find('*') //retrieves the img element
.each(function() {}) //iterates over the jQuery set (only one img element)
.html(); //returns the HTML serialization of the img element
//which has no contents, so it is an empty string
You could call .parent().html(), which would retrieve the contents of the div you created.
In your second example, you would want .end().html() which would pop the internal jQuery stack and get you back to the top-most div.
The issue here is that when you do:
var abc = $('<div>' + newvalue + '</div>').find('*')
your jQuery object holds the img element, not the div element. So when you're calling .html(), you're getting the inner HTML of the image - which of course doesn't exist.
var abc = $('<div>' + newvalue + '</div>')
.find('*')
.each(function() {
// stuff
})
.parent().html();
(but #Dennis got there first :). )
Do it like that (if you insist on getting HTML of element you just generated):
var abc = $('<div>' + newvalue + '</div>').html();
The problem is just incorrect mixing of different jQuery functions and callbacks.
EDIT:
The problem you have is that with find('*') you retrieve all the <img> tags (actually: one <img> tag) within <div>, but <img> tags have no HTML inside them (they have no other tags inside).
If you shorten your code to this:
var abc = $('<div>' + newvalue + '</div>').find('*').each(function() {
/* your JS code here */
}).parent().html();
you will actually receive HTML of the whole <img> tag.
Of course, there are a whole range of possible errors relating to document validity, but my immediate stumbling block occurs when changing a paragraph (p) into an address element. My current method is (more-or-less):
var p = $('p#test');
p.replaceWith('<address>' + p.html() + '</address>');
but that fails for this specific case; it works perfectly for p -> blockquote or h2 -> h3. Firebug suggests that a self-closing element (<address/>) has been added to the document, for some reason.
Can anyone spot the bug or suggest an alternative method?
var p = $('p#test');
var a = $('<address>').
append(p.contents());
p.replaceWith(a);
Your solution is subject to all sorts of horrible HTML escaping issues and possibly injection attacks.
You'll could use a placeholder around the title:
<span id="demo"><h1>Title</h1></span>
Then use JavaScript DOM to create new values for the innerHTML property.
<script type="javascript">
setTitle = function(id, tag, title) {
var container = document.getElementById(id);
container.innerHTML = '<' + tag + '>' + title + '</' + tag + '>';
}
setTitle('demo', 'h1', 'My Title');
</script>