How can I ensure that this:
$('.graph svg').append('<polyline points="' + '3,' +point+ ' 97,' +point+ '"style="fill:none;stroke:#FFFFFF;stroke-width:0.5"/>');
Actually results in a self closing tag ..../>
Rather than closing with </polyline>
For some reason only the former renders on iOS.
It doesn't result in any tags at all; it results in elements in the DOM. Tags are textual means of describing elements. When you give that string to jQuery, it asks the browser to parse that string and create elements (objects) in memory. The only tags involved are the ones you give to jQuery.
From your update (comment):
...is there another way of doing this that avoids the append method? Here's a fiddle that refuses to work on iOS http://jsfiddle.net/rCfrF/23
That doesn't work for me on Chrome, Firefox, or IE either. I don't think you can add to SVG elements like that, I think jQuery tries to create an HTML element polyline rather than the SVG polyline (which is namespaced).
This works on Chrome, Firefox, IE, and my iPhone 5: Updated version of your fiddle on JSBin (jsFiddle doesn't work properly on my iPhone 5)
function clickappend() {
var svg = $("#graph svg")[0];
var polyline = svg.ownerDocument.createElementNS('http://www.w3.org/2000/svg', 'polyline');
polyline.setAttribute("points", "20,0 20,100");
polyline.style.fill = "none";
polyline.style.stroke = "#232323";
polyline.style.strokeWidth = "0.5";
svg.appendChild(polyline);
alert('ran');
}
You could use:
$('.graph svg').html($('.graph svg').html() + '<polyline points="' + '3,' +point+ ' 97,' +point+ '"style="fill:none;stroke:#FFFFFF;stroke-width:0.5"/>');
This is the inspector's problem. There is a substantial difference between void elements (aka self-closing elements) and others, in that they cannot accept descendant nodes. polyline is such a void element. The inspector may show it as having a closing tag, but it shouldn't be able to accept methods such as – if you tried to insert content between its opening and closing tags that content would likely be inserted after it in the DOM.
This code work greate in any browser (included IE)
document.getElementById('solicit').innerHTML += document.getElementById('prod1').innerHTML+"< br >";
But when I try remove this same substring using IE, it does not work! In Firefox or Chorme works OK.
var text=document.getElementById('solicit').innerHTML;
document.getElementById('solicit').innerHTML = text.replace(document.getElementById('prod1').innerHTML+"< br >","");
IE does not recognize the substring with < br > ?
I tried without < br > tag and IE works correctly, but I need to be able to add and remove spaces in my HTML element.
using Firefox or Chorme it's replaced with no problem.
How to solve this problem?
Thanks a lot!
The innerHTML property doesn't have to return the exact string that you assign to it. Some browsers do, but IE doesn't.
In IE when you read the property, the HTML code is constructed from the elements in the DOM, not from the HTML code that was used to create the elements. In IE you will get back <BR> even if you use <br> in the HTML code to create the element. That could be solved with a case insensetive replace, but the same applies to the elements inside prod1, which might not be as simple to solve depending on what the code looks like.
You should rather add/remove elements in the DOM instead of manipulating HTML. When you use += and replace on the innerHTML property, you will be converting the elements to HTML, then create new elements again, including all the elements in the solicit element that you don't change. You might consider using a library like jQuery, which makes it a lot easier to manipulate elements.
View source and you might see
<BR>
so add a ,"i" to the replace to ignore case - and possibly a regex to handle the missing white space in the result tag
Thanks for all the help!
Knowing the information that you passed me by saying that IE interprets the < br > as < BR > I was only able to develop this solution:
var text=document.getElementById('solicit').innerHTML;
if (navigator.appName=='Microsoft Internet Explorer')
document.getElementById('solicit').innerHTML = text.replace(document.getElementById('prod1').innerHTML+"<BR>","");
else
document.getElementById('solicit').innerHTML = text.replace(document.getElementById('prod1').innerHTML+"<br>","");
With this browse verification my code works correctly. But I'm sure my solution is not the most "elegant" as possible.
Is there any other alternative using only javascript?
Thanks again
I have a (legacy) JS function, that shows or hides child nodes of argument element. It is used in mouseover and mouseout event handlers to show-hide img tags.
The function looks like this:
function displayElem(elem, value, handlerRoot){
try{
var display = 'inline';
if(!value)
display = 'none';
if(handlerRoot)
elem.style.display = display;
var childs = elem.childNodes;
for (i = 0; i < childs.length; i++){
if(childs[i].nodeType == Node.ELEMENT_NODE){
childs[i].style.display = display;
alert("Node "+childs[i].tagName+" style set to " +childs[i].style.display);
}
}
}catch(e){
alert('displayElem: ' + e);
}
}
Here, value and handlerRoot are boolean flags.
This function works perfectly, if target html page has no doctype. Adding any doctype (strict or transitional) breaks this. Alert shows style has been set to the right value, but child elements are not displayed.
Would be good, if this function could work with any DOCTYPE.
Image (a child node of elem) is initialized like this (perhaps something is wrong here?):
var img = new Image();
img.style.cssText =
'background: transparent url("chrome://{appname}/content/dbutton.png") right top no-repeat;' +
'position: relative;' +
'height:18px;'+
'width:18px;'+
'display:none;';
JavaScript doesn't really work over plain HTML but on the DOM tree generated by the browser. Thus the DOCTYPE does not have a direct influence on JavaScript but on the way the browser handles invalid HTML and CSS.
I think the first step is to clean-up the HTML and make sure it's valid, esp. that tags are used in allowed places and properly nested. That will guarantee that the generated node tree is the same no matter the rendering mode.
You can also use your favourite browser tool (such as Firebug) the inspect the real tree and make sure nodes are placed where you think they are.
Update:
I wonder if when dealing with a document in standards mode (the document has a DOCTYPE), Firefox is inserting an implied element that it doesn't insert in backward-compat mode (no DOCTYPE), and so the image isn't an immediate child of elem but instead a child of this implied element that's then a child of elem; so you won't see the image in elem.childNodes. Walking through the code in a debugger is the best way to tell, but failing that, alert the tagName of each of the child nodes you're iterating through in the loop.
For example, with this markup:
<table id='theTable'>
<tr><td>Hi there</td></tr>
</table>
...Firefox will insert a tbody element, so the DOM looks like this:
<table id='theTable'>
<tbody>
<tr><td>Hi there</td></tr>
</tbody>
</table>
...but it won't be that specific example unless the DOCTYPE is a red herring, because I just tested and Firefox does that even in backward-compat mode. But perhaps you were testing two slightly different documents? Or perhaps it does it with some elements only in standards mode.
Original:
Not immediately seeing the problem, but I do see two issues:
i isn't declared in the function, and so you're falling prey to the Horror of Implicit Globals. Since your alert is showing the correct value, I can't see why that would be the problem.
url(..) in CSS doesn't use quotes. Yes they can, optionally.
Thanks to Álvaro G. Vicario. Though he didn't gave an exact answer, the direction was right.
I've checked the page with w3c validator, and found that my Image objects were missing src attribute. Thus, adding img.src = "chrome://{appname}/content/dbutton.png"; helped.
Still, I'm not sure, why the original code author used background style instead of src... Perhaps, that would remain a mystery. :)
I've been running my head into a wall trying to figure this out. Take the following HTML body:
<body>
<div id="project">
<h1>Hi</h1>
<h2>Hello</h2>
</div>
</body>
And the following jQuery code:
$(function(){
var h = $('#project').html();
$('#project').remove();
$(h).hide().appendTo('body');
alert("Created HTML, hide, and appended!");
});
The $(h).hide() portion causes jQuery to throw an exception in Safari 4 and Firefox 3.5.
Safari: TypeError: Result of expression 'this[a].style' [undefined] is not an object.
Firefox: uncaught exception: [Exception... "Could not convert JavaScript argument arg 0" nsresult: ...]
When I change the HTML to contain just one of the two headings (if you remove the <h1> or <h2> from the HTML, the script runs successfully. Why is this?
To try for yourself, see http://jsbin.com/avisi/edit
Edit: I'm not actually trying to remove and element from the DOM and re-insert it by copying the HTML. This is just a test case for an error I'm having in more complex code, and I'm trying to understand why this error occurs. I agree that, if I wanted to accomplish just what is shown here, I would use something like $('#project').remove().children().appendTo('body')
I cannot duplicate your error in Firefox. However, you might want to try cleaning it up with the following:
$('#project').remove().children().appendTo('body').hide();
Broken down, this is what's happening
// Get the `project` container
$('#project')
// Remove it from the page
.remove()
// Get its children (the h1, h2, etc)
.children()
// Append those nodes to the body
.appendTo('body')
// Hide those nodes
.hide();
Others are proposing that .hide() is causing problems since the node that it is being applied to is not part of the main document; however, this is just not the case. As long as you maintain a reference to any node, you can affect its style property (via hide, show, etc).
One things you might want to check is to make sure that $('#project') is actually returning the (if any) expected node. Problems may arise otherwise.
So I poked around in Safari and found your problem. Here's a dump from the developer console.
> var h = $('#project').html();
undefined
> var t = $(h);
undefined
So far, so good. undefined here simply means that the statement (the var statement) has no return value (which it doesn't)
> t.hide()
ajax.googleapis.com/ajax/libs/jquery/1.4.0/jquery.min.js:131TypeError: Result of expression 'this[a].style' [undefined] is not an object.
Here's the error that you described. Inspecting each item in jQuery object will reveal the error below
> t[0]
<h1 style="display: none; ">Hi</h1>
Good...
> t[1]
(whitespace)
Dammit. Really? Here's the problem. whitespace nodes have no style attribute, which is what's causing the problem.
> t[2]
<h2>Hello</h2>
This is why copying the HTML of one node to another just to move those nodes is a bad technique. I suggest you use the snippet that I provided above.
There's a text node being selected in the $(h). We can filter that out using the filter function though.
This should work (I've only tested in FF though):
$(function(){
var h = $('#project').html();
$('#project').remove();
$(h).filter("*").hide().appendTo('body');
alert("Created HTML, hide, and appended!");
});
Pretty wierd behaviour IMO.
You removed the contents from the DOM before, so there is nothing to hide. If you would do
$(h).appendTo('body').hide();
it should work
I have some JavaScript code that works in IE containing the following:
myElement.innerText = "foo";
However, it seems that the 'innerText' property does not work in Firefox. Is there some Firefox equivalent? Or is there a more generic, cross browser property that can be used?
Update: I wrote a blog post detailing all the differences much better.
Firefox uses W3C standard Node::textContent, but its behavior differs "slightly" from that of MSHTML's proprietary innerText (copied by Opera as well, some time ago, among dozens of other MSHTML features).
First of all, textContent whitespace representation is different from innerText one. Second, and more importantly, textContent includes all of SCRIPT tag contents, whereas innerText doesn't.
Just to make things more entertaining, Opera - besides implementing standard textContent - decided to also add MSHTML's innerText but changed it to act as textContent - i.e. including SCRIPT contents (in fact, textContent and innerText in Opera seem to produce identical results, probably being just aliased to each other).
textContent is part of Node interface, whereas innerText is part of HTMLElement. This, for example, means that you can "retrieve" textContent but not innerText from text nodes:
var el = document.createElement('p');
var textNode = document.createTextNode('x');
el.textContent; // ""
el.innerText; // ""
textNode.textContent; // "x"
textNode.innerText; // undefined
Finally, Safari 2.x also has buggy innerText implementation. In Safari, innerText functions properly only if an element is
neither hidden (via style.display == "none") nor orphaned from the document. Otherwise, innerText results in an empty string.
I was playing with textContent abstraction (to work around these deficiencies), but it turned out to be rather complex.
You best bet is to first define your exact requirements and follow from there. It is often possible to simply strip tags off of innerHTML of an element, rather than deal with all of the possible textContent/innerText deviations.
Another possibility, of course, is to walk the DOM tree and collect text nodes recursively.
Firefox uses the W3C-compliant textContent property.
I'd guess Safari and Opera also support this property.
If you only need to set text content and not retrieve, here's a trivial DOM version you can use on any browser; it doesn't require either the IE innerText extension or the DOM Level 3 Core textContent property.
function setTextContent(element, text) {
while (element.firstChild!==null)
element.removeChild(element.firstChild); // remove all existing content
element.appendChild(document.createTextNode(text));
}
jQuery provides a .text() method that can be used in any browser. For example:
$('#myElement').text("Foo");
As per Prakash K's answer Firefox does not support the innerText property. So you can simply test whether the user agent supports this property and proceed accordingly as below:
function changeText(elem, changeVal) {
if (typeof elem.textContent !== "undefined") {
elem.textContent = changeVal;
} else {
elem.innerText = changeVal;
}
}
A really simple line of Javascript can get the "non-taggy" text in all main browsers...
var myElement = document.getElementById('anyElementId');
var myText = (myElement.innerText || myElement.textContent);
Note that the Element::innerText property will not contain the text which has been hidden by CSS style "display:none" in Google Chrome (as well it will drop the content that has been masked by other CSS technics (including font-size:0, color:transparent, and a few other similar effects that cause the text not to be rendered in any visible way).
Other CSS properties are also considered :
First the "display:" style of inner elements is parsed to determine if it delimits a block content (such as "display:block" which is the default of HTML block elements in the browser's builtin stylesheet, and whose behavior as not been overriden by your own CSS style); if so a newline will be inserted in the value of the innerText property. This won't happen with the textContent property.
The CSS properties that generate inline contents will also be considered : for example the inline element <br \> that generates an inline newline will also generate an newline in the value of innerText.
The "display:inline" style causes no newline either in textContent or innerText.
The "display:table" style generates newlines around the table and between table rows, but"display:table-cell" will generate a tabulation character.
The "position:absolute" property (used with display:block or display:inline, it does not matter) will also cause a line break to be inserted.
Some browsers will also include a single space separation between spans
But Element::textContent will still contain ALL contents of inner text elements independantly of the applied CSS even if they are invisible. And no extra newlines or whitespaces will be generated in textContent, which just ignores all styles and the structure and inline/block or positioned types of inner elements.
A copy/paste operation using mouse selection will discard the hidden text in the plain-text format that is put in the clipboard, so it won't contain everything in the textContent, but only what is within innerText (after whitespace/newline generation as above).
Both properties are then supported in Google Chrome, but their content may then be different. Older browsers still included in innetText everything like what textContent now contains (but their behavior in relation with then generation of whitespaces/newlines was inconsistant).
jQuery will solve these inconsistencies between browsers using the ".text()" method added to the parsed elements it returns via a $() query. Internally, it solves the difficulties by looking into the HTML DOM, working only with the "node" level. So it will return something looking more like the standard textContent.
The caveat is that that this jQuery method will not insert any extra spaces or line breaks that may be visible on screen caused by subelements (like <br />) of the content.
If you design some scripts for accessibility and your stylesheet is parsed for non-aural rendering, such as plugins used to communicate with a Braille reader, this tool should use the textContent if it must include the specific punctuation signs that are added in spans styled with "display:none" and that are typically included in pages (for example for superscripts/subscripts), otherwise the innerText will be very confusive on the Braille reader.
Texts hidden by CSS tricks are now typically ignored by major search engines (that will also parse the CSS of your HTML pages, and will also ignore texts that are not in contrasting colors on the background) using an HTML/CSS parser and the DOM property "innerText" exactly like in modern visual browsers (at least this invisible content will not be indexed so hidden text cannot be used as a trick to force the inclusion of some keywords in the page to check its content) ; but this hidden text will be stil displayed in the result page (if the page was still qualified from the index to be included in results), using the "textContent" property instead of the full HTML to strip the extra styles and scripts.
IF you assign some plain-text in any one of these two properties, this will overwrite the inner markup and styles applied to it (only the assigned element will keep its type, attributes and styles), so both properties will then contain the same content. However, some browsers will now no longer honor the write to innerText, and will only let you overwrite the textContent property (you cannot insert HTML markup when writing to these properties, as HTML special characters will be properly encoded using numeric character references to appear literally, if you then read the innerHTML property after the assignment of innerText or textContent.
myElement.innerText = myElement.textContent = "foo";
Edit (thanks to Mark Amery for the comment below): Only do it this way if you know beyond a reasonable doubt that no code will be relying on checking the existence of these properties, like (for example) jQuery does. But if you are using jQuery, you would probably just use the "text" function and do $('#myElement').text('foo') as some other answers show.
innerText has been added to Firefox and should be available in the FF45 release: https://bugzilla.mozilla.org/show_bug.cgi?id=264412
A draft spec has been written and is expected to be incorporated into the HTML living standard in the future: http://rocallahan.github.io/innerText-spec/, https://github.com/whatwg/html/issues/465
Note that currently the Firefox, Chrome and IE implementations are all incompatible. Going forward, we can probably expect Firefox, Chrome and Edge to converge while old IE remains incompatible.
See also: https://github.com/whatwg/compat/issues/5
This has been my experience with innerText, textContent, innerHTML, and value:
// elem.innerText = changeVal; // works on ie but not on ff or ch
// elem.setAttribute("innerText", changeVal); // works on ie but not ff or ch
// elem.textContent = changeVal; // works on ie but not ff or ch
// elem.setAttribute("textContent", changeVal); // does not work on ie ff or ch
// elem.innerHTML = changeVal; // ie causes error - doesn't work in ff or ch
// elem.setAttribute("innerHTML", changeVal); //ie causes error doesn't work in ff or ch
elem.value = changeVal; // works in ie and ff -- see note 2 on ch
// elem.setAttribute("value", changeVal); // ie works; see note 1 on ff and note 2 on ch
ie = internet explorer, ff = firefox, ch = google chrome.
note 1: ff works until after value is deleted with backspace - see note by Ray Vega above.
note 2: works somewhat in chrome - after update it is unchanged then you click away and click back into the field and the value appears.
The best of the lot is elem.value = changeVal; which I did not comment out above.
As in 2016 from Firefox v45, innerText works on firefox, take a look at its support: http://caniuse.com/#search=innerText
If you want it to work on previous versions of Firefox, you can use textContent, which has better support on Firefox but worse on older IE versions: http://caniuse.com/#search=textContent
What about something like this?
//$elem is the jQuery object passed along.
var $currentText = $elem.context.firstChild.data.toUpperCase();
** I needed to make mine uppercase.
Just reposting from comments under the original post. innerHTML works in all browsers. Thanks stefita.
myElement.innerHTML = "foo";
found this here:
<!--[if lte IE 8]>
<script type="text/javascript">
if (Object.defineProperty && Object.getOwnPropertyDescriptor &&
!Object.getOwnPropertyDescriptor(Element.prototype, "textContent").get)
(function() {
var innerText = Object.getOwnPropertyDescriptor(Element.prototype, "innerText");
Object.defineProperty(Element.prototype, "textContent",
{ // It won't work if you just drop in innerText.get
// and innerText.set or the whole descriptor.
get : function() {
return innerText.get.call(this)
},
set : function(x) {
return innerText.set.call(this, x)
}
}
);
})();
</script>
<![endif]-->
It's also possible to emulate innerText behavior in other browsers:
if (((typeof window.HTMLElement) !== "undefined") && ((typeof HTMLElement.prototype.__defineGetter__) !== "undefined")) {
HTMLElement.prototype.__defineGetter__("innerText", function () {
if (this.textContent) {
return this.textContent;
} else {
var r = this.ownerDocument.createRange();
r.selectNodeContents(this);
return r.toString();
}
});
HTMLElement.prototype.__defineSetter__("innerText", function (str) {
if (this.textContent) {
this.textContent = str;
} else {
this.innerHTML = str.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/\n/g, "<br />\n");
}
});
}