native javascript equivalent to jquery.append when iframes are present - javascript

I am trying to use native javascript to append a string of html to a target div. This works fine using:
var selector = document.getElementById('divid');
var str = '<div><h1>string of html content</h1></div>';
selector.innterHTML += str;
Except whenever the document contains an iframe it seems to hide the frame when appending the innerhtml. I tried a work around as follows:
var selector = document.getElementById('divid');
var str = '<div><h1>string of html content</h1></div>';
var div = document.createElement('div');
div.innerHTML = str;
selector.appendChild(div);
This works but now I am creating an unnecessary div container, is there a way to do this without creating a new element that won't erase the iframe?

Except whenever the document contains an iframe it seems to hide the frame when appending the innerhtml
See "innerHTML += ..." vs "appendChild(txtNode)" for the reason - modifying innerHTML creates a new iframe that reloads. Also have a look at What is better, appending new elements via DOM functions, or appending strings with HTML tags?
This works but now I am creating an unnecessary div container
Just don't create an extra div, you have one in your HTML anyway:
var selector = document.getElementById('divid');
var div = selector.appendChild(document.createElement('div'));
div.innerHTML = '<h1>string of html content</h1>';
is there a way to do this without creating a new element that won't erase the iframe?
You can also use the native insertAdjacentHTML method which is the equivalent to jQuery's append with a HTML string:
var selector = document.getElementById('divid');
selector.insertAdjacentHTML('beforeend', '<div><h1>string of html content</h1></div>');

This seems to work.
var parser = new DOMParser();
var el = parser.parseFromString(str, "text/html");
selector.appendChild(el.childNodes[0]);

Related

Create html elements inside tooltip for a chrome extension

I want to create an HTML element (a div) using javascript to use that as a tooltip.
I can create the simple element by doing:
const element = document.createElement("div");
element.id = "myID"
and that works fine...however, I want to add a table (and some other HTML) inside the tooltip, so I was trying to do
element.appendChild(childElement); //where the childElement is another document.createElement("") that contains all the HTML I want.
or:
element.insertAdjacentHTML('afterbegin', '<table></table>');
however, nothing happens. there's no error, but it won't append it either. Am I missing something?
If it matters, this is happening inside the contentScripts.js of a chrome extension I'm building.
EDIT
Full code of div creation:
const element = document.createElement("div");
element.id = "tooltip-creation";
element.classList.add("tooltip");
const childElement = document.createElement("div");
childElement.id = "data";
//I've attempted to do .appendChild, innerHTML, and .insertAdjacentHTML (as can be seen here) and neither works but no error is given.
element.appendChild(childElement);
element.insertAdjacentHTML('afterbegin','<table border="1"><tr><td><strong>OMG</strong></td></tr></table>');
element.innerHTML = "<table border="1"><tr><td><strong>OMG</strong></td></tr></table>";
Separately I have 2 functions that do:
document.addEventListener("mouseover", function(e){
if (e.target.classList.contains("tooltip")) {
createTooltip(e);
}
});
document.addEventListener("mouseout", function(e){
if (e.target.classList.contains("tooltip")) {
removeAllTooltips();
}
});
I think your issue is that you're not actually appending the tooltip to anything. You need to append your element to a node that is already in the DOM. Here is a working example (without any CSS) that I got from your code, the only difference being that I appended the element node to an existing element in the DOM called root.
https://jsfiddle.net/irantwomiles/09o7vuj5/12/

CSS Style Doesn't Work After createElement

