How to get data stored in a DOM element? - javascript

I have a DOM element of class bar that stores data foo, which is the id of another DOM element.
<div class="bar" data="foo">...</div>
When I hover over such element, I want to get the DOM element that the data (id) points to. I did this:
$(".bar").hover(function(){alert($("#"+$(this).data()));});
But when I hover, I get this error:
Uncaught Error: Syntax error, unrecognized expression: #[object Object]
What am I doing wrong, and how can I fix it?

You are confusing the data() method with the element's data attribute.
The data() method returns an unrelated object of data attached to the element and not the string you are looking for.
Solution 1 - data as an attribute
To get the value you're looking for in your example, you should query the attribute with the attr() method:
$(".bar").hover(function(){alert($("#"+$(this).attr('data')));});
Solution 2 - data as an object
Using the data() method you can manually attach information to the element:
$('.bar').data('data','foo');
$(".bar").hover(function(){alert($("#"+$(this).data('data')));});
Note how in this case 'data' is just an arbitrary name for a key in the element's data object. For more on the data() method see the jQuery manual
Solution 3 - data as an object and HTML5 attribute
I believe your original intention was to query the data attribute as an HTML5 data-attribute, that according to the jQuery documentation should be automatically pulled in to jQuery's data object.
However, note that according to the HTML5 specification, HTML5 data-attributes are expected to have a data- prefix. So in order for your example to work, the attribute cannot be named data but rather data-something. For example:
<div class="bar" data-something="foo">...</div>
Which you can then access with jQuery's data() method:
$(".bar").hover(function(){alert($("#"+$(this).data('something')));});
Note how data-something is accessed with data('someting'), since jQuery automatically removes the data- prefix.

you need to access the attribute with the attr function.
$(".bar").hover(function() {
alert($("#"+$(this).attr('data')));
});

I know no one is asking for this, but here is how to do this in modern browsers without jQuery:
for (bar of document.getElementsByClassName('bar')) {
bar.addEventListener('hover', e => alert(
document.getElementById(e.target.attributes.data.value)
))
}

Related

Assign an object to an element as an attribute in java script

I have this scenario where i need to assign a java-script object to div attribute.
var temp["name"]="first";
i assigned it to a div tag attribute using Jquery.
div.attr('data-polygon',temp);
Object [ <div#image01> ]
when i try to retrieve it , it does not come back same.. it is converted as String.
div.attr('data-polygon');
"[object Object]"
Any proper option / alternate to retain the object in attribute? please let me know
Attributes are always strings.
Here are two options for doing this; since you're already using jQuery, the first is probably best:
jQuery's data
jQuery provides the data method for doing this:
// Setting -- notice no "data-" prefix
div.data("polygon", temp);
// Retrieving
varName = div.data("polygon");
Under the covers, traditionally data assigns the element a unique ID and manages a data cache for the element, separate from it. I think in the v3 branch they've updated it to actually store the data on the element (there were memory issues with doing that in Internet Explorer 8 and earlier, which is why jQuery didn't do it before).
Assign it as your own "expando" property
If you don't need to support Internet Explorer 8, you can just create a property on the actual DOM element.
// Setting
rawDiv.myUniquePrefixToAvoidConflicts_polygon = temp;
// Getting
varName = rawDiv.myUniquePrefixToAvoidConflicts_polygon;
Note that to avoid conflicts with the many predefined properties elements have, and future ones they don't have yet, you'll want to use a likely-unique prefix.

jQuery get/select element by property value

Is there a way to get/select an element by it's property value, just as it is possible with the attribute values:
$('[attribute="value"]')
For example, I'd set a property using jQuery like this:
$('#foo').prop('my-property', 'value');
and then I'd like to find an element which has property 'my-property' and it has value 'value'.
No, there isn't anything exposed at the selector level that can select by property value, just (as you know) attribute value.
Some properties are reflections of attributes, which means that setting the property sets the attribute, which allows you to use attribute selectors. For instance, an input element's defaultValue property is a reflection of its value attribute (which its value property is not).
Otherwise, you select by what you can and use filter to filter the resulting list to only the elements you actually want.
Re your edit:
For example, I'd set a property using jQuery like this:
$('#foo').prop('my-property', 'value');
No, there's no way to select by that property directly, you'd need something like my filter suggestion above:
var list = $("something-that-gets-you-close").filter(function() {
return this["my-property"] == "value";
});
You might consider using data-* attributes instead:
$("#foo").attr("data-my-property", "value");
then
var list = $("[data-my-property='value']");
to select it (the inner quotes are optional for values matching the definition of a CSS identifier). Note that attribute values are always strings.
Beware: There's a persistent misconception that jQuery's data function is a simple accessor for data-* attributes. It is not. It manages a data cache associated with the element by jQuery, which is initialized from data-* attributes but disconnected from them. In particular, .data("my-property", "value") would not let you find that later via a [data-my-property=value] selector.

