Adding arbitrary information to createElement object - javascript

This w3schools page mentions the HTML DOM createElement() Method. For example, you can create a button by
var btn = document.createElement("BUTTON");
Now, I want to attach some information to this button. What is the appropriate way to do it? If I want to attach the array ["one", "two", "three"], can I just do
btn.myOwnInformation = ["one", "two", "three"]
?

You can use the html5 data attribute to add arbitrary data to DOM elements.
btn.setAttribute('data-array','one,two,three');
Get the data back by using split;
Here's an example: jsFiddle

That certainly works if you try, but it is usually discouraged, for a few reasons:
Separation of concerns
The DOM is meant for display structure and logic, so any other kind of data is better stored separately.
Collision with future DOM specifications
What if you choose a property or method name that becomes a standard in the future? Your code may become buggy on future browsers.
Browser compatibility
Old browsers (IE 6/7) could leak memory when data was attached to DOM objects. It's less of a problem now, but since JavaScript objects provided by browsers ("host objects") are less controllable, I suggest avoiding to extend them (or their prototypes) unless you know what you're doing.
For those reasons, libraries like jQuery use a separate structure to store arbitrary data (and also event handlers) and relate them to DOM elements. For the same reasons, jQuery wraps selected DOM nodes in jQuery objects, instead of directly extending the DOM interface with methods like append, css, etc.
Related questions and references
Storing data in the DOM
Javascript DOM: Setting custom DOM element properties
What’s wrong with extending the DOM
Can I just make up attributes on my HTML tags?
Jquery data() storage
Storing custom data in dom elements
I know its bad to store data in the DOM, but why?

