What is the idea behind dataset objects and data- attributes? - javascript

What is the benefit of using the dataset objects and data- attributes? I feel the same thing can be accomplished by extending HTML DOM objects and adding properties to them. (I’m aware this code isn’t exactly reasonable; it’s just a quick example).
There must have been some idea behind adding data- objects to the API. Also is there a convention against adding properties to DOM objects or are these two methods equally acceptable? If this is debatable what are the pros and cons to each method?
There is a similar question involving the jquery version data-objects, but I'm assuming .data() operates a bit differently and maybe has different pros and cons associated with it.
//dataset
let input = document.getElementById("userData");
input.addEventListener("change", function() {
let value = input.value;
input.dataset.value = value;
console.log("input.dataset.value:" + input.dataset.value);
});
//dom objects extending
let input = document.getElementById("userData");
input.addEventListener("change", function() {
let value = input.value;
input.Val = value; //adds properties refering to html object state
console.log("input.val:" + input.val);
});
<div class="userInput">
<label for="userData">Type Something:</label><input type="text" id="userData">
</div>

The idea is that you can safely extend any html element without knowing 100% of present, past and future html attributes.
It also make html code easier to read, because after seeing
<input sync>
I might go and search what is this new sync attribute ?
however
<input data-sync="true">
makes it very clear where it comes from (custom attribute later used in js to add behaviors or styles)
You can then retrieve the value using the DOM dataset API or getAttribute.
It also make it easy to include data with a template based language like PHP.
In a pure javascript settings, I would not use data attributes. WeakMaps allows you to safely extend DOM or you can set a key-value pair directly on the DOM object.

How were you planning on extending the DOM objects?
What property(ies) would you extend them with?
How often would you need to go back and add some new extension?
How would you keep track of all the extensions?
The answers to these questions should make it clear that by using the data-* attribute and then accessing those attribute values with dataset make custom extensions of DOM objects unnecessary.
By the way, it is generally considered bad practice to modify the underlying API of any native object/element.

Related

augmenting a jQuery object with custom properties

In my app, I have a number of jQuery objects which are kept in memory. That is, they don't get regenerated by another selector search. Also, they are local to the module.
const jQthing = $('#thing');
Is there any reason not to add custom properties to this object?
jQthing.title = 'All Things';
I know I can use the data dictionary but this looks a bit clumsy, especially
when retrieving a method. Would this be a bad design, or bad style?
Thanks
You can definitely do this, but you just need to be careful that the property that you add does not clash with any properties or functions that the jquery object would have. And that is why I wouldn't recommend that.
Instead, you would probably be better served wrapping the jquery object in an object and then make your own properties off of that. So for example something like below would do what you want, plus avoid any possible collisions.
var objectWrapper = {
jQthing: $('#thing'),
title: 'All Things'
}
So now you can use it like this objectWrapper.jQthing.fadeIn() or objectWrapper.title, without any worries.

purpose of data in jquery? (vs adding my own fields to Jquery objects)

This question is related to mine and explains what .data method is in Jquery.
Apart from the relation to HTML5 data-* element attributes (like <p class='foo_cl' data-bar='gee'>, for example) why would I code:
$('body').data("my_lab", {some:"object"}); // §1
instead of
$('body').my_lab = {some:"object"}; // §2
(I am mostly interested in the case where the Jquery selector gives one object, like for $('body') above)
The later (§2) seems more readable and shorter, and I guess would be more efficient, than the former (§1). Of course data is a Jquery selector (but I could use each to set the .my_lab field, etc...)
And I might even consider changing the DOM element with the ugly looking
$('body')[0].my_lab = {some:"object"}; // §3 is ugly
(which is perhaps undefined behavior, see this)
Of course, there is the potential issue of colliding the field name my_lab with some existing field in JQuery implementation; but I assume that using some common suffix (like my_) in field names should be enough.
FWIW, I am only interested in recent Jquery (e.g. Jquery 2.1.4) on recent Firefox (e.g. 38 or 42) on Linux.
In other words, why would adding my own fields in JQuery objects be frowned upon?
By doing
$('body').my_lab = {some:"object"};
You are setting value to a specified jQuery wrapper. You would not be able to reaccess the data with another selector :
$('body').my_lab = {some:"object"};
console.log($('body').my_lab); // will log undefined
This is why using data is basically more reliable
$('body').data('my_lab', {some:"object"});
console.log($('body').data("my_lab")); // will log {some: "object"}
For the 3rd option : $("body")[0].attr = { my : "object" } part :
The jQuery data method prevents potential memory leaks when manipulating the dom / removing elements from the page (by removing the binded data and stuff) and avoid attribute conflicts (like setting domElement existing attributes and other subtle things)
So basically, if you have jQuery in you app, you don't really have any good reason to reinvent the wheel by doing manual binding between dom element and javascript data.