Assigning individual keys of object stored in jQuery.data()

I have custom data stored on elements using jQuery.data() method.
<div id="mydiv" data-test='{"1":"apple", "2":"banana"}'>Custom data</div>
I know I can access individual keys of the object stored in data-test using
$('#mydiv').data('test')["1"]
But is it ok to re-assign individual keys like this ? It works but it isn't documented. Secondly, on inspecting the element using browser's developer tools, I still see the old value i.e. "apple" in this case. JSFiddle
$('#mydiv').data('test')["1"] = "pear"
Update
- Found more related Q&A (not really duplicate because my primary question was about assigning individual keys of the object)
Unable to set data attribute using jQuery Data() API
Why don't changes to jQuery $.fn.data() update the corresponding html 5 data-* attributes?
Can't update data-attribute value : Good discussion in comments of answers
Using .data() to set a value, won't change the values in the element while you inspect it, it would store that data internally. If you want to reflect those changes to the DOM element, then you should use .attr() like this,
$('#mydiv').data('test')["1"] = "pear"
$('#mydiv').attr('data-test', JSON.stringify($('#mydiv').data('test')));
DEMO
Inspect that particular element to verify the changes.
Try this
$('#mydiv').data('test')["1"] = "pear";
$('#mydiv').attr('data-test',function(_,attr){
return JSON.stringify(attr);
});

HTML5 data DOM's change isn't seen by JQuery

I'm using HTML5's data to store some informations on a div on my website, and whenever I change the value of this data with jQuery, the DOM's updating well, but jQuery doesn't see the update when I try to retrieve the value.
I update the value of this data with $('#myDiv').attr('data-my_data',value);, and get the value back with $('#myDiv').data('data-my_data').
Here's the fiddle to illustrate my problem.
Is this happening because of some jQuery's initial representation of the DOM that doesn't update?
I don't get it, any help will be appreciated!
Configuration : Chrome 25 - jQuery 1.9.0 - Mac OSx 10.7
you can set the values to the data('yourKey','Yourvalue')
$(yourElement).data('isEdit','1');
according to your Example
$('#myDiv').data('data-my_data','value');
Attr : it will add attributges to the dom object.
prop : it will add properites in memory. so your data will be stroed in dataSet of DOM.
for more info check this attr vs prop
data-* attributes are mapped to dataset DOMString object, use data method as setter, do not use attr for properties.
$('#testDiv').data('test_data', newData).html("My data is : " + newData);
http://jsfiddle.net/zgKdg/

Best method to get attributes from getElementsByTagName()?