If you are willing to use jQuery
there's a function which can match you requirement
jQuery.data()
code can be written like this:
var $btn = $('<input type="button" value="buttonName">');
$btn.data('keyName',["one", "two", "three"]); //insert data
var getData = $btn.data('keyName'); //get data by keyName
(Sorry, I don't have enough reputation to use commend)

Related

dataset vs .data - Difference?

I am reading some values in data attribute fields. I have seen two easy ways to read the data as shown below:
var webappData = document.getElementById('web-app-data'),
rating = webappData.dataset.rating;
OR
var effectData = $('.effects-list li'),
creative = effectData.filter('[data-creative]').data("creative");
My question is which of these has better performance or do they really differ?
I have a page with many data attributes that I am accessing and I would like to use the method that has the best performance.
Any guidance on understanding the difference between the two would be appreciated. While I am looking at performance specifically if there are other reasons to use one over the other I would like to know this as well.
dataset is a native property of an element that contains the data attributes, it's a new(ish) addition and as such is only supported in IE11+, Chrome 8+, FF 6+ etc.
A more cross browser solution would be to get the attribute directly
webappData.getAttribute('data-rating');
data() is a jQuery method, and other than using the HTML5 data attribute to set the inital value if none exists internally, it has nothing in common with dataset.
data() stores whatever data you pass it in an internal object created by jQuery, so this for instance would fail
$(element).data('key', 'value');
element.dataset.key // undefined
as the data is not stored in the attributes at all, but internally by jQuery.
The jQuery equivalent of getting and setting the data attribute would be attr()
$(element).attr('data-key', 'value');
The native methods are probably faster, but as they are not really comparable to jQuery's data() it doesn't really matter, but for getting the data attribute I would think the fastest method with the best browser support would be
var rating = webappData.getAttribute('data-rating');

Remove all the DOM elements with a specific tag name in Javascript

How can I remove all the elements with a specific tag name using Javascript. For example, I did the following:
var els = document.getElementsByTagName("center");
and it returned an array of all the center elements. How may I remove all these elements?
Coming from Remove all child elements of a DOM node in JavaScript and JavaScript DOM remove element I know that I can loop through els, find the parent of each element and then remove that specific node. But is there anyother way provided by javascript. Like we can do $('center').remove() in jquery and it removes all the elements with center tag. Anything similar to that in Javascript?
With the mention that you still loop over the elements (there is no way to avoid that), you can do this:
Array.prototype.slice.call(document.getElementsByTagName('center')).forEach(
function(item) {
item.remove();
// or item.parentNode.removeChild(item); for older browsers (Edge-)
});
DEMO: http://jsbin.com/OtOyUVE/1/edit
Some notes on slice:
document.getElementsByTagName doesn't return an array, it returns a live list with a length
property. That is why it is needed to first convert it into an array (Array.prototype.slice does that for any object with the length property). By doing that you eliminate the problem of the list being live (gets updated when you change the DOM) and you also get the other array functions to work (like forEach) which have a more functional syntax for looping.
"it returned an array of all the center elements."
Well, it returned an array-like object (a live NodeList or an HTMLCollection depending on the browser).
"How may I remove all these elements?"
You have to loop through the list removing them one at a time as you mentioned later in your question. If you find yourself doing that a lot, encapsulate the looping inside a function so that you don't have to repeat it.
"we can do $('center').remove() in jquery and it removes all the elements with center tag. Anything similar to that in Javascript?"
jQuery is a collection of JavaScript functions, so it can't do anything JavaScript can't do. jQuery's .remove() method (like most other jQuery methods) will loop internally, it just saves you having to think about it. So that comes back to what I already mentioned above, encapsulate the loop/remove code in a function so that you can use it from any part of your code.

What is the fastest way to get multiple data-attributes from the same element

I have a use case which requires getting multiple html5 data-attributes from elements. This occurs within a loop across many elements and pushes the data in to an array for caching.
From doing some research it appears that using el.getAttribute('data-whatever') is faster than using the native html5 dataset method however I need to get around 5 separate data attributes from the same element.
The dataset method allows you to retrieve all data-attributes with one call and then access them with standard object dot notation ( dataset.index, dataset.whatever, dataset.somethingelse ) whereas using getAttribute I have to make repeated getAttribute calls to retrieve all the needed data.
If using non compliant attributes I can of course simply use dot notation to access the properties speeding up this function considerably. But using html5 data attributes this does not work (i.e. el.data-whatever will always be undefined).
I wish to remain compliant to standards therefore I am looking for the fastest possible way of retrieving these multiple data attributes.
Thanks in advance.
I made this test:
http://jsperf.com/dataset-vs-getattribute-2
The test is a the following:
dataset all:
var data = el.dataset;
getAttribute all:
var data = {
id: el.getAttribute('data-id'),
user: el.getAttribute('data-user'),
dateOfBirth: el.getAttribute('data-date-of-birth')
};
dataset single:
var user = el.dataset.user;
getAttribute single:
var user = el.getAttribute('user');
https://developer.mozilla.org/en-US/docs/Web/API/element.dataset
Just benchmark it :
http://jsperf.com/dataset-access-vs-getattrb
It still looks to be 2 times faster using getAttribute on chrome.
I'm using a noop to prevent the JIT from optimizing it away.

Iterate over a jQuery collection without having to rebuild the jQuery object

$(".item").each (i, elt) ->
$(elt).attr("href")
# ...
Doing $(elt) is necessery to get the jquery object. Is there a way to iterate over a jquery collection, without having to rebuild the jquery object?
Doing $(elt) is necessery to get the jquery object.
Yes.
Is there a way to iterate over a jquery collection, without having to rebuild the jquery object?
No. Because the jQuery object you have is a set of all of the matched elements. To use the jQuery methods on individual elements, you need to get a jQuery object containing just the individual element you want to act on. In a loop, that means wrapping your elt (or this, as both are the same DOM element).
For lots of things, though, you don't need jQuery methods. Your example is one of those things, just use elt.href directly:
$(".item").each (i, elt) ->
var someVar = elt.href;
# ...
The DOM2 HTML spec and the newer HTML5 spec both list lots of reflected properties you can use directly. id, for instance, is one in particular people frequently use. You see $(this).attr("id") a lot where this.id would be sufficient (and more efficient, although it's extremely rare that the efficiency matters).
Yes, cache the jQuery object then select by index.
var $items = $(".item");
$items.each(function(i) {
$items.eq(i).doStuff();
});

Deriving an HTMLElement Object from jQuery Object

I'm doing a fairly exhaustive series of DOM manipulations where a few elements (specifically form elements) have some events.
I am dynamically creating (actually cloning from a source element) several <select> boxes and assigning a change() event to them.
The change event executes, and within the context of the event, "this" is the HTML Element Object.
What I need to do at this point however is determine a context for this HTML Element Object. I have these objects stored already as jQuery entities in assorted arrays, but obviously
[HTMLElement Object] != [Object Object]
And the trick is that I cannot cast $(this) and make a valid comparison since that would create a new object and the pointer would be different.
So... I've been banging my head against this for a while. In the past I've been able to circumvent this problem by doing an innerHTML comparison, but in this case the objects I am comparing are 100% identical, just there's lots of them. Therefore I need a solid comparison.
This would be easy if I could somehow derive the HTMLElement object from my originating jQuery object.
Thoughts, other ideas? Help. :(
This would be easy if I could somehow derive the HTMLElement object from my originating jQuery object
you don't just mean $("#object")[0] or $("#object").get(0) with 'derive' do you?
Can't you just use $(this).data("something") to keep data on your elements and then check the values later? (That's assuming you can't just give these things plain ol' "id" values.)
Oh also jQuery itself has a "guid" element that you can use (be careful!)
$(myNewObject).data("identity", $.quid++);
If you maintain a jQuery object containing the elements you've created/cloned (let's call it "jqClonedElements"), you can reduce that set to the single element matching "this" with $().filter(element):
var jqThis = jqClonedElements.filter(this);
After this, you may want to confirm that your element was found, as follows:
var elementWasFound = (jqThis.length > 0);
That should be all there is to it!
-Matt

Categories

Resources