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.
Related
I wish to change the name attribute at dynamic in JavaScript, but I couldn't change the name attribute using either element.name or the setAttribute() method. Is there any other way to set the name attribute?
var status_Element = document.getElementsByName("BD_task_status_"+old_id+"[]");
var final_status_Element = document.getElementsByName("BD_final_task_status_"+old_id+"[]");
for(var in_count=0;in_count<status_Element.length;in_count++)
{
status_Element[in_count].name="BD_task_status_level"+inner_count+"[]";
final_status_Element[in_count].name="BD_final_task_status_level"+inner_count+"[]";
}
Setting the name property as in your example will work (other than the inner_count vs in_count typo). The issue is that getElementsByName returns a live collection of elements. When you change the name of the element at index 0, it no longer belongs in the collection and the collection drops it; then the element that used to be at index 1 is now at index 0. But in the meantime, you've incremented in_count and so you never end up changing that element. Half of them will end up not being changed.
Either:
Loop backward through the collection to change the names (since then the element that disappears is at the end and you don't care), or
Use querySelectorAll instead, which gives you a snapshot collection (not a live one). (querySelectorAll is supported on all modern browsers, and also IE8.)
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);
});
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.
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.
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