Storing custom data in dom elements - javascript

Is this wrong? If so why?
var elm = document.getElementById("myElm");
elm.customValue = {attr1 : "test", attr2 : "test"};
I understand how to use the data attributes, but I don't want to muddy up my dom with all those attributes.

This introduces a memory leak in some browsers because you bind a native C object (the DOM element) and a JS object together and some garbage collection algorithms cannot deal with this. IE is one of them.
Here is an MSDN article about IE memory leaks: http://msdn.microsoft.com/en-us/library/ie/bb250448(v=vs.85).aspx

Bottom line, why wouldn't you use the proper tools available? You have no idea if in the future, near or far, whatever custom property name you are using will be added to the w3c specifications for that particular element. Now, suddenly your code is broken.
Never mind that adding custom properties to elements which already have defined properties makes your code a maintenance nightmare. Whether it's you or someone else maintaining it in the future, there's going to be a "wtf" moment where the developer is trying to igure out if a) a custom property was added to the element or b) the element itself is in fact a custom object.
Finally, what if that element is replaced in the dom via Ajax or dynamic HTML? Now the property is gone and your code is broken.

You should consider HTML5 data-attributes.
From the man himself: http://ejohn.org/blog/html-5-data-attributes/

Related

Set properties on DOM elements happen to be undefined again if I include Polymer Platform on a existing library

The issue's impact
I have a proprietary library and custom elements to make settings on the library. Separately the library is running fine and so do my custom elements.
As soon as I include platform, the functionality of the library gets broken due to missing data. I figured out that set (custom) properties on DOM elements happen to be undefined again where they are expected to still hold set data. At least if platform is not included, the properties hold a defined value.
The issue is given within Firefox 32 and Internet Explorer 11.
Chrome 37 is not affected, suprisingly not even with polymer-dev sources and Platform = {flags: {debug: true, log: 'data', register: true, shadow: 'polyfill'}}.
Backgrounds explained
Platform wraps objects to polyfill functionality i.e. ShadowDOM. So I falsely assumed the wrappers to lose set properties by being exchanged/renewed or to do not delegate properly, however the wrappers stay the same.
As pointed out by kentaromiura within the #polymer IRC channel on freenode and by Scott in the comment below, platform basically needs to wrap every element, but there are bound to be cases where polymer does not wrap. See ShadowDOM#wrap-and-unwrap and ShadowDOM#known-limitations:
Known limitations
document, window, document.body, document.head and others are non configurable and cannot be overridden. We are trying to make these work as seamlessly as possible but there will doubtlessly be cases where there will be problems; for those cases you can use wrap and unwrap to get unblocked.
Having platform included, within the library problems occur where there is still access to unwrapped elements (access via document.body, document.head) and therefore data is registered or read upon unwrapped DOM elements. Peter supposed so.
Possible workarounds
Within IRC kentaromiura added to workaround this by:
[17:57:27] kentaromiura a) [his] preferred method: using selectors instead of pointer
[17:57:46] kentaromiura b) if not possible for any reason use the wrap/unwrap method https://github.com/Polymer/ShadowDOM#wrap-and-unwrap
where b) would be "very discouraged by the polymer guys".
Also Peter demonstrates the selector based workaround a) in his answer.
I am still facing a problem
Apparently listeners are also affected in some way and since the library organizes and visualizes graphs on DOM heavy operations, platform should not engage this for performance reasons.
A new issue will be referenced here soon, where I try to get platform running on just a subtree of custom elements.
Polymer/platform is still great and fun to be used. Thank you all for the help! :)
Hm, I'm not able to reproduce. The below code behaves the same for me in Firefox 32, Safari 7, and Chrome 37. Would it be possible to provide a minimal, viable, and complete example of the issue?
One thought that occurs to me is that you may be ending up with a mix of wrapped and unwrapped elements (the polymer platform needs to wrap all DOM objects in some situations, I think when polyfilling the Shadow DOM).
<script src='http://polymer-project.org/components/platform/platform.js'></script>
<script>
var elem = document.createElement('div');
elem.setAttribute('id', 'myElem');
elem.customProperty = 'hello world';
document.body.appendChild(elem);
var elemFromDoc = document.querySelector('#myElem');
var wasPreserved = (elemFromDoc.customProperty === elem.customProperty);
document.write('Custom property value: ' + elemFromDoc.customProperty);
document.write('<br>Custom property preserved? ' + wasPreserved);
</script>