I'm playing around with getting attributes of a link tag, there seems to be several ways of accessing the attributes:
document.getElementsByTagName("link")[0]['media']
document.getElementsByTagName("link")[0].media
document.getElementsByTagName("link")[0].getAttribute('media')
document.getElementsByTagName("link")[0].attributes['media']
It's bordering on ridiculous how many paths there are to the same data. Is one of these methods far superior to the rest?
I would use .media for this case, since media is indeed a property on the link element. Each of these has its use:
['media']: Retrieves the "media" property value using square bracket notation. Use square bracket notation when you don't know the name of the property at design time. For example, when iterating properties.
.media: Retrieves the "media" property value. I'd use this in most cases. It provides concise, direct access to the property value.
.getAttribute('media'): Retrieves the "media" attribute value. Use this when you want the value of an attribute that is not necessarily a property on the element. Not all attributes are properties and not all properties are attributes.
.attributes['media']: Retrieves the "media" attribute node. Use the attributes collection when you need more information about an attribute than just it's value. For example, the attribute name. You can also easily use this to get the value, since .toString() returns the value, but that may be overkill if all you want is the value. The attributes collection is also useful for iterating the attributes of an element.
The method you are looking for is called getElementsByTagName. It returns an array-like list of elements (which is not an array).
Note that your last sample .attributes['media'] does not return a string as the other methods. It returns an attribute node instead.
In theory the ways of accessing the content should be equivalent but browser bugs led to other behavior in reality. It's probably best to use an abstraction layer (a library such as jQuery) to get consistent behavior. If you intend to program without a library the choice depends on your taste however I'd say that going via the attribute node is safest in general.
To add a bit more technical detail, although the different way return the same ways most of the time this is not necessarily true for non-existent attributes. Take the following HTML as example: <a href='test'>. You can try it yourself in another browser on a test jsFiddle (the output below is from Firefox).
// Get reference to element
var a = document.getElementsByTagName('a')[0];
// Existent attributes
console.log(a.href); // String: http://fiddle.jshell.net/_display/test
console.log(a.getAttribute('href')); // String: test
console.log(a.attributes['href']); // Attribute node: href
Note that one time an absolute URI was returned, another time the original value was returned.
// Existent invalid attributes
console.log(a.other); // undefined
console.log(a.getAttribute('other')); // String: thing
console.log(a.attributes['other']); // Attribute node: other
Everything that exists on page load gets merged into DOM but is not available as property if invalid.
// Inexistent but valid attributes
console.log(a.title); // Empty string
console.log(a.getAttribute('title')); // null
console.log(a.attributes['title']); // undefined
The first call returned a properties default value. Then we saw null as a marker for an inexistent attribute. Lastly we got a so called NamedNodeMap which is something like a mixture of an array and object. Accessing it as an object gave the undefined value.
// Creating attributes
a.setAttribute('title', 'test title');
console.log(a.title); // String: test title
console.log(a.getAttribute('title')); // String: test title
console.log(a.attributes['title']); // Attribute node: title
Attribute becomes available as property, too.
// Creating "attributes" by using property
a.rel = 'test rel';
console.log(a.rel); // String: test rel
console.log(a.getAttribute('rel')); // String: test rel
console.log(a.attributes['rel']); // Attribute node: rel
Setting property for a valid attribute also creates an entry in attributes map.
// Inexistent invalid attributes
console.log(a.dummyInvention); // undefined
console.log(a.getAttribute('dummyInvention')); // null
console.log(a.attributes['dummyInvention']); // undefined
Property access on a, marker return value and index access on node map.
// Creating invalid attributes via setAttribute
a.setAttribute('title2', 'test title2');
console.log(a.title2); // undefined
console.log(a.getAttribute('title2')); // String: test title2
console.log(a.attributes['title2']); // Attribute node: title2
Attribute gets created even though its existent is invalid but it is not available as property.
// Creating invalid "attributes" via property
a.title3 = 'test title3';
console.log(a.title3); // String: test title3
console.log(a.getAttribute('title3')); // null
console.log(a.attributes['title3']); // undefined
Object a is extended but DOM is untouched.
// NamedNodeMap of length 4 and indexes other, href, title, rel, title2 (valid attributes or result of setAttribute in order of creation except those from parsing)
console.log(a.attributes);
The node map only reflects the current state of the DOM. It is not aware of extension to our object a that we received via getElementsByTagName.
It's important to note that manipulating JavaScript object does not necessarily affect the DOM. The DOM only reflects the things that have been available on parsing plus modification with DOM methods or property modifications (of predefined properties that is). I hope I did not miss any important cases and that the comments have been verbose enough to see what happens.
I would appreciate a comment on the final NamedNodeMap because I would like to know if Firefox's behavior is correct there to discard the order of the attributes from parsing.
Functionally, they are equal.
Performance-wise, the first two are superior by a significant factor - though they are all extremely fast. See this JSPerf test.
Practically speaking, the first two are easier to read, and my personal preference is the second. (It's also a hair faster.)
The first two options are the the same. You can use either. I personally prefer the .media version since I think it reads easier.
The last two options depend upon getAttribute() and setAttribute() which have not always been reliable in IE. You can read a lot more about that in the reference that Matt posted. As such, I prefer the .media version out of all four of your choices as most reliable and most readable.

Categories

Resources