javascript element.style is undefined in FF - javascript

I want to set up css display property in javascript code:
var div = document.createElement('div');
div.innerHTML = content;
div.childNodes[0].style.display = '';
It works in IE but doesn't in FF. It says "style" is undefined for element div. How can I do it in FF?
Thanks

What is content? If it starts with white space, then there will be a TextNode as the first child and they don't have style properties (HTMLElementNodes do).
You can either:
loop over the children until you either get to the end or find an HTMLElementNode
strip the whitespace from the start of content
switch to using createElement and friends instead of innerHTML

This should also work:
var div = document.createElement('div');
div.innerHTML = content;
div.childElementCount && div.firstElementChild.style.display = '';

Related

How to find the wrapper tag by char position in html

I'm trying to get the html tag object that wraps the char in specific position.
for example:
position = 34
(first 'e' in the word "everyone")
<html><body><h1>Welcome</h1><p>Hi everyone</p><body></html>
Is there a way to get the 'p' tag that wraps this position?
I need the tag object itself, for changing its innerHTML.
One way is to put an element in the string at that position, then add that string to another element and use querySelector and parentNode to get the p tag.
I used BR with an ID, because when using a div etc, it wasn't giving me what I wanted.
let html = '<html><body><h1>Welcome</h1><p>Hi everyone</p></body></html>';
let position = 34;
let obj = "<br id='posObject' />";
html = [html.slice(0, position), obj, html.slice(position)].join('');
let el = document.createElement("div");
el.innerHTML = html;
console.log(el.querySelector("#posObject").parentNode)

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.createElement() vs Document.createTextNode() - Javascript

I'm trying to figure out what is the differences between this two:
// first one
var h1 = document.createElement('h1');
var t = document.createTextNode('hey');
h1.appendChild(t);
document.body.appendChild(h1);
// second one
document.body.appendChild(document.createElement('h1').appendChild(document.createTextNode('hey')));
The first (Document.createElement()) works perfectly, but the second (Document.createTextNode()) does not.
The return value of appendChild is the appended child.
So if we add variables to:
document.body.appendChild(document.createElement('h1').appendChild(document.createTextNode('hey')));
it gets broken down into:
var text = document.createTextNode('hey');
var h1 = document.createElement('h1');
h1.appendChild(text);
document.body.appendChild(text);
Appending the text to the body removes the text from the h1.
The h1 is discarded because it is never appended anywhere.
I find a way to do it: (just add .parentNode at the end)
document.body.appendChild(document.createElement('h1').appendChild(document.createTextNode('hey')).parentNode);

Get all child nodes javascript

Hi I am trying to add a html with a SPACE after in a contenteditable div;
The problem is that, with above code it only return the content of the first DIV and ignore everything else.
var tdiv = document.createElement('div');
tdiv.innerHTML = '<div>testing html</div> ';
var replacment = tdiv.firstChild; //
el.insertNode(replacment); // it is just the purpose, "el" is the HTML element
With this the nbsp will be removed.
If you want all children of tdiv to be added to el then try
var el = document.getElementById('x')
while (tdiv.firstChild) {
el.appendChild(tdiv.firstChild);
}
Demo: Fiddle
You can create an element with an nbsp in it like this:
var div = document.createElement("div");
div.innerHTML = " ";
If you really just want an element with a space of text, you can just create a text node:
var div = document.createElement("div");
div.appendChild(document.createTextNode(" "));
Looking at your question again, it is actually quite unclear what you're really asking and it appears that there are many different things your question might mean. So, this is just one possibility for what you might be asking.
If you want to add it as an element, then you need to put it in some sort of container since a non-breakingspace isn't an element by itself. You can wrap it in a <span> element like this and then insert the <span>.
var span = document.createElement("span");
span.innerHTML = " ";
el.appendChild(span);
Or, maybe it works just fine to insert a text node with a space in it:
el.appendChild(document.createTextNode(" "));
After Arun P Johny Idea I resolved like this:
var replacement = '<div>testing</div> ',startAfter,i,tdiv = document.createElement('div');
tdiv.innerHTML = replacment;
replacment=document.createDocumentFragment();
while(i=tdiv.firstChild) replacment.appendChild(i);
startAfter = replacment.lastChild;
// This is my extra code to the contenteditable div insert and positioning the caret - this.range is my selection range.
this.range.insertNode(replacment);
this.range.setStartAfter(startAfter);
Thank you all, even for the down votes :P

native javascript equivalent to jquery.append when iframes are present

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]);

Categories

Resources