I created a word counting function and found a discrepancy. It produced different results counting the text words in html depending on if the element the html is enclosed in is part of the document.body or not. For example:
html = "<div>Line1</div><div>Line2<br></div>";
document.body.insertAdjacentHTML("afterend", '<div id="node1"></div>');
node1 = document.getElementById("node1");
node1.style.whiteSpace = 'pre-wrap';
node1.innerHTML = html;
node2 = document.createElement('div');
node2.style.whiteSpace = 'pre-wrap';
node2.innerHTML = html;
The white-space: pre-wrap style is applied so that the code in the html variable is rendered, in terms of line-breaks, consistently across browsers. In the above:
node1.innerText // is "Line1\nLine2\n" which counts as two words.
node2.innerText // is "Line1Line2" which counts as only one word.
My word count function is:
function countWords(s) {
s = (s+' ').replace(/^\s+/g, ''); // remove leading whitespace only
s = s.replace(/\s/g, ' '); // change all whitespace to spaces
s = s.replace(/[ ]{2,}/gi,' ')+' '; // change 2 or more spaces to 1
return s.split(' ').filter(String).length;
}
If I then did something like this in the Web Console:
node1.after(node2);
node2.innerText // is changed to "Line1\nLine2\n" which counts as two words.
My questions are:
Why is the white-space: pre-wrap style not being applied to node 2.innerText before it is inserted into the document.body?
If node 2 has to be a part of document.body in order to get a white-space: pre-wrap style node 2.innerText value, how do I do that without having to make node 2 visible?
I'm curious. When I crate a node element with createElement, where does that node element reside? It doesn't appear to be viewable in a Web Console Inspector inside or outside of the <html> tag and I can't find it in the document object.
This tipped me off that the discrepancy was something to do with if the node element being in the document.body or not: javascript createElement(), style problem.
Indeed, when the element is attached to the DOM, Element.innerText takes the rendered value into account - you can say, the visible output. For non-attached elements, there is no rendering. The CSS properties exist but are not executed.
If you want consistent results between attached and non-attached elements, use Element.textContent.
For more information, see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/innerText
In follow-up to my question above, I needed to count the words in html text strings like this: <div>Line1</div><div>Line2<br></div> where the word count matched what it would be if that html was rendered in the displayed DOM
To summarize what others have said, when you create an element using createElement it isn’t inserted into the DOM yet and can’t be found when inspecting the DOM. Before the element is inserted into the DOM, the CSS properties exist but are not executed, so there is no rendering. When the element is inserted into the DOM, the CSS properties are executed, and the element is rendered according to the CSS.
Here's the html-string-to-rendered-html-text function I ended up using. This function strips the html tags but retains the "white space" so that the words can then be counted (with consistency across browsers, including IE 11).
var html = "<div>Line1</div><div>Line2<br></div>";
// Display the html string
var htmlts = document.getElementById("htmlts");
htmlts.innerText = html;
// Display a DOM render of the html string
var node1 = document.getElementById("node1");
node1.style.whiteSpace = 'pre-wrap';
node1.innerHTML = html;
// Display the innerText of the above DOM render
var node1ts = document.getElementById("node1ts");
node1ts.innerText = node1.innerText;
// Display the results of the htmlToText function
var node2ts = document.getElementById("node2ts");
node2ts.innerText = htmlToText(html);
// Adapted from https://stackoverflow.com/a/39157530
function htmlToText(html) {
var temp = document.createElement('div');
temp.style.whiteSpace = 'pre-wrap';
temp.style.position = "fixed"; // Overlays the normal flow
temp.style.left = "0"; // Placed flush left
temp.style.top = "0"; // Placed at the top
temp.style.zIndex = "-999"; // Placed under other elements
// opacity = "0" works for the entire temp element, even in IE 11.
temp.style.opacity = "0"; // Everything transparent
temp.innerHTML = html; // Render the html string
document.body.parentNode.appendChild(temp); // Places just before </html>
var out = temp.innerText;
// temp.remove(); // Throws an error in IE 11
// Solution from https://stackoverflow.com/a/27710003
temp.parentNode.removeChild(temp); // Removes the temp element
return out;
}
<html lang="en-US">
<body>
HTML String: <code id="htmlts"></code><br><br>
Visible Render of HTML String (for comparison): <div id="node1"></div><br>
Visible Render Text String: <code id="node1ts"></code><br>
Function Returned Text String: <Code id="node2ts"></code><br>
</body>
</html>
If you prefer to have the temporary element insert inside the body element, change document.body.parentNode.appendChild to document.body.appendChild.
As Noam had suggested, you can also use temp.style.top = "-1000px";.
To answer my curiosity question: before the element is "inserted into the DOM" it appears to be in a Shadow DOM or Shadow Dom-like space.

Document Create Full Element