performance issue : storing a reference to DOM element vs using selectors

So in my app, the user can create some content inside certain div tags, and each content, or as I call them "elements" has its own object. Currently I use a function to calculate the original div tag that the element has been placed inside using jquery selectors, but I was wondering in terms of performance, wouldn't it be better to just store a reference to the div tag once the element has been created, instead of calculating it later ?
so right now I use something like this :
$('.div[value='+divID+']')
but instead I can just store the reference inside the element, when im creating the element. Would that be better for performance ?
If you have lots of these bindings it would be a good idea to store references to them. As mentioned in the comments, variable lookups are much much faster than looking things up in the DOM - especially with your current approach. jQuery selectors are slower than the pure DOM alternatives, and that particular selector will be very slow.
Here is a test based on the one by epascarello showing the difference between jQuery, DOM2 methods, and references: http://jsperf.com/test-reference-vs-lookup/2. The variable assignment is super fast as expected. Also, the DOM methods beat jQuery by an equally large margin. Note, that this is with Yahoo's home page as an example.
Another consideration is the size and complexity of the DOM. As this increases, the reference caching method becomes more favourable still.
A local variable will be super fast compared to looking it up each time. Test to prove it.
jQuery is a function that builds and returns an object. That part isn't super expensive but actual DOM lookups do involve a fair bit of work. Overhead isn't that high for a simple query that matches an existing DOM method like getElementById or getElementsByClassName (doesn't in exist in IE8 so it's really slow there) but yes the difference is between work (building an object that wraps a DOM access method) and almost no work (referencing an existing object). Always cache your selector results if you plan on reusing them.
Also, the xpath stuff that you're using can be really expensive in some browsers so yes, I would definitely cache that.
Stuff to watch out for:
Long series of JQ params without IDs
Selector with only a class in IE8 or less (add the tag name e.g. 'div.someClass') for a drastic improvement - IE8 and below has to hit every piece of HTML at the interpreter level rather than using a speedy native method when you only use the class
xpath-style queries (a lot of newer browsers probably handle these okay)
When writing selectors consider how much markup has to be looked at to get to it. If you know you only want divs of a certain class inside a certain ID, do one of these $('#theID div.someClass') rather than just $('div.someClass');
But regardless, just on the principle of work avoidance, cache the value if you're going to use it twice or more. And avoid haranguing the DOM with repeated requests as much as you can.
looking up an element by ID is super fast. i am not 100% sure i understand your other approach, but i doubt it would be any better than a simple lookup of an element by its id, browsers know how to this task best. from what you've explained I can't see how your approach would be any faster.

Get element by tag name shorthand?

