Recently I have been reading more and more about people using custom attributes in their HTML tags, mainly for the purpose of embedding some extra bits of data for use in javascript code.
I was hoping to gather some feedback on whether or not using custom attributes is a good practice, and also what some alternatives are.
It seems like it can really simplify both server side and client side code, but it also isn't W3C compliant.
Should we be making use of custom HTML attributes in our web apps? Why or why not?
For those who think custom attributes are a good thing: what are some things to keep in mind when using them?
For those who think custom attributes are bad thing: what alternatives do you use to accomplish something similar?
Update: I'm mostly interested in the reasoning behind the various methods, as well as points as to why one method is better than another. I think we can all come up with 4-5 different ways to accomplish the same thing. (hidden elements, inline scripts, extra classes, parsing info from ids, etc).
Update 2: It seems that the HTML 5 data- attribute feature has a lot of support here (and I tend to agree, it looks like a solid option). So far I haven't seen much in the way of rebuttals for this suggestion. Are there any issues/pitfalls to worry about using this approach? Or is it simply a 'harmless' invalidation of the current W3C specs?
HTML 5 explicitly allows custom attributes that begin with data. So, for example, <p data-date-changed="Jan 24 5:23 p.m.">Hello</p> is valid. Since it's officially supported by a standard, I think this is the best option for custom attributes. And it doesn't require you to overload other attributes with hacks, so your HTML can stay semantic.
Source: http://www.w3.org/TR/html5/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes
Here's a technique I've been using recently:
<div id="someelement">
<!-- {
someRandomData: {a:1,b:2},
someString: "Foo"
} -->
<div>... other regular content...</div>
</div>
The comment-object ties to the parent element (i.e. #someelement).
Here's the parser: http://pastie.org/511358
To get the data for any particular element simply call parseData with a reference to that element passed as the only argument:
var myElem = document.getElementById('someelement');
var data = parseData( myElem );
data.someRandomData.a; // <= Access the object staight away
It can be more succinct than that:
<li id="foo">
<!--{specialID:245}-->
... content ...
</li>
Access it:
parseData( document.getElementById('foo') ).specialID; // <= 245
The only disadvantage of using this is that it cannot be used with self-closing elements (e.g. <img/>), since the comments must be within the element to be considered as that element's data.
EDIT:
Notable benefits of this technique:
Easy to implement
Does not invalidate HTML/XHTML
Easy to use/understand (basic JSON notation)
Unobtrusive and semantically cleaner than most alternatives
Here's the parser code (copied from the http://pastie.org/511358 hyperlink above, in case it ever becomes unavailable on pastie.org):
var parseData = (function(){
var getAllComments = function(context) {
var ret = [],
node = context.firstChild;
if (!node) { return ret; }
do {
if (node.nodeType === 8) {
ret[ret.length] = node;
}
if (node.nodeType === 1) {
ret = ret.concat( getAllComments(node) );
}
} while( node = node.nextSibling );
return ret;
},
cache = [0],
expando = 'data' + +new Date(),
data = function(node) {
var cacheIndex = node[expando],
nextCacheIndex = cache.length;
if(!cacheIndex) {
cacheIndex = node[expando] = nextCacheIndex;
cache[cacheIndex] = {};
}
return cache[cacheIndex];
};
return function(context) {
context = context || document.documentElement;
if ( data(context) && data(context).commentJSON ) {
return data(context).commentJSON;
}
var comments = getAllComments(context),
len = comments.length,
comment, cData;
while (len--) {
comment = comments[len];
cData = comment.data.replace(/\n|\r\n/g, '');
if ( /^\s*?\{.+\}\s*?$/.test(cData) ) {
try {
data(comment.parentNode).commentJSON =
(new Function('return ' + cData + ';'))();
} catch(e) {}
}
}
return data(context).commentJSON || true;
};
})();
You can create any attribute if you specify a schema for your page.
For example:
Addthis
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:addthis="http://www.addthis.com/help/api-spec">
...
<a addthis:title="" addthis:url="" ...>
Facebook (even tags)
<html xmlns:og="http://opengraphprotocol.org/schema/" xmlns:fb="http://www.facebook.com/2008/fbml">
...
<fb:like href="http://developers.facebook.com/" width="450" height="80"/>
The easiest way to avoid use of custom attributes is to use existing attributes.
use meaningful, relevant class names.
For example, do something like: type='book' and type='cd',
to represent books and cds. Classes are much better for representing what something IS.
e.g. class='book'
I have used custom attributes in the past, but honestly, there really isn't a need to for them if you make use of existing attributes in a semantically meaningful way.
To give a more concrete example, let's say you have a site giving links to different kinds of stores. You could use the following:
<a href='wherever.html' id='bookstore12' class='book store'>Molly's books</a>
<a href='whereverelse.html' id='cdstore3' class='cd store'>James' Music</a>
css styling could use classes like:
.store { }
.cd.store { }
.book.store { }
In the above example we see that both are links to stores (as opposed to the other unrelated links on the site) and one is a cd store, and the other is a book store.
Embed the data in the dom and use metadata for jQuery.
All the good plug-ins support the metadata plugin(allowing per tag options).
It also allows infinitely complex data/data structures, as well as key-value pairs.
<li class="someclass {'some': 'random,'json':'data'} anotherclass">...</li>
OR
<li class="someclass" data="{'some':'random', 'json': 'data'}">...</li>
OR
<li class="someclass"><script type="data">{"some":"random","json":"data"}</script> ...</li>
Then get the data like so:
var data = $('li.someclass').metadata();
if ( data.some && data.some == 'random' )
alert('It Worked!');
I see no problem in using existing XHTML features without breaking anything or extending your namespace. Let's take a look at a small example:
<div id="some_content">
<p>Hi!</p>
</div>
How to add additional information to some_content without additional attributes? What about adding another tag like the following?
<div id="some_content">
<div id="some_content_extended" class="hidden"><p>Some alternative content.</p></div>
<p>Hi!</p>
</div>
It keeps the relation via a well defined id/extension "_extended" of your choice and by its position in the hierarchy. I often use this approach together with jQuery and without actually using Ajax like techniques.
Nay. Try something like this instead:
<div id="foo"/>
<script type="text/javascript">
document.getElementById('foo').myProperty = 'W00 H00! I can add JS properties to DOM nodes without using custom attributes!';
</script>
I'm not doing using custom attributes, because I'm outputing XHTML, because I want the data to be machine-readable by 3rd-party software (although, I could extend the XHTML schema if I wanted to).
As an alternative to custom attributes, mostly I'm finding the id and class attributes (e.g. as mentioned in other answers) sufficient.
Also, consider this:
If the extra data is to be human-readable as well as machine-readable, then it needs to be encoded using (visible) HTML tags and text instead of as custom attributes.
If it doesn't need to be human readable, then perhaps it can be encoded using invisible HTML tags and text.
Some people make an exception: they allow custom attributes, added to the DOM by Javascript on the client side at run-time. They reckon this is OK: because the custom attributes are only added to the DOM at run-time, the HTML contains no custom attributes.
We've made a web-based editor that understands a subset of HTML - a very strict subset (that understood nearly universally by mail clients). We need to express things like <td width="#INSWIDTH_42#"> in the database, but we can't have that in the DOM, otherwise the browser where the editor runs, freaks out (or is more likely to freak out than it is likely to freak out over custom attributes). We wanted drag-and-drop, so putting it purely in the DOM was out, as was jquery's .data() (the extra data didn't get copied properly). We probably also needed the extra data to come along for the ride in .html(). In the end we settled on using <td width="1234" rs-width="#INSWIDTH_42#"> during the editing process, and then when we POST it all, we remove width and do a regex search-and-destroy s/rs-width=/width=/g.
At first the guy writing most of this was the validation-nazi on this issue and tried everything to avoid our custom attribute, but in the end acquiesced when nothing else seemed to work for ALL our requirements. It helped when he realized that the custom attribute would never appear in an email We did consider encoding our extra data in class, but decided that would be the greater of two evils.
Personally, I prefer to have things clean and passing validators etc., but as a company employee I have to remember that my primary responsibility is advancing the company's cause (making as much money as quickly as possible), not that of my egotistical desire for technical purity. Tools should work for us; not us for them.
I know people are against it, but I came up with a super short solution for this. If you want to use a custom attribute like "mine" so for example:
Test
Then you can run this code to get an object back just like jquery.data() does.
var custom_props = {} ;
$.each($(".selector")[0].attributes, function(i,x) {
if (this.specified && x.name.indexOf("mine-") !== -1)
self.new_settings[x.name.replace("modal-","")] = x.value;
});
For complex web apps, I drop custom attributes all over the place.
For more public facing pages I use the "rel" attribute and dump all my data there in JSON and then decode it with MooTools or jQuery:
<a rel="{color:red, awesome:true, food: tacos}">blah</a>
I'm trying to stick with HTML 5 data attribute lately just to "prepare", but it hasn't come naturally yet.
Spec: Create an ASP.NET TextBox control which dynamically auto-formats its text as a number, according to properties "DecimalSeparator" and "ThousandsSeparator", using JavaScript.
One way to transfer these properties from the control to JavaScript is to have the control render out custom properties:
<input type="text" id="" decimalseparator="." thousandsseparator="," />
Custom properties are easily accessible by JavaScript. And whilst a page using elements with custom properties won't validate, the rendering of that page won't be affected.
I only use this approach when I want to associate simple types like strings and integers to HTML elements for use with JavaScript. If I want to make HTML elements easier to identify, I'll make use of the class and id properties.
I use custom fields all the time for example <a i="" .... Then reference to i with jquery. Invalid html , yes. It works well, yes.
Contrary to answers which say custom attributes won't validate:
Custom attributes will validate.
So will custom tags, as long as the custom tags are lowercase and hyphenated.
Try this in any validator. It will validate.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Custom Test</title>
</head>
<body>
<dog-cat PIANO="yellow">test</dog-cat>
</body>
</html>
Some validators:
https://appdevtools.com/html-validator
https://www.freeformatter.com/html-validator.html
https://validator.w3.org/nu/
The question is: Is it safe? Will it break later?
Custom Tags
No hyphenated tags exist. I believe that W3C will never use a hyphenated tag. And if they did, as long as you use an uncommon prefix, you'll never see a conflict. Eg.<johny-mytag>.
Custom Attributes
There are hyphenated HTML attributes. But the HTML spec promises never to use an attribute starting with data-. So data-myattrib is guaranteed to be safe. However, i believe that W3C will never introduce any attribute that starts with johny-. As long as your prefix is unusual, you'll never see a conflict.
Custom attributes, in my humble opinion, should not be used as they do not validate. Alternative to that, you can define many classes for a single element like:
<div class='class1 class2 class3'>
Lorem ipsum
</div>
Related
So, I have some code that should do four things:
remove the ".mp4" extension from every title
change my video category
put the same description in all of the videos
put the same keywords in all of the videos
Note: All of this would be done on the YouTube upload page. I'm using Greasemonkey in Mozilla Firefox.
I wrote this, but my question is: how do I change the HTML title in the actual HTML page to the new title (which is a Javascript variable)?
This is my code:
function remove_mp4()
{
var title = document.getElementsByName("title").value;
var new_title = title.replace(title.match(".mp4"), "");
}
function add_description()
{
var description = document.getElementsByName("description").value;
var new_description = "Subscribe."
}
function add_keywords()
{
var keywords = document.getElementsByName("keywords").value;
var new_keywords = prompt("Enter keywords.", "");
}
function change_category()
{
var category = document.getElementsByName("category").value;
var new_category = "<option value="27">Education</option>"
}
remove_mp4();
add_description();
add_keywords();
change_category();
Note: If you see any mistakes in the JavaScript code, please let me know.
Note 2: If you wonder why I stored the current HTML values in variables, that's because I think I will have to use them in order to replace HTML values (I may be wrong).
A lot of things have been covered already, but still i would like to remind you that if you are looking for cross browser compatibility innerHTML won't be enough, as you may need innerText too or textContent to tackle some old versions of IE or even using some other way to modify the content of an element.
As a side note innerHTML is considered from a great majority of people as deprecated though some others still use it. (i'm not here to debate about is it good or not to use it but this is just a little remark for you to checkabout)
Regarding remarks, i would suggest minimizing the number of functions you create by creating some more generic versions for editing or adding purposes, eg you could do the following :
/*
* #param $affectedElements the collection of elements to be changed
* #param $attribute here means the attribute to be added to each of those elements
* #param $attributeValue the value of that attribute
*/
function add($affectedElements, $attribute, $attributeValue){
for(int i=0; i<$affectedElements.length; i++){
($affectedElements[i]).setAttribute($attribute, $attributeValue);
}
}
If you use a global function to do the work for you, not only your coce is gonna be easier to maintain but also you'll avoid fetching for elements in the DOM many many times, which will considerably make your script run faster. For example, in your previous code you fetch the DOM for a set of specific elements before you can add a value to them, in other words everytime your function is executed you'll have to go through the whole DOM to retrieve your elements, while if you just fetch your elements once then store in a var and just pass them to a function that's focusing on adding or changing only, you're clearly avoiding some repetitive tasks to be done.
Concerning the last function i think code is still incomplete, but i would suggest you use the built in methods for manipulating HTMLOption stuff, if i remember well, using plain JavaScript you'll find yourself typing this :
var category = document.getElem.... . options[put-index-here];
//JavaScript also lets you create <option> elements with the Option() constructor
Anyway, my point is that you would better use JavaScript's available methods to do the work instead of relying on innerHTML fpr anything you may need, i know innerHTML is the simplest and fastest way to get your work done, but if i can say it's like if you built a whole HTML page using and tags only instead of using various semantic tags that would help make everything clearer.
As a last point for future use, if you're interested by jQuery, this will give you a different way to manipulate your DOM through CSS selectors in a much more advanced way than plain JavaScript can do.
you can check out this link too :
replacement for innerHTML
I assume that your question is only about the title changing, and not about the rest; also, I assume you mean changing all elements in the document that have "title" as name attribute, and not the document title.
In that case, you could indeed use document.getElementsByName("title").
To handle the name="title" elements, you could do:
titleElems=document.getElementsByName("title");
for(i=0;i<titleElems.length;i++){
titleInner=titleElems[i].innerHTML;
titleElems[i].innerHTML=titleInner.replace(titleInner.match(".mp4"), "");
}
For the name="description" element, use this: (assuming there's only one name="description" element on the page, or you want the first one)
document.getElementsByName("description")[0].value="Subscribe.";
I wasn't really sure about the keywords (I haven't got a YouTube page in front of me right now), so this assumes it's a text field/area just like the description:
document.getElementsByName("keywords")[0].value=prompt("Please enter keywords:","");
Again, based on your question which just sets the .value of the category thingy:
document.getElementsByName("description")[0].value="<option value='27'>Education</option>";
At the last one, though, note that I changed the "27" into '27': you can't put double quotes inside a double-quoted string assuming they're handled just like any other character :)
Did this help a little more? :)
Sry, but your question is not quite clear. What exactly is your HTML title that you are referring to?
If it's an element that you wish to modify, use this :
element.setAttribute('title', 'new-title-here');
If you want to modify the window title (shown in the browser tab), you can do the following :
document.title = "the new title";
You've reading elements from .value property, so you should write back it too:
document.getElementsByName("title").value = new_title
If you are refering to changing text content in an element called title try using innerHTML
var title = document.getElementsByName("title").value;
document.getElementsByName("title").innerHTML = title.replace(title.match(".mp4"), "");
source: https://developer.mozilla.org/en-US/docs/DOM/element.innerHTML
The <title> element is an invisible one, it is only displayed indirectly - in the window or tab title. This means that you want to change whatever is displayed in the window/tab title and not the HTML code itself. You can do this by changing the document.title property:
function remove_mp4()
{
document.title = document.title.replace(title.match(".mp4"), "");
}
Pretty simple question that I couldn't find an answer to, maybe because it's a non-issue, but I'm wondering if there is a difference between creating an HTML object using Javascript or using a string to build an element. Like, is it a better practice to declare any HTML elements in JS as JS objects or as strings and let the browser/library/etc parse them? For example:
jQuery('<div />', {'class': 'example'});
vs
jQuery('<div class="example></div>');
(Just using jQuery as an example, but same question applies for vanilla JS as well.)
It seems like a non-issue to me but I'm no JS expert, and I want to make sure I'm doing it right. Thanks in advance!
They're both "correct". And both are useful at different times for different purposes.
For instance, in terms of page-speed, these days it's faster to just do something like:
document.body.innerHTML = "<header>....big string o' html text</footer>";
The browser will spit it out in an instant.
As a matter of safety, when dealing with user-input, it's safer to build elements, attach them to a documentFragment and then append them to the DOM (or replace a DOM node with your new version, or whatever).
Consider:
var userPost = "My name is Bob.<script src=\"//bad-place.com/awful-things.js\"></script>",
paragraph = "<p>" + userPost + "</p>";
commentList.innerHTML += paragraph;
Versus:
var userPost = "My name is Bob.<script src=\"//bad-place.com/awful-things.js\"></script>",
paragraph = document.createElement("p");
paragraph.appendChild( document.createTextNode(userPost) );
commentList.appendChild(paragraph);
One does bad things and one doesn't.
Of course, you don't have to create textNodes, you could use innerText or textContent or whatever (the browser will create the text node on its own).
But it's always important to consider what you're sharing and how.
If it's coming from anywhere other than a place you trust (which should be approximately nowhere, unless you're serving static pages, in which case, why are you building html?), then you should keep injection in mind -- only the things you WANT to be injected should be.
Either can be preferable depending on your particular scenario—ie, if everything is hard-coded, option 2 is probably better, as #camus said.
One limitation with the first option though, is that this
$("<div data-foo='X' />", { 'class': 'example' });
will not work. That overload expects a naked tag as the first parameter with no attributes at all.
This was reported here
1/ is better if your attribubes depends on variables set before calling the $ function , dont have to concatenate strings and variables. Aside from that fact ,since you can do both , and it's just some js code somebody else wrote , not a C++ DOM API hardcoded in the browser...
It is very often I come across a situation in which I want to modify, or even insert whole blocks of HTML into a page using JavaScript. Usually it also involves changing several parts of the HTML dynamically depending on certain parameters.
However, it can make for messy/unreadable code, and it just doesn't seem right to have these little snippets of HTML in my JavaScript code, dammit.
So, what are some of your techniques to avoid mixing HTML and JavaScript?
The Dojo toolkit has a quite useful system to deal with HTML fragments/templates. Let's say the HTML snippet mycode/mysnippet.tpl.html is something like the following
<div>
<span dojoAttachPoint="foo"></span>
</div>
Notice the dojoAttachPoint attribute. You can then make a widget mycode/mysnippet.js using the HTML snippet as its template:
dojo.declare("mycode.mysnippet", [dijit._Widget, dijit._Templated], {
templateString: dojo.cache("mycode", "mysnippet.tpl.html"),
construct: function(bar){
this.bar = bar;
},
buildRendering: function() {
this.inherited(arguments);
this.foo.innerHTML = this.bar;
}
});
The HTML elements given attach point attributes will become class members in the widget code. You can then use the templated widget like so:
new mycode.mysnippet("A cup of tea would restore my normality.").placeAt(someOtherDomElement);
A nice feature is that if you use dojo.cache and Dojo's build system, it will insert the HTML template text into the javascript code, so that the client doesn't have to make a separate request.
This may of course be way too bloated for your use case, but I find it quite useful - and since you asked for techniques, there's mine. Sitepoint has a nice article on it too.
There are many possible techniques. Perhaps the most obvious is to have all elements on the page but have them hidden - then your JS can simply unhide them/show them as required. This may not be possible though for certain situations. What if you need to add a number (unspecified) of duplicate elements (or groups of elements)? Then perhaps have the elements in question hidden and using something like jQuery's clone function insert them as required into the DOM.
Alternatively if you really have to build HTML on the fly then definitely make your own class to handle it so you don't have snippets scattered through your code. You could employ jQuery literal creators to help do this.
I'm not sure if it qualifies as a "technique", but I generally tend to avoid constructing blocks of HTML in JavaScript by simply loading the relevant blocks from the back-end via AJAX and using JavaScript to swap them in and out/place them as required. (i.e.: None of the low-level text shuffling is done in JavaScript - just the DOM manipulation.)
Whilst you of course need to allow for this during the design of the back-end architecture, I can't help but think to leads to a much cleaner set up.
Sometimes I utilise a custom method to return a node structure based on provided JSON argument(s), and add that return value to the DOM as required. It ain't accessible once JS is unavailable like some backend solutions could be.
After reading some of the responses I managed to come up with my own solution using Python/Django and jQuery.
I have the HTML snippet as a Django template:
<div class="marker_info">
<p> _info_ </p>
more info...
</div>
In the view, I use the Django method render_to_string to load the templates as strings stored in a dictionary:
snippets = { 'marker_info': render_to_string('templates/marker_info_snippet.html')}
The good part about this is I can still use the template tags, for example, the url function. I use simplejson to dump it as JSON and pass it into the full template. I still wanted to dynamically replace strings in the JavaScript code, so I wrote a function to replace words surrounded by underscores with my own variables:
function render_snippet(snippet, dict) {
for (var key in dict)
{
var regex = new RegExp('_' + key + '_', 'gi');
snippet = snippet.replace(regex, dict[key]);
}
return snippet;
}
For example in javascript code running on the page we have something like:
var data = '<html>\n <body>\n I want this text ...\n </body>\n</html>';
I'd like to use and at least know if its possible to get the text in the body of that html string without throwing the whole html string into the DOM and selecting from there.
First, it's a string:
var arbitrary = '<html><body>\nSomething<p>This</p>...</body></html>';
Now jQuery turns it into an unattached DOM fragment, applying its internal .clean() method to strip away things like the extra <html>, <body>, etc.
var $frag = $( arbitrary );
You can manipulate this with jQuery functions, even if it's still a fragment:
alert( $frag.filter('p').get() ); // says "<p>This</p>"
Or of course just get the text content as in your question:
alert( $frag.text() ); // includes "This" in my contrived example
// along with line breaks and other text, etc
You can also later attach the fragment to the DOM:
$('div#something_real').append( $frag );
Where possible, it's often a good strategy to do complicated manipulation on fragments while they're unattached, and then slip them into the "real" page when you're done.
The correct answer to this question, in this exact phrasing, is NO.
If you write something like var a = $("<div>test</div>"), jQuery will add that div to the DOM, and then construct a jQuery object around it.
If you want to do without bothering the DOM, you will have to parse it yourself. Regular expressions are your friend.
It would be easiest, I think, to put that into the DOM and get it from there, then remove it from the DOM again.
Jquery itself is full of tricks like this. It's adding all sorts off stuff into the DOM all the time, including when you build something using $('<p>some html</p>'). So if you went down that road you'd still effectively be placing stuff into the DOM then removing it again, temporarily, except that it'd be Jquery doing it.
John Resig (jQuery author) created a pure JS HTML parser that you might find useful. An example from that page:
var dom = HTMLtoDOM("<p>Data: <input disabled>");
dom.getElementsByTagName("body").length == 1
dom.getElementsByTagName("p").length == 1
Buuuut... This question contains a constraint that I think you need to be more critical of. Rather than working around a hard-coded HTML string in a JS variable, can you not reconsider why it's that way in the first place? WHAT is that hard-coded string used for?
If it's just sitting there in the script, re-write it as a proper object.
If it's the response from an AJAX call, there is a perfectly good jQuery AJAX API already there. (Added: although jQuery just returns it as a string without any ability to parse it, so I guess you're back to square one there.)
Before throwing it in the DOM that is just a plain string.
You can sure use REGEX.
Hi I would like to do dom selection and manipulation out of the dom.
The goal is to build my widget out of the dom and to insert it in the dom only once it is ready.
My issue is that getElementById is not supported on a document fragment. I also tried createElement and cloneNode, but it does not work either.
I am trying to do that in plain js. I am used to do this with jQuery which handles it nicely. I tried to find the trick in jQuery source, but no success so far...
Olivier
I have done something similar, but not sure if it will meet your needs.
Create a "holding area" such as a plain <span id="spanReserve"></span> or <td id="cellReserve"></td>. Then you can do something like this in JS function:
var holdingArea = document.getElementById('spanReserve');
holdingArea.innerHTML = widgetHTMLValue;
jQuery will try to use getElementById first, and if that doesn't work, it'll then search all the DOM elements using getAttribute("id") until it finds the one you need.
For instance, if you built the following DOM structure that isn't attached to the document and it was assigned to the javascript var widget:
<div id="widget">
<p><strong id="target">Hello</strong>, world!</p>
</div>
You could then do the following:
var target;
// Flatten all child elements in the div
all_elements = widget.getElementsByTagName("*");
for(i=0; i < all_elements.length; i++){
if(all_widget_elements[i].getAttribute("id") === "target"){
target = all_widget_elements[i];
break;
}
}
target.innerHTML = "Goodbye";
If you need more than just searching by ID, I'd suggest installing Sizzle rather than duplicating the Sizzle functionality. Assuming you have the ability to install another library.
Hope this helps!
EDIT:
what about something simple along these lines:
DocumentFragment.prototype.getElementById = function(id) {
for(n in this.childNodes){
if(id == n.id){
return n;
}
}
return null;
}
Why not just use jQuery or the selection API in whatever other lib youre using? AFAIK all the major libs support selection on fragments.
If you wan tto skip a larger lib like jQ/Prototype/Dojo/etc.. then you could jsut use Sizzle - its the selector engine that powers jQ and Dojo and its offered as a standalone. If thats out of the question as well then i suppose you could dive in to the Sizzle source and see whats going on. All in all though it seems like alot of effort to avoid a few 100k with the added probaility that the code you come up with is going to be slower runtime wise than all the work pulled into Sizzle or another open source library.
http://sizzlejs.com/
Oh also... i think (guessing) jQ's trick is that elements are not out of the DOM. I could be wrong but i think when you do something like:
$('<div></div>');
Its actually in the DOM document its just not part of the body/head nodes. Could be totally wrong about that though, its just a guess.
So you got me curious haha. I took a look at sizzle.. than answer is - its not using DOM methods. It seems using an algorithm that compares the various DOMNode properties mapped to types of selectors - unless im missing something... which is entirely possible :-)
However as noted below in comments it seems Sizzle DOES NOT work on DocumentFragments... So back to square one :-)
Modern browsers ( read: not IE ) have the querySelector method in Element API. You can use that to get and element by id within a DocumentFragment.
jQuery uses sizzle.js
What it does on DocumentFragments is: deeply loop through all the elements in the fragment checking if an element's attribute( in your case 'id' ) is the one you're looking for. To my knowledge, sizzle.js uses querySelector too, if available, to speed things up.
If you're looking for cross browser compatibility, which you probably are, you will need to write your own method, or check for the querySelector method.
It sounds like you are doing to right things. Not sure why it is not working out.
// if it is an existing element
var node = document.getElementById("footer").cloneNode(true);
// or if it is a new element use
// document.createElement("div");
// Here you would do manipulation of the element, setAttribute, add children, etc.
node.childNodes[1].childNodes[1].setAttribute("style", "color:#F00; font-size:128px");
document.documentElement.appendChild(node)
You really have two tools to work with, html() and using the normal jQuery manipulation operators on an XML document and then insert it in the DOM.
To create a widget, you can use html():
$('#target').html('<div><span>arbitrarily complex JS</span><input type="text" /></div>');
I assume that's not what you want. Therefore, look at the additional behaviors of the jQuery selector: when passed a second parameter, it can be its own XML fragment, and manipulation can happen on those documents. eg.
$('<div />').append('<span>').find('span').text('arbitrarily complex JS'). etc.
All the operators like append, appendTo, wrap, etc. can work on fragments like this, and then they can be inserted into the DOM.
A word of caution, though: jQuery uses the browser's native functions to manipulate this (as far as I can tell), so you do get different behaviors on different browsers. Make sure to well formed XML. I've even had it reject improperly formed HTML fragments. Worst case, though, go back and use string concatenation and the html() method.