I'm making a little app, which has to append 3 elements to another element, by using this code:
var MyElem1= document.createElement("div");
ParentElem.appendChild(MyElem1);
This works just fine, but i was wondering if there is a way to create a full element, like this for example:
var MyElem1= document.createElement('<div style="some-styling: here;">Some InnerHtml Here</div>');
ParentElem.appendChild(MyElem1);
I know i can add those properties to the element after i create it, but i'm hopping there's a way to do it inline like that (Something that works cross-browser).
I saw on W3Schools (yes i know i should stop using it) the createElement function requires only the element type (div, span, button, etc...).
You could create a dummy container and create all elements you want inside it by replacing its innerHTML property, and then getting the .firstChild.
Here is a reusable function for it
var elementFactory = (function (){
var dummy = document.createElement('div');
return function(outerHtml){
var node;
dummy.innerHTML = outerHtml;
node = dummy.firstChild;
dummy.removeChild(node);
return node;
}
})();
and use it like this
var MyElem1 = elementFactory('<div style="some-styling: here;">Some InnerHtml Here</div>'),
MyElem2 = elementFactory('<div style="some-other-styling: here;">Some Other InnerHtml Here</div>');
Demo at http://jsfiddle.net/5De3p/1/

DOM create object direct from his HTML code

in my project i have stored in a variable (htmlG) an html code like this:
<img src="http://mygrtew.imm.com/graph?&o=f&c=1&y=q&b=ffffff&n=666666&w=450&h=250&r=1m&u=www.test.com" width="450" height="250"/>
and i would like to insert dinamically in a div that i create with DOM this image directly
var htmlG = response.testg;
var divAgraph = createElement('div', 'divAgraph', 'divAgraphcss');
var oImgG = createElement('img');
oImgG.setAttribute('src',htmlG);
divAgraph.appendChild(oImgG);
but fail, probably because in var htmlG at the beginning there is correct?
How can icreate my img with these parameters?
thanks in advance
Hope this helps:
var htmlG = response.testg;
var divAgraph = document.createElement('div');
divAgraph.innerHTML = htmlG
I assume you are working in an environment that provides DOM. (node.js does not)
You try to set the src attribute of your <img> element
oImgG.setAttribute('src',htmlG);
yet htmlG does not contain the src attribute content but a complete HTML img element as well.
So instead of your current
var htmlG = '<img src="http://mygrtew.imm.com/graph?&o=f&c=1&y=q&b=ffffff&n=666666&w=450&h=250&r=1m&u=www.test.com" width="450" height="250"/>';
oImgG.setAttribute('src', htmlG);
you probably want to
var htmlG = 'http://mygrtew.imm.com/graph?&o=f&c=1&y=q&b=ffffff&n=666666&w=450&h=250&r=1m&u=www.test.com';
oImgG.setAttribute('src', htmlG);
If you want to set the width and height attributes as well, you will have to call setAttribute for those two separately.
If you have to work with the entire HTML code for the element - as the dereferencing of response.testg suggests, you can use innerHTML to set the content of your div - and not call setAttribute at all.
divAgraph.innerHTML = htmlG

How to pass a Javascript function in a dynamically created div

I want to pass a javascript function to a dynamically created div, like I am attempting below. If I replace the script string with an ordinary string this works, but is there a way to pass a JS script in createTextNode?
newDiv = document.createElement("div");
newContent = document.createTextNode("<script type=\"text/javascript\">var pager = new Pager(3); pager.init(); pager.showPageNav('pager', 'pageNavPosition'); pager.showPage(1); </script>");
newDiv.appendChild(newContent);
TIA
A <script> tag is not a text node.
You need to create a <script> element using document.createElement.
However, you should not do this, unless you're trying to load an external script file dynamically (eg, JSONP)
var js=document.createElement('script');
js.setAttribute("type","text/javascript");
js.appendChild(document.createTextNode(" var pager = new Pager(3); pager.init(); pager.showPageNav('pager', 'pageNavPosition'); pager.showPage(1); "));
var newDiv=document.createElement("div");
newDiv.appendChild(js);
document.appendChild(newDiv);

Categories

Resources