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.
Related
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.
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 aggregating network data from all our Cisco switch ports, plus other stuff from other databases, and am outputting into an HTML file that renders strikingly like this (except I'm an idiot and just realized I drew "tbody" everywhere instead of "thead"):
I'm only displaying 10 rows of data for now in each table (which they are HTML tables with tbody, thead, and tfoot tags assigned; No PHP, Javascript, etc. at all yet, just pure HTML) to keep everything neat and similar (some switches have 48 ports, some 24, etc.). I'd like to use those "Prev, 1, 2, [...], Next" buttons to cycle through the data of each switch, preferably without the page refreshing.
What I've used in the past is this setup:
Give each possible data set to show up its own "div" id
Make their "style.display" attribute = 'none' (except the first page)
Have a Javascript function that puts these divs in an array
The function can hide and show divs and will show only the div I pass
as an argument
Tie this function to an HTML button's onClick event
Is this the best way to go? Since I'm creating this HTML dynamically (I'm outputting text from a C++ program to index.html like a boss), it would mean an issue of assigning div ID's to many different sections, and even then could I create the function to update only the div that the button's parent is in?
I'm thinking this is possible and certainly time-consuming, but I'm not a great web programmer. If there is a better way out there, I'd like to hear it before I proceed to spend too much time on this.
If you don't mind an additional library, datatables would make paging easy (and, as you mentioned, just pre-populate then let JS do the work).
The downside is it's an included library (which means either directly including it in the HTML within a <script> or find a CDN reference to it). The upside is that the paging is built-in and all you have to worry about is getting the data in there. Then, with a few quick config options, and optionally some .CSS changes, you have the desired result.
You can use event delegation to set only a few event handlers:
var footers = document.getElementsByTagName('tfoot');
for(var i=0; i<footers.length; i++) {
footers[i].onclick = function(e) {
console.log(e.target); // the clicked element within the footer
}
}
This will create a single click handler for each table footer, and you can detect which button was clicked by looking at the event object's target property (or srcElement on oldIE). Then you can traverse the DOM relative to that element, using standard properties like parentElement (see MDN for reference).
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.
Wondering if anyone out there has ran into this before....
I'd like to use JavaScript to identify a DOM element on a page, then store it's reference in a database or cookie for later retrieval.
To get specific, what I'm looking to do is create a UI so that when the user CLICKs an element on a page, JavaScript fires the click event, passing the instance of the DOM element clicked on.
easy so far, right?
So what I want to do is store the "identity" of this DOM element, say in a database, so when I later return to this page, I can pull out all stored DOM element identities and get access to them in the page once more.
So this is quite simple if this DOM element has a unique ID. Just store the ID, then when the page comes back up, we just do a getElementByID and we've got our DOM element again.
The problem is that not everything in the DOM has a unique identifier, so there the problem lies.
I had some bad ideas initially, like iterating through the entire DOM and incrementing them with unique class names (dom-01, dom-02, etc) and this would give me an identifier. But this would cause a lot of initial overhead and if the page ever changed, the order of the DOM elements wouldn't be the same, so we wouldn't get back the correct DOM elemet.
I'mve never tried it, but another thought was to serialize the DOM element, stick it in the DB, and then on reload parse to an object, and use that object to find my original DOM element. I've never done that before, so how I can actually compare the restored (parsed) object to the one in the DOM is a big unknown.
Specifics on the serialization solution or any other original ideas for accomplishing this are welcome!!
Thanks in advance everyone!
Here's a jsFiddle solution attempt: http://jsfiddle.net/techbubble/pJgyu/7720/
The approach I took was to compute a simple hash of the HTML content of the target element, or if no such content is present, a hash of the aggregated attributes and values of the element. I have a getElementHash() function that returns a string in the format: TAG:[H | A]:Hash (the H or A indicates if the HTML content or attributes were used to calculate the hash). This produces a unique key for any element on the page that either has HTML content or has at least one attribute (miniscule risk of duplication possible).
For retrieving an element with a previously saved key, I created a getElementByHash() function. It uses the tag that is extracted from the key in a jQuery selector. For each element returned, the HTML content or attributes hash is computed (based on the value "H" or "A" specified in the key) to see if it matches the hash in the key. If there is a match, the search ends and the element is returned.
This approach is impervious to the element being moved around on the page as long as its HTML content (or attributes) remain unchanged. It does not produce a key for elements that have neither any HTML content nor any attributes (which makes them pretty useless anyway).
If you want to keep the location of the node in the DOM, why not just keep an XPath of it? XPath allows you to keep an exact location of a node in a document, as long as that location doesn't change. For instance, you can say something like
//div[#id="xpath_is"]/span[class="cool"]/a[4]
Meaning the 4th <a> tag within a <span class="cool"> within a <div id="xpath_is">
http://www.w3.org/TR/xpath/
http://www.w3schools.com/xpath/default.asp
You can get the XPath of an attribute by Inspecting it with Firebug and right clicking on the node and selecting "Copy XPath". I'm not sure how easy it is to get it from a DOM Node (there are ways, but not sure how many baked implementations there are lying around). It'd be relatively easy to simply look for an ancestor (by traversing upward with .parentNode and building one) and adding .classNames and .ids as you go - but I'm too lazy to write this right now, ;).