I've been using innerHTML and innerText for a while to change elements and text on web pages and I've just discovered that they are not W3C standard.
I've now found that innerHTML can be replaced with createElement, setAttribute and a few others but what is the best method for changing text inside an element?
I found a textContent as well but is there a standard way and is it widly implemented across older browsers?
textContent isn't implemented in IE8 and lower. You can use createTextNode() similar to how you would use createElement(). However, I often use discovery techniques to find out which property I need to use and keep a reference to it:
// You can use a shorter variable name if you want
var innerTextOrTextContent = "textContent" in document.body
? "textContent" : "innerText";
// Set an element's text:
myElement[innerTextOrTextContent] = "Added using: "+innerTextOrTextContent;
The createTextNode() example:
var tNode = document.createTextNode("Added using createTextNode()");
myElement.appendChild(tNode);
Something I often forget about, you can also directly set a text node's value, if you can get a reference to it:
// childNodes[0] is a text node:
myElement.childNodes[0].nodeValue = "Added using nodeValue";
Example - http://jsfiddle.net/BxPaG/.
I think you can't go wrong by using whatever your javascript library offers for changing text (innerHtml for jQuery). After all one of the the main reasons for using such a library is having a platform that abstracts from different browser implementations.
Related
I'm learning Javascript right now, and attempting to change the text title of a particular tab. It's actually part of a larger Shiny dashboard project, but I want to add some custom functionality to a few tabs. Below are the tabs in question:
Simple enough. I first access my tabs in my Javascript file:
var tabScrub2 = $(document).find('[data-value="scrubTab2"]');
console.log(tabScrub2);
When I use Firefox's developer console, I see that the tab is an object:
Moreover, it looks like I need to change the innerText property of 0, whatever this is, since that corresponds to the title of my tab (the innerText of 1 corresponds to the text inside scrubTab2). However, I'm not familiar with the actual object type being returned here:
Simply put, how the heck do I access and manipulate properties from this? And am I actually accessing an array? When I type in
var scrub2 = tabScrub2["1"];
console.log(scrub2);
I get an HTML element. I'm seen the a element in CSS and jQuery, but am not super familiar with how to manipulate its properties programmatically? How do I go about accessing and manipulating the innerText properties of this via Javascript? For instance, how would I hide scrubTab2, or change its title to something else?
The first object you're seeing is jQuery's wrapper around the real DOM elements. It's not an actual array, but it does contain all of the elements that matched your query under zero-indexed properties (e.g. "0" and "1") which allows you to access to them via an array-like API (e.g. tabScrub[1]).
Your method of grabbing a node using tabScrub2["1"] is correct (see this question in the jQuery FAQ). It's more likely to see that done with a numeric key though (i.e. tabScrub[1]) because that matches the way you would access an element in a normal array.
As far as manipulating properties of the DOM node, the DOM's API is notoriously inconsistent and quirky (hence the need for things like jQuery in the first place). However, for your use case you can just assign a string to the innerText property directly (e.g. tagScrub2[1].innerText = "Tab title"). MDN is a great resource if you're looking for reference material on other parts of the DOM.
A side note: if you're looking for a specific element you should use a query that will only match that element. It's generally a bad sign if you're grabbing extra elements and then accessing the element you want at a key other than 0. If you're doing this then your code depends on other (potentially unrelated) nodes in the DOM existing before your node, and if/when you change those nodes your original code will break.
Just use jQuery eq method to get the relevant object index from the array.
For an example
//Query and get first element.
var tabScrub2 = $(document).find('[data-value="scrubTab2"]:eq(0)');
//Hide
tabScrub2.hide();
//Change title
tabScrub2.attr("title", "New Title Text");
Lean more about jQuery eq here.
https://api.jquery.com/eq/
Since you use jquery selectors tabScrub2[0] returns the native DOM element instead of another jQuery object. Therefore the hide function won't work in that object since the native DOM element doesn't implement such type of functionality for an element. That's why you have to use jQuery pseudo selector as above. Because hide will only work with a jQuery object.
Can I access a data- attribute without jQuery?
It's easy with jQuery, but I can't see anywhere how to do it without jQuery.
If I search on Google 'without jQuery' all I get is jQuery examples.
Is it even possible?
On here I found this example:
<div id='strawberry-plant' data-fruit='12'></div>
<script>
// 'Getting' data-attributes using getAttribute
var plant = document.getElementById('strawberry-plant');
var fruitCount = plant.getAttribute('data-fruit'); // fruitCount = '12'
// 'Setting' data-attributes using setAttribute
plant.setAttribute('data-fruit', '7'); // Pesky birds
</script>
So it would appear very doable.
Update: Since Microsoft is now (2020) phasing out the old Internet Explorer engine in favour of a Chromium based Edge, the dataset property is likely to work everywhere. The exception will, for a time, be organizations and corporate networks where IE is still forced. At the time of writing this though - jsPerf still shows the get/setAttribute method as being faster than using dataset, at least on Chrome 81.
You could use the dataset attribute. As in:
element = document.getElementById("el");
alert(element.dataset.name); // element.dataset.name == data-name
It's just an attribute ... use getAttribute as with any other attribute : https://developer.mozilla.org/en/docs/DOM/element.getAttribute
Or am I missing the point of your question.
You can also use:
getAttribute('data-property');
Which is a bit cleaner and easier to read.
This will get the value of the data attribute.
I think you can try this:
var ele = document.getElementById("myelement");
if (ele.hasOwnProperty("data")) {
alert(ele.data);
}
OR use
alert(ele['data-property']);
Say a HTML snippet like this:
<div a_example = "x" b_example = "y" class = "z"></div>
What is the proper way to get the corresponding properties of a_example and b_example in Javascript?
Can xpath do the job?
Use getAttribute:
var elem = document.getElementsByClassName("z")[0],
a = elem.getAttribute("a_example");
Here's a working example.
But, as has already been mentioned, you should really be using HTML5 data-* attributes, otherwise your markup is invalid.
Some browsers will add all attributes as named properties of the DOM element, others will only add standard attributes. In both cases you can get non–standard attributes using getAttribute, however such a scheme is not recommended.
It is common to use standard attributes and DOM properties and only use getAttribute where necessary as it is inconsistently implemented in different browsers.
You should take a look at HTML5 data attributes, here is a useful article: http://html5doctor.com/html5-custom-data-attributes/
Reading data attributes from a tag is really easy, and a fallback is available for older browsers. An example from the article:
<div id="sunflower" data-leaves="47" data-plant-height="2.4m"></div>
<script>
// 'Getting' data-attributes using dataset
var plant = document.getElementById('sunflower');
var leaves = plant.dataset.leaves; // leaves = 47;
</script>
If you are using jQuery, it is as simple as saying:
HTML
<div id="testDiv" a_example = "x" b_example = "y" class = "z"></div>
Javascript:
var attr1 = $('#testDiv').attr('a_example');
element.getAttribute(attributename)
This should work for you.
I agree you should look at data attributes and better ways to do add non-standard attributes, but here's a 'raw' answer to your question, but I wouldn't treat this as universally supported (or advisable):
alert(document.getElementsByTagName('div')[0].getAttribute('b_example'));
Is there a way to create a new element in a Document object from the tag source? Essentially what I'd like to do is something to effect of:
myDocument.createElement('<sometag attr="lol">');
No, native DOM API for .createElement doesn't support that syntax. You need to create the plain Element and set any property either directly on the object
newElem.attr = "lol";
or (better), use .setAttribute()
newElem.setAttribute( 'attr', 'lol' );
What you "could" do is do create a documentFragment, then use .innerHTML to write that string into that fragment and finally .append its contents to its target destination.
well, use innerHTML instead of trying to hack dom manipulation for this kind of thing.
To do so, create a valid node with dom if you want (or get it via getElementById), then set innerHTML of this node with your code
The innerHTML property works here - but it's a tad bit difficult to place the thing where you want it sometimes. For example:
var div = document.createElement('div');
div.innerHTML = "<img src='http://www.google.com/logos/classicplus.png'/>";
In my humble opinion, it's a heck of a lot easier to use jQuery to handle it for you, as it comes with all of the jQuery methods already attached.
var div = $("<div class='blah'><img src='http://www.google.com/logos/classicplus.png'/></div>");
div.find('img').hide();
div.appendTo('body');
div.find('img').fadeIn();
I'm trying to find a way that will add / update attribute using JavaScript. I know I can do it with setAttribute() function but that doesn't work in IE.
You can read here about the behaviour of attributes in many different browsers, including IE.
element.setAttribute() should do the trick, even in IE. Did you try it? If it doesn't work, then maybe
element.attributeName = 'value' might work.
What seems easy is actually tricky if you want to be completely compatible.
var e = document.createElement('div');
Let's say you have an id of 'div1' to add.
e['id'] = 'div1';
e.id = 'div1';
e.attributes['id'] = 'div1';
e.createAttribute('id','div1')
These will all work except the last in IE 5.5 (which is ancient history at this point but still is XP's default with no updates).
But there are contingencies, of course.
Will not work in IE prior to 8:e.attributes['style']
Will not error but won't actually set the class, it must be className:e['class'] .
However, if you're using attributes then this WILL work:e.attributes['class']
In summary, think of attributes as literal and object-oriented.
In literal, you just want it to spit out x='y' and not think about it. This is what attributes, setAttribute, createAttribute is for (except for IE's style exception). But because these are really objects things can get confused.
Since you are going to the trouble of properly creating a DOM element instead of jQuery innerHTML slop, I would treat it like one and stick with the e.className = 'fooClass' and e.id = 'fooID'. This is a design preference, but in this instance trying to treat is as anything other than an object works against you.
It will never backfire on you like the other methods might, just be aware of class being className and style being an object so it's style.width not style="width:50px". Also remember tagName but this is already set by createElement so you shouldn't need to worry about it.
This was longer than I wanted, but CSS manipulation in JS is tricky business.
Obligatory jQuery solution. Finds and sets the title attribute to foo. Note this selects a single element since I'm doing it by id, but you could easily set the same attribute on a collection by changing the selector.
$('#element').attr( 'title', 'foo' );
What do you want to do with the attribute? Is it an html attribute or something of your own?
Most of the time you can simply address it as a property: want to set a title on an element? element.title = "foo" will do it.
For your own custom JS attributes the DOM is naturally extensible (aka expando=true), the simple upshot of which is that you can do element.myCustomFlag = foo and subsequently read it without issue.