For example, does $('#f').load('http://foobar.com #content'); keep or strip out inline JavaScript such as onclick="..."?
It throws away the script tags and does not execute the scripts when you use ".load()" in that form - with a selector attached to the URL like that.
See this jQuery bug report for more information.
When you use ".load()" with just a URL:
$('#f').load('http://foobar.com', function () { ... });
then it does run the scripts, though it still does strip them out. I think that the rationale for removing the scripts is that when manipulating the DOM by grabbing content and moving it around or replicating it, you generally don't want any stray script blocks to run again, but I'm not a jQuery contributor so I don't know for sure.
edit — Re-reading your question through my morning pre-caffeine haze I see that you're asking specifically about inline JavaScript in element attributes, like "onfoo" event handlers. Those are perfectly safe, as far as I know, no matter what sort of DOM wrangling you ask jQuery to do (other than explicitly affecting the attributes of course). What I wrote above pertains to embedded <script> tags in the HTML markup.
Related
I'm looking to inject HTML via JavaScript into a page at work.
What I'd like to know is if injecting a re-write of the page is more or less efficient than injecting snippets throughout the page with methods like getElementById().
For example:
document.getElementById("Example").innerHTML = '<h2 id="Example" name="Example">Text</H2>'
document.getElementsByClassName("Example").innerHTML = '<H1>Test</H1>'
...etc. Is this more efficient/effective than simply injecting my own version of the entire page's HTML start to finish?
Edit: Per Lix's comment, I should clarify that I likely will be injecting a large amount of content into the page, but it will affect no more than a dozen elements at any time.
If your project can manage it, it could be better to create DOM Elements and append them to the tree.
The big problem with efficiency would be that setting .innerHTML property would first remove all the nodes and only then parse the html and append it to the DOM.
It's obvious that you should avoid removing and the re-appending identical elements, so if you're sure the "Example" elements would always remain on the page, your way of setting them seems to be a nice optimazation.
If you want to optimize it even further, you could parse the html you want to append to nodes and have a function that checks which ones should be appended and which one shouldn't. But be aware that accessing the DOM is costly. Read more about the ECMA-DOM bridge.
Edit: In some cases it might be better to let the browser do the html parsing and injecting through innerHTML. It depends on the amount of HTML you're inserting and the amount you're deleting. See #Nelson Menezes's comments about innerHTML vs. append.
Depends on the context. If it was only decoration of existing content, then your proposal would suffice. I'd use jQuery anyway, but that's only my preference.
But when injecting the actual content you have two concerns:
maintainability - Make the structure of your code readable and subject to easy change when you need (and you will need).
accessibility - When javascript is disabled, then no content will be visible at all. You should provide a link to desired content in <noscript/> tag or ensure accessibility to everyone any other way you prefer. That's a minority of internet users at the moment, but for professional webmasters they make it count.
To address both of above concerns I prefer to use ajax to load a whole page, some part or even plaintext into existing element. It makes it readable, 'cause the content is sitting in another file completely separated from the script. And since it's a file, you may redirect to it directly when javascript is disabled. It makes the content accessible to anyone.
For plain javascript you'd have to use XMLHttpRequest object, like here.
With jQuery it's even simpler. Depending on what you need you may use .load, .get or .ajax.
Best practice today is using JQuery Manipulation functions.
Most time you'd use one of this 3 functions :
Replace existing HTML node:
$("div").html("New content");
Append a sibling node:
$("div").append("New content");
Remove a node:
$("div").remove();
I have been struggling with choosing unobtrusive javascript over defining it within the html syntax. I want to convince my self to go the unobtrusive route, but I am having trouble getting past the issues listed below. Can you please help convince me :)
1) When you bind events unobtrusively, there is extra overhead on the client's machine to find that html element, where as when you do stuff, you don't have to iterate the DOM.
2) There is a lag between when events are bound using document.ready() (jquery) and when the page loads. This is more apparent on very large sites.
3) If you bind events (onclick etc) unobtrusively, there is no way of looking at the html code and knowing that there is an event bound to a particular class or id. This can become problematic when updating the markup and not realizing that you may be effecting javascript code. Is there a naming convention when defining css elements which are used to bind javascript events (i have seen ppl use js_className)
4) For a site, there are different pieces of javascript for different pages. For example Header.html contains a nav which triggers javascript events on all pages, where as homepage.html and searchPage.html contains elements that trigger javascript on their respective pages
sudo code example:
header.html
<script src="../myJS.js"></script>
<div>Header</div>
<ul>
<li>nav1</li><li>nav2</li>
</ul>
homepage.html
<#include header.html>
<div class="homepageDiv">some stuff</div>
searchpage.html
<#include header.html>
<div class="searchpageDiv">some other stuff</div>
myJS.js
$(document).ready(function(){
$("ul.li").bind("click",doSomething());
$(".homePageDiv").bind("click",doSomethingElse());
$(".searchPageDiv").bind("click",doSomethingSearchy());
});
In this case when you are on the searchPage it will still try to look for the "homepageDiv" which does not exist and fail. This will not effect the functionality but thats an additional unnecessary traversal. I could break this up into seperate javascript files, but then the browser has to download multiple files, and I can't just serve one file and have it cached for all pages.
What is the best way to use unobtrusive javascript so that I could easily maintain a ( pretty script heavy) website, so another developer is aware of scripts being bound to html elements when they are modifying my code. And serve the code so that the client's browser is not looking for elements which do not exist on a particular page (but may exist on others).
Thanks!
You are confused. Unobtrusive JavaScript is not just about defining event handlers in a program. It's a set of rules for writing JavaScript such that the script doesn't affect the functionality of other JavaScript on the same page. JavaScript is a dynamic language. Anyone can make changes to anything. Thus if two separate scripts on the same page both define a global variable add as follows, the last one to define it will win and affect the functionality of the first script.
// script 1
var add = function (a, b) {
return a + b;
};
// script 2
add = 5;
//script 1 again
add(2, 3); // error - add is a number, not a function
Now, to answer your question directly:
The extra overhead to find an element in JavaScript and attach an event listener to it is not a lot. You can use the new DOM method document.querySelector to find an element quickly and attach an event listener to it (it takes less than 1 ms to find the element).
If you want to attach your event listeners quickly, don't do it when your document content loads. Attach your event listeners at the end of the body section or directly after the part of your HTML code to which you wish to attach the event listener.
I don't see how altering the markup could affect the JavaScript in any manner. If you try to attach an event listener to an element that doesn't exist in JavaScript, it will silently fail or throw an exception. Either way, it really won't affect the functionality of the rest of the page. In addition, a HTML designer really doesn't need to know about the events attached any element. HTML is only supposed to be used for semantic markup; CSS is used for styling; and JavaScript is used for behavior. Don't mix up the three.
God has given us free will. Use it. JavaScript supports conditional execution. There are if statements. See if homePageDiv exists and only then attach an event listener to it.
Try:
$(document).ready(function () {
$("ul.li").bind("click",doSomething());
if (document.querySelector(".homePageDiv")) {
$(".homePageDiv").bind("click",doSomethingElse());
} else {
$(".searchPageDiv").bind("click",doSomethingSearchy());
}
});
Your question had very little to do with unobtrusive JavaScript. It showed a lack of research and understanding. Thus, I'm down voting it. Sorry.
Just because jQuery.ready() executes does not mean that the page is visible to the end user. This is a behaviour defined by browsers and these days there are really 2 events to take into consideration here as mootools puts it DomReady vs Load. When jQuery executes the ready method it's talking about the dom loading loaded however this doesn't mean the page is ready to be viewed by the user, external elements which as pictures and even style sheets etc may still be loading.
Any binding you do, even extremely inefficient ones will bind a lot faster than all the external resources being loaded by the browser so IMHO user should experience no difference between the page being displayed and functionality being made available.
As for finding binding on elements in your DOM. You are really just fearing that things will get lost. This has not really been my actual experience, more often than not in your JS you can check what page you are on and only add javascript for that page (as Aadit mentioned above). After that a quick find operation in your editor should help you find anything if stuff gets lost.
Keep in mind that under true MVC the functionality has to be separate from the presentation layer. This is exactly what OO javascript or unobtrusive javascript is about. You should be able to change your DOM without breaking the functionality of the page. Yes, if you change the css class and or element id on which you bind your JS will break, however the user will have no idea of this and the page will at least appear to work. However if this is a big concern you can use OO-Javascript and put div's or span's as placeholders in your dom and use these as markers to insert functionality or tell you that it exists, you can even use html comments. However, in my experience you know the behavior of your site and hence will always know that there is some JS there.
While I understand most of your concerns about useless traversals, I do think you are nickle and dime'ing it at this point if you are worried about 1 additional traversal. Previous to IE8 it used to be the case that traversing with the tag name and id was a lot faster than my selector but this is no longer true infact browsers have evolved to be much faster when using just the selectors:
$("a#myLink") - slowest.
$("a.myLink") - faster.
$("#Link") - fastest.
$(".myLink") - fastest.
In the link below you can see that as many as 34 thousand operations per second are being performed so I doubt speed is an issue.
You can use firebug to test the speed of each in the case of a very large dom.
In Summary:
a) Don't worry about losing js code there is always ctrl+f
b) There is no lag because dom ready does not mean the page is visible to start with.
Update
Fixed order of speed in operations based on the tests results from here
However keep in mind that performances of IE < 8 are really had if you don't specify the container (this used to be the rule, now it seems to be the exception to the rule).
I have a pretty strange 'assembly' of an HTML file going on, with <script> tags sprinkled throughout in various areas (can't do anything about that). One of these (deeply nested) is an include for jQuery. I need to remove the DOM element that has this jQuery script tag, so I want to make sure that is a safe operation. I'm assuming that since jQuery has already been loaded into memory I should be fine (and everything seems to work ok) but just wanted to verify.
Not relevant to this question but if you need to know why I would want to do such a thing take a look at jQuery table.wrap() causes layout issues
This shouldn't cause problems, except when the script tags are expected to exist in the DOM (for whatever reason).
I've noticed that jQuery can create, and access non-existent/non-standard HTML tags. For example,
$('body').append('<fake></fake>').html('blah');
var foo = $('fake').html(); // foo === 'blah'
Will this break in some kind of validation? Is it a bad idea, or are there times this is useful? The main question is, although it can be done, should it be done?
Thanks in advance!
You can use non-standard HTML tags and most of the browsers should work fine, that's why you can use HTML5 tags in browsers that don't recognize them and all you need to do is tell them how to style them (particularly which tags are display: block). But I wouldn't recommend doing it for two reasons: first it breaks validation, and second you may use some tag that will later get added to HTML and suddenly your page stops working in newer browsers.
The biggest issue I see with this is that if you create a tag that's useful to you, who's to say it won't someday become standard? If that happens it may end up playing a role or get styles that you don't anticipate, breaking your code.
The rules of HTML do say that if manipulated through script the result should be valid both before and after the manipulation.
Validation is a means to an end, so if it works for you in some way, then I wouldn't worry too much about it. That said, I wouldn't do it to "sneak" past validation while using something like facebook's <fb:fan /> element - I'd just suck it up and admit the code wasn't valid.
HTML as such allows you to use any markup you like. Browsers may react differently to unknown tags (and don't they to known ones, too?), but the general bottom line is that they ignore unknown tags and try to render their contents instead.
So technically, nothing is stopping you from using <fake> elements (compare what IE7 would do with an HTML5 page and the new tags defined there). HTML standardization has always been an after-the-fact process. Browser vendors invented tags and at some point the line was drawn and it was called HTMLx.
The real question is, if you positively must do it. And if you care whether the W3C validator likes your document or not. Or if you care whether your fellow programmers like your document or not.
If you can do the same and stay within the standard, it's not worth the hassle.
There's really no reason to do something like this. The better way is to use classes like
<p class = "my_class">
And then do something like
$('p.my_class').html('bah');
Edit:
The main reason that it's bad to use fake tags is because it makes your HTML invalid and could screw up the rendering of your page on certain browsers since they don't know how to treat the tag you've created (though most would treat it as some kind of DIV).
That's the main reason this isn't good, it just breaks standards and leads to confusing code that is difficult to maintain because you have to explain what your custom tags are for.
If you were really determined to use custom tags, you could make your web page a valid XML file and then use XSLT to transform the XML into valid HTML. But in this case, I'd just stick with classes.
I'm retrieving an entire HTML document via AJAX - and that works fine. But I need to extract certain parts of that document and do things with them.
Using a framework (jquery, mootools, etc) is not an option.
The only solution I can think of is to grab the body of the HTML document with a regex (yes, I know, terrible) ie. <body>(.*)</body> put that into the current page's DOM in a hidden element, and work with it from there.
Is there an easier/better way?
Update
I've done some testing, and inserting an entire HTML document into a created element behaves a bit differently across browsers I've tested. For example:
FF3.5: keeps the contents of the HEAD and BODY tags
IE7 / Safari4: Only includes what's between ...
Opera 10.10: Keeps HEAD and everything inside it, Keeps contents of BODY
The behavior of IE7 and Safari are ideal, but different browsers are doing this differently. Since I'm loading a predetermined HTML document I think I'm going to use the regEx to grab what I want and insert it into a DOM element - unless someone has other suggestions.
Elements can exist without being in the page itself. Just dump the HTML into a dummy div.
var wrapper = document.createElement('div');
wrapper.innerHTML = "<ul><li>foo</li><li>bar</li></ul>";
wrapper.getElementsByTagName('li').length; // 2
Given your edits, we run into a sticky situation, since you want getElementById. The matter would probably be easy if you could just create a new virtual document via document.implementation.createDocument, but IE doesn't support that at all.
Using a regex is a messy business, since what if we see something like <body><input value="</body>" /></body>? You could probably just make your regex greedy so that it moves on to the last instance of </body>, but if you do end up running into troubles, a more thorough parsing may be necessary. Even if a full framework isn't an option, you might end up wanting to use something like Sizzle, the core of libraries like jQuery, to look for the element you want. Or, if you're really feeling in a purist sort of mood, you could write the recursive search function yourself - but why take that hit if someone else has already taken it?
var response_el = document.createElement('html'), foo;
response_el.innerHTML = the_html_elements_content;
foo = Sizzle('#foo', response_el);