I'm creating a HTML page with many, many "widgets" (can be in the magnitude of 1000, many not visible by display:none which get's modified dynamically by user interaction).
Each widget must carry some information regarding it.
At the moment I'm building that DOM piece by piece and add a jQuery .data() to each widget. But this building of little blocks is too slow (lots of time spent in Parse HTML), so I want to switch to a new approach where I first build a string of all widgets and then add that to the DOM with innerHTML at one go. But this doesn't allow me to use the .data() during the build anymore.
As all widgets have a unique ID anyway (currently only stored in the .data()...) I could think of two obvious solutions:
Give every widget an id attribute with the widget ID as content
Give every widget an data-widgetid attribute with the ID as content
(Parallel to that I'd have a big JavaScript hash that links the widget-id to the per widget data.)
What approach should I prefer?
Performance and resources is an issue (also on mobile devices).
By the id attribute I'm interfering with the DOM, so I don't know if that could have any negative effects. (E.g. it could be that browsers are starting to build an extra look up structure for that internally that I could avoid otherwise. I'm not a browser developer, so I don't know if that is the case though)
Use ID. If you want to protect the ID namespace of the DOM, use a prefix. For example, , where "123" is the unique ID. If your application is driven by a database, the primary key conveniently provides non-colliding ID values. Otherwise use a client-side counter to generate unique IDs.
Accessing the element by ID is much faster via document.getElementById. Modern browsers allow this kind of access really fast. The internal storage is also more efficient comparing to a custom attribute. To access a custom attribute, you'll have to traverse all the matching nodes and compare them with the values of the custom attribute. Some old IE also don't support custom attributes.
If you don't need to get those elements by their id, and you will only use it to associate data with the elements, I would recommend not using id.
Since ids are unique, browsers build a hash table to retrieve elements by id so fast.
Therefore, adding ids to lots of elements that don't need them will increase the size of the hash table unnecessarily.
In average, a search in a hash table is O(1), so the size doesn't matter. However, on the worst case, it's O(n), so better have a small table if you can.
This way, if you use document.getElementById to get other elements, it may be faster.
Related
I am designing a web page and want to be able to hide/show certain divs based on the user clicking filter buttons.
I have seen DOM elements with aria-controls and also with data-attributes (I could add either to my div elements in order to later find them with jQuery and show/hide them).
When it comes to selecting DOM elements with jQuery, I wondered if there is a difference between the two methods?
I've Googled aria-controls but haven't managed to work it out.
Which would be the preferred method (and why)?
Many thanks
When it comes to selecting DOM elements with jQuery, I wondered if there is a difference between the two methods?
From a performance standpoint, no. They are both just attributes, and I don't know of any special mechanism that boosts performance of finding elements by aria-* attributes.
From an ideological standpoint, yes.
The aria-* attributes are meant to enhance the accessibility of JavaScript heavy pages. If the purpose of your JavaScript is to enhance accessibility then it might make sense to select elements based on the aria attributes. If you just want to identify a user interface component, then using data attributes might be more descriptive. If there is an accessibility feature in newer browsers that you want supported in older browsers then JavaScript selecting elements based on aria attributes makes sense, because you are creating a pollyfill that would most likely require the use of aria attributes even in supported browsers.
I would use these guidelines:
Creating pollyfills for accessibility features in older browsers (select by aria)
Building your own accessibility enhancements (select by aria)
Want to identify user interface elements without regards to accessibility, or having nothing to do with accessibility (use data attributes)
ARIA controls are meant for accessibility, and data attributes are meant for your own custom use that has no meaning to the browser, but has meaning to your application. Ultimately this is the differentiating factor.
Specifically, I have areas of my (heavily JS) web page that contain lists of HTML elements and for simplicity let's assume there are just two lists: A and B. Let's also say When I click on the first item in list A (A1) something happens to the first item in list B (B1).
I gave each element in list A a common HTML class and an ID (like <li class='listAmember' id='1'>...</li>). I set up elements in list B in a similar way (like <li class='listBmember' id='1'>). Then I attached some click handlers (using jQuery in this case) and ran into problems with duplicate IDs, even if I qualified my jQuery id-based selectors with the class name, like this
$('.listAmember#1').click(function(){});
I've realised that this is bad practice (IDs are supposed to be unique in the document!) but I'm unsure what good alternatives there are.
I don't really want to create IDs like listAmember-1 because if I have, say, a lookup-table in my JS code that is keyed on the numeric ID, I'd need to parse out the 1 from that ID string to get the 'real' ID. (And I would still need to add a class like listAmember for styling purposes and that seems unnecessarily repetitious?) All in all that seems clumsy and I assume there are better ways?
As Florent says, I would try and avoid IDs altogether. One convention is to use class names like js-list-a to signify it's a class intended for JavaScript usage only. Then you're free to start using the index of the li within the list.
Also, you could just set one click handler on the list and use event delegation .
A combination of these ideas means you won't have to touch IDs.
For Unified ID's maybe in a System that has external Libarys in use, you should always attach them with a Namespace. For Example like: "myFancySlider-container"
This helps to keep names Unique for your special application.
If you generate Dynamic Code, you have to Make sure, to only create One of each object. Or you Assemble them With iterations. An alternative to that, could be the unifying with Timestamps.
EDIT
As others already mentioned, you should avoid Using ID's as you can. ID's only make sense, to benefit from the Unique Attributes. For example, you know exactly what element you want, so an ID can be a verry good shortcut for that. Specialy in dynamic Content Applications.
I'm experiencing an issue which has two possible solutions. I am unsure which solution is 'more correct.'
I have a modal dialog which opens above a page. This dialog hosts an element with ID "foo".
Now, that is not an issue at all on its own. However, the non-dialog page has multiple tabs. One of these other tabs, deep down in some content, also has an ID "foo." This causes weird, intermittent issues depending on which "foo" is encountered first when traversing the DOM tree.
Unfortunately, both values are presenting exactly the same information in exactly the same way. The only difference is that one is being hosted inside of a dialog. The same model is being used -- thus the same ID is being generated by my ViewModel.
I can do one of two things:
Explicitly override one of these ID-creation methods to ensure that the ID generated in the dialog is unique when compared to that of the non-dialog.
Modify my jQuery search selector to only read from the dialog's form inward -- ensuring that the dialog will not capture unexpected DOM elements.
It would seem like the second idea is a better practice. I traverse less DOM nodes and don't have to hack anything in. However, to an unknowing developer, one could still accidentally re-introduce this issue by not starting searching from the proper area.
The same issue could be said to any developer working on our application, though. They would need to know explicitly to override the ID-creation of the ViewModel such that it does not create the same ID.
Is it ever acceptable to have repeating IDs if they're encapsulated in different forms? Where does the expectation of an ID being unique cease to make sense?
The ID is generated through MVC's EditorFor HTML Helper. I can override this in such a way that it generates a form-specific ID, but that was clearly not MVC's intention.
<%= Html.EditorFor(model => model.CustomerDisplayName) %>
UPDATE: It appears I should be enforcing the IDs uniqueness. However, ASP.NET MVC3 does not seem to provide an easy way of ensuring an ID is unique to the DOM. I can append on the form's ID, but that would generate huge IDs.. not sure if that is the best call. Any thoughts?
Is it ever acceptable to have repeating IDs if they're encapsulated in
different forms?
It is never acceptable, an ID should be unique. Otherwise your document is not valid.
Where does the expectation of an ID being unique cease to make sense?
The expectation of an ID being unique never ceases to make sense. It's part of the specs to have an unique ID per element.
Do you have control over the IDs? If you do, perhaps ID isn't the most "proper" way to go about it. If you used a class instead, then:
$("#DialogID .foo")
would select it without the potential for foo being a duplicated ID. The above selector will restrict the search to within the specified dialog.
To your question "To what extent should I enforce a DOM element's ID's uniqueness?", I boldly answer "You should NOT enforce unique IDs".
"Blasphemy!", I hear the Pharisees shout, vigorously waving the W3C bible.
But I live in the real world.
1. It is impossible.
It is virtually impossible to create a large website that guarantees the uniqueness of IDs.
Modern website are assembled from unrelated components, be it plug-ins, ads, widgets, you name it. All using their own set of IDs without knowing the existence of the other IDs on the page.
Technically the unique IDs can only be enforced by using some sort of GUID.
Of course, you could qualify, prefix or suffix your IDs with a classname or parent id and turn it into a long hierarchical composed ID. In fact this isn't that bad of a practice.
But there will be no guarantee. Bottom line.
2. It's not your fault.
Repeat after me: "It's not my fault...it's not my fault...".
I find it intellectually lazy and frustrating that the W3C team keeps this all too simplistic dogma alive, without looking at the real world. Do they suggest how to enforce this rule? Of course not - it's not their job. They only write the specs. But, if no one abides the law, either all of us are evil and doomed...or the law itself is at fault.
So, once again, repeat after me: "It's not my fault...it's not my fault...".
3. A bit of creativity, perhaps?
Is there really no way to adjust that rigid rule and come up with a practical solution? Either in the specs or implemented in the browsers? A form of "id scope"? A namespace?
4. Darwin says "To survive, you need to adapt."
The only way to survive in the real world is to adapt to the real world, with all it's imperfections. Some survival advice (as suggested by others already):
The more unique you make your IDs, the less chance for errors.
When searching for IDs, assume that there may be duplicates on your page. So, limit your search as much as possible.
Now stone me, I dare you.
You should enforce ID uniqueness 100%
The DOM requires that IDs be unique within it, else it is not valid, and as you've discovered you get strange and sometimes intermittent errors if you violate that requirement.
You can introduce some way to change the ID based on context, as you've mentioned, or you could take the approach of combining classes so you have, for example <div class="main foo"> and <div class="dialog foo"> where you can then use selectors to find "div.main.foo" or "div.dialog.foo" -- or get both by using just "div.foo"
Say I have a container element/div on a page. There are other elements outside of it, comprising page layout/navingation, and there is a fair amount of content inside of it.
In my javascript, I need to find/manipulate a few elements inside of that container. If all of these elements have id properties set, speed wise, is it better to use document.getElementById() (considering that once found, the element will need to be turned into a jQuery object for manipulation) to find them, or to select them using jQuery like so: $("#id"), or to select the container first, store it in a variable, and then select the elements to be manipulated using jQuery like so: container.find("#id")?
Which approach is faster? What does the speed of searches like these depend on?
As jQuery() with an id selector uses document.getElementById inside, using the native method directly is obviously faster. Of course the overhead is neglibible (you never need to select hundreds of elements by id), and they do different things - most likely you want to get a jQuery wrapper object containing the DOM node.
container.find(idselector) is an interesting case, though. As ids are unique all over the document, you should not need such an expression at all. Because of that, id selections are usually boosted by a O(1) lookup table inside the browser, and very fast even for full documents. I'm not sure what happens when you use it inside a container, but it might fall back to a rather slow DOM tree traversal.
I need to store data in html documents that are associated with elements, and that I can get to with javascript. I think I want to avoid arbitrary attributes on elements, since after reading various posts here I don't trust them. I can't use id or class, since I those are used for other things and I don't want to mess with them (my project has to work on wide varieties of html so I can't make any assumptions as to the design of the class and id structure). Another thing I need is for whatever I do, it needs to survive round-tripping through innerHTML (of a parent or ancestor element of the element I need to tag with data), with data intact.
I have considered various hidden elements (including script tags and html comments), which I insert into the document right before the element I need to tag with data. Currently my favorite is hidden form elements (i.e. input with type "hidden"). I can stick any data I want into the "value" of the element, and I can find all such elements easily enough with getElementsByTagName(). Also importantly, it doesn't seem to affect the layout of the page.
I'm curious about the ramifications of this, and if anyone can think of any any problems with it. I need to be able to put them anywhere in body of the page, before any element. For instance I might need them associated with an option element (a child of a select element), so that rules out using a hidden div, since putting one of those inside a select element is illegal. I don't think they will affect form behavior, since they don't have a name attribute (I can avoid using id's if that helps).
Any thoughts on this, or suggestions for other ways of accomplishing the same that meets my needs?
If this is going to be data for JavaScript's purposes, why even try to put it in the HTML at all? Here's a simple example of what I mean
<script type="text/javascript">
var nodeData = {
foo: {/* Data to associate with div#foo */}
, bar: {/* Data to associate with div#bar */}
};
</script>
<div id="foo">Foo!</div>
<div id="bar">Bar!</div>
It's simple and elegant since the principle of IDs being unique per document nicely matches with javascript's dictionaries requiring unique keys per entry.