I don't know what it's called, but I know that there's a way to get elements based on their tags without getElementsByTagName. It returns the same thing, but it's shorter and I'm using tags a lot in my project. What I'm talking about is document.frames[x] and document.images[x], but with other elements, like document.b[x] or document.a[x]. Seeing as document.images isn't the same as the <img> tag, it seems like if there are more they'd be named differently as well. Would anyone happen to know what it's called when using this method and/or have a list of accepted tags? Thanks.
P.S. Please do not suggest using a library such as jQuery. This project is meant to be a learning experience, so I want to use regular JavaScript.
As mentioned elsewhere in the answers, this doesn't have anything to do with JavaScript really, these are DOM properties and methods accessible via the JavaScript language binding for the DOM.
With reference to addressing elements such as document.frames[x] (note that this is incorrect, it should be window.frames[x]) and document.images[x] - these are Document Object/HTML Collections and the W3C standard includes only images, applets, links, forms and anchors.
So unless I'm looking in completely the wrong place, from what I can tell from the DOM-1 and DOM-2 specs, there doesn't seem to any way of arbitrarily addressing elements by tag name the way that you remember doing.
Update
The MDC entry on HTMLCollection is more understandable; it reads
The following lists each item (and its specific properties) which return an HTMLCollection: Document (images, applets, links, forms, anchors); form (elements); map (areas); table (rows, tBodies); tableSection (rows); row (cells)
Other than other JavaScript libraries creating these shorthands, I am not aware of any that are built into the language. It would be trivial to map this to your own shorthand:
var $ = document.getElementsByTagName;
// you can then use it like so:
$('SPAN').// and so on
Other than this, there is no built-in array-like access to all of the tags in the document:
http://www.javascriptkit.com/jsref/document.shtml
Create your own reference,
document.tag = document.getElementsByTagName;
or a wrapper,
function tag(name) {
return document.getElementsByTagName(name);
}
The only APIs I know of that support querying by element name are,
DOM
getElementsByTagName
CSS Selectors
querySelectorAll
XPath
evaluate
E4X
(mozilla only, and doesn't work with the DOM yet)

Is it a bad practice to reference Javascript objects from DOM elements?

As a "best practice" for front-end developers, is it bad to use the "control" property to reference back to the Javascript object?
Here's a link to the property in question:
https://developer.mozilla.org/en/XUL/Property/control
I've seen a lot of Javascript functions that reference DOM elements using selectors and then perform DOM manipulation that way. But what if we started by traversing through the DOM tree and we have the DOM element first?
EDIT 1
Okay, it seems like there are some interest here but no contributions for some reason. This started as a conversation between me and my co-worker. He was concerned about circular references and possible cases of losing references... does that apply here? I thought as long as we don't call delete <javascript object> then we're fine.
EDIT 2 I found this: JQuery methods and DOM properties
In my world right now, I'm using the Microsoft AJAX Library where we created multiple ScriptControls and put them on various pages; which in turn, (the ScriptControls) get "modified" by page's events and sometimes events of other ScriptControls. When pages need to do something with the DOM element, the Javascript would use the respective Javascript Object's methods.
However, it seems in JQuery (based on the other question), it's common to get the DOM element then use .get(0) to grab the JQuery object out of it (if it exists).
So I guess this is a witch hunt so far and there's still no right answer to my question :(
I know I'm still lacking an example but I'm not sure how to approach this.
I am not too sure what exactly you're referring to. Could you provide a simple code example? Otherwise, your question is a bit vague IMHO. I'll give it a shot anyways:
I do not understand why there would be any lost or circular references. The control attribute is just the id (string) of the "controlling" DOM Element, not a reference to the actual DOM Element. If you delete label.control it will no longer be associated with the other DOM Element.

DOM properties/methods that aren't available in jQuery?

Following up on my question about jQuery.get() I was wondering if there is a list of DOM properties and methods that aren't available in jQuery that can only be accessible if you were working with the raw DOM object (i.e. $("#someID").get().scrollHeight; )
I haven't encountered a list but if one existed it would probably be quite lengthy. In addition to browser-specific (proprietary) properties there's a bunch of other less useful properties and methods not currently abstracted by jQuery. But then, I don't really see this as a problem, or even a valid point of discussion because jQuery IS JavaScript; if you need access to something beyond what jQuery provides then you can use get() or access a specified element within one of your "jQuery collections" like an array:
jQuery(elem)[0].someDOMProperty;
Plus jQuery provides absolutely no support for non-element nodes within the DOM. If, for whatever reason, you need direct access to comment nodes, text nodes etc. then you'll need to use the "raw" DOM.
I don't know of a compiled list of DOM operations/properties that are NOT available in jQuery (and a quick google search didn't turn anything up), but if you go to http://api.jquery.com/ you can see the entire API, and even download it as an Adobe AIR app in case you don't have internet when you need it.
No. JQuery is just JavaScript. If you can do it in JavaScript, you can do it in jQuery. Some properties and methods are overwritten in the context of a jQuery object and that's where you would want to us the get() method--to 'get' (i.e. access) the standard property/method.
That's really as complicated as it is.
Every attribute of every element is accessible through the attr() function. If you could do a document.getElementById() on that element and then access a property, you can also do it using the attr() function. However, some properties are accessed more easily in other ways when using jquery. For example, to see if an element is hidden or visible, you could do:
var isVisible=$("#el").is(":visible");
instead of using the attr() method. Similarly, you can find the selectedIndex of dropdowns and the text of the selected option, in easier ways than using the attr() method. This pdf outlines some of these easier approaches.
To access a css property, you are better off doing:
var fontWeight=$("#el").css("fontWeight");
rather than using get() or attr(). You can also set the css properties in this way, e.g:
$("#el").css("fontWeight","bold");
I could be wrong, but I think you can access any properties via the attr method.

Categories