Is there an advantage in how I store my data using jQuery?

I know understand more about how jQuery stores data.
Is there any advantage to doing one or the other of these:
$('#editCity').data('href', "xx");
var a = $('#editCity').data('href');
or
$('#editCity').attr('data-href', "xx");
var a = $('#editCity').attr('data-href');
One more related question.
If I have this:
var modal = { x: 'xx', y: 'yy' };
Can I also store this using .data( .. ) ?
Storing property values directly on DOM elements is risky because of possible memory leaks. If you're using jQuery anyway, the .data() mechanism is a wonderful and safe way to keep track of per-element information. It allows for storage of arbitrary JavaScript data structures too, not just strings.
edit — when your HTML markup contains data-foo attributes, those are implicitly read when the keys are accessed. That is, if your HTML looks like this:
<div id="div1" data-purpose="container">
Then in jQuery:
alert( $('#div1').data('purpose') ); // alerts "container"
Furthermore, jQuery will also do some "smart" analysis of the attribute values. If a value looks like a number, jQuery will return a number, not a string. If it looks like JSON, it de-serializes the JSON for you.
edit — here's a good trick: in the Chrome developer console (the "Console" view), you can type JavaScript expressions and have them evaluated. The evaluation is always done in the context of the page you're working on. If you select an element from the "Elements" view, then in the console the JavaScript symbol $0 will refer to that selected DOM element. Thus you can always inspect the "data" map for an element by going to the console and typing something like:
$($0).data("something");
The .data() function, if called with no parameters, returns all the key/value pairs:
$($0).data();
The most interesting point about the data function is that you can add any kind of object, for example your modal. And jQuery, as stated in the documentation, take care of avoiding memory leaks when the DOM changes :
The jQuery.data() method allows us to attach data of any type to DOM
elements in a way that is safe from circular references and therefore
free from memory leaks.
For strings, memory leaks aren't possible but the main difference is that the first solution is cleaner (more coherent if you might store other data than strings in other parts of your application), clearer (the intent is evident), and doesn't force CSS calculation (DOM isn't changed).
They both have advantages... That said, 99% of the time you should be using .data('whatever', value)
Advantages of using .data('whatever', value):
less apt to cause memory leaks because it's not using the DOM.
Slightly faster to pull data from memory than from the DOM.
Can put any type of object in it without serializing it to JSON first.
Advantages of using .attr('data-whatever', value):
compatible with .data('whatever')
allows you to select the element by the value: $('[data-whatever=foo]')
You can put any object in it, but it will need to serialize if it's a complex type.

What is the advantage of using 'data-attribute' over $.data in jQuery?

I was wondering what the advantage is of using data assignment to the DOM vs. NOT to the DOM
i.e. Assume we have said HTML
<a id="foo" href="#">foo!</a>
//Set attr data-me so it's <a id="foo" data-me="yay" href="#">foo!</a>
$('#foo').attr('data-me', 'yay');
//Retrieve the data 'yay'
$('#foo').data('data-me');
Over and above direct assignment:
var myInput = $('#foo');
//Add some data
$.data(myInput, 'data-me', 'yay');
//Retrieve the data 'yay'
$.data(myInput, 'data-me');
My understanding is that the later is MUCH faster and therefore I can't see the sense in adding data-someAttr all over the DOM when it's not required ?
They serve different purposes. Yes, it seems like they can be used to achieve the same thing, but under the hood there are differences.
While you can save simple values in attributes, you can not save DOM nodes, because you will create memory leaks. Neither can you save objects, arrays, functions, etc...
$.attr() might be faster than $('selector').data(), but it is not faster than the low-level method jQuery.data(). The first data method has much more overhead than the second, however the second one does not carry all the functionality of the first one. For example, it does not get the data out of the data- attributes.
Thus, I think it's best to use data- attributes at load time, so you can extract the data with $('selector').attr(), and handle the application state with $.data().
I'm not a guru, that' s for sure... but it appears to me that two obvious differences are the time/environment when the 'data' is set, and the structure(type) of data that will be stored/accessed.
Concider this scenario:
<a id="foo" data-me="some string data" href="#">foo!</a
This pice of html was maybe generated on the server side. If so,only the server side needs to know about the 'data-me' value origin. One limitation is that the attribute must be a string , or a string representation of an object (JSON)
var customData =
{
date:new Date(),
otherProp:'some value',
someFunc: function(a,b)
{
// function dody
}
};
$('#foo').attr('data-me', customData)
From the javascript(medium), at a certain moment, triggered by a certain event(time), you can use jQuery to bind a dom element to a given object (not necessarily a string)
So the latter way ($('#foo').attr('data-me', customData)), removes the 'only string' limitation and allows you to bind to a dom element any kind of js object , even functions.

What is the correct way to store data in the DOM

I have recently been using the title tag in various HTML elements to store data in JSON format in the DOM.
Is this a bad approach (I am assuming it is)? What is the correct way to accomplish this that works well with jQuery? By "works well" I mean
$("myButton").click(function (e) {
var myData;
eval("myData=" + $(this).attr("title"));
});
Works pretty well but again I am assuming there is a better way to do this no?
PS: BTW how does the title tag of HTML elements actually work? I cant seem to find where it actually ends up getting used?
PSS: Can I also get a jQuery based and Non jQuery response? (Sorry to be fussy)
eval("myData=" + $(this).attr("title"));
This is almost a legal reason to slap you! (j/k)
You should use your own namespace object to store data "globally". In that context, globally means only global in your application code and not using the global object (window in a browser).
var my_application = {};
$('myButton').click(function() {
my_application.myData = $(this).attr('title');
});
This is a very basic strategy of course. In your particular case, you can also use jQuery's .data() method to attach data to a DOM node.
$('myButton').click(function() {
$.data(this, 'myData', this.title);
});
Ref.: .data(), jQuery.data()
In your example, I'd suggest doing the following which does not expose you to the security risks of 'eval':
myData = JSON.decode($(this).attr("title"));
In general it's a valid approach to holding non-secure data. You have a number of other options too:
Use JQuery's .data() methods:
myData = $this.data("foo");
In HTML5 you now can use custom data attributes (Eg "") as an attribute on any element. http://html5doctor.com/html5-custom-data-attributes/
You could use Local Storage if you know it is available. http://dev.w3.org/html5/webstorage/
You could use Backbone.js on top of Jquery to give you a more abstracted way of handling your data as Models. http://documentcloud.github.com/backbone/
use jquery data()
The jQuery.data() method allows us to
attach data of any type to DOM
elements in a way that is safe from
circular references and therefore free
from memory leaks. jQuery ensures that
the data is removed when DOM elements
are removed via jQuery methods, and
when the user leaves the page. We can
set several distinct values for a
single element and retrieve them
later:
jQuery.data(document.body, 'foo', 52);
In the jQuery world it is usually said to be a best practice to use the metadata plugin as it is an official jQuery plugin and also supports HTML5 data attributes. For more info you could look at this http://docs.jquery.com/Plugins/Metadata/metadata

Categories