Tips on using Javascript in Umbraco
Posted on 10 March 2011 by Pete Duncanson
While redesigning our new website I had the task of getting the Blog4Umbraco package to play ball with our existing design. While mashing it around I noticed a bit of a trend for injecting Javascript directly into templates etc. which can limit the usabilty and portability of the code. So I though I would just write some notes/tips on using javascript in your Umbraco website(s).
There will be no end of different ways to achieve some of what I
discus here so feel free to throw your opinions into the ring at
the bottom of the post. When I mention templates I mean XSLT/Razor
or any other flavour you might be using. Anyway on with it.
Don't write out chunks of javascript in your templates
The place for javascript is in your external javascript files
where it can get cached, write out javascript in template and it
has to go down the wire each and every time, not good.
That is not to say that you are not allowed to inject any
javascript into the page, of course you are but ideally it should
be a global javascript object which contains the data that your
external javascript can use when ondomready (aka jQuery.ready)
fires.
You might be thinking that you only want to include the
javascript on the pages it affect, but as long as the javascript is
not overly long (and if it is it should be an external file) your
users will loose very little by you including it sitewide and just
having it activate when it knows it is on the right page.
Remember your users can't cache javascript that is in page so
get it moved to an external and adjust your code a little to work
with this model rather than against it.
Assume jQuery or similar only gets included in the footer
Loading your scripts in the footer greatly increases the speed
that your website renders and is shown to your users. So you should
get in the habit of rendering your code in the footer.
To ease this we have a ContentPlaceHolder called
"CustomFooterJs" in our parent master page template which we can
use to render out any custom JS and <script /> tags into the
footer.
This content place holder is always included after our jQuery
(other javascript frameworks are available) and sitewide setting
files are included.
Now if you assume that you have to wait until the footer before
you can do any special JS then you have to be careful in your
template with what javascript you include. Again similar to point
one you are limited to only writing out javascript objects or
setting variables.
In your external code you can run code on dom ready which can
check for the existance of your javascript objects or dom elements
before running (this stops the code running on pages it shouldn't).
We tend to use the body's id as an inital check followed by a check
for an element we definitely need before running any code that uses
said element. Its safer to assume it won't be their and not run
than to assume it will be and try to run everytime.
// Somewhere in your footer code
$(document).ready( function() {
// Are we on a blog post page?
if ( jQuery("body#blogpost") ) {
// Do something blog post related, beauty of this
// is it can safely be included site wide but will
// only run when it should
}
});
Don't add events directly to elements, use javascript to add
javascript events
Following on from the first two tips this one is a well known
issue but it is still oh so easy to add a quick and dirty onclick
even to your elements within the template itself. If on the other
hand you follow the rule that jQuery et al are not available right
there you will have to add the event after you've rendered out the
HTML.
This is what jQuery and its like are so good at, decorating any
HTML with javascript events. So in your Custom Footer JS place
holder you can add in (or even better in an external file which you
can include in the place holder if need be):
// Somewhere in your footer code
$(document).ready( function() {
jQuery("#myElementId").click( function( elem ) {
// Do something with my elem
});
});
Store handy information as part of your master page
template
We always try to store sitewide important information in the
same page in all pages. That way our javascript only has to look in
one place for it. A great example of this is storing the current
page's node id in a meta tag in the head of your HTML.
<head>
<meta name="pageId" id="pageId" content="<umbraco:Item field='pageId' runat='server' />" />
...
We can use a little jQuery to get this and to have it available
to all our scripts to save us having to try to inject this into our
Javascript.
// Add this code as one of your first lines
// of code in your sitewide js file
$(document).ready( function() {
// Stash this value once where all the
// other scripts can get to it
window.pageId = jQuery.("#pageId").attr("content");
// Other code should always check for the
// existance of the pageId before running if they require it
if ( window.pageId ) {
// do page Id related goodness, Ajax call to
// Base to get comments for this page for instance?
}
});
Again this was handy for re-writing the blog comment form
javascript so that we could pull it out of the XSLT template, move
the javascript into an external file and have it reference this in
page bit of meta data rather than having to write out the
javascript inline.
I've mentioned earlier that you should write out javascript
objects with data in them rather than code it self if you are
looping over content in a template. A nice trick with doing that is
to inject the data into an global array variable, this stops you
having to come up with lots of unique names which can clutter up
the global javascript namespace (or clash with something else).
Something like this:
<!-- Imagine we are looping over a XML dataset in a XSLT for-each...-->
<xsl:for-each select="MyNodes">
<!-- Do other stuff -->
<script type="text/javascript">
// This check will ensure you either create the "mystore"
// variable or re-use it if you are not the first in the
// loop, of course this variable might have been created
// in another template entirely. The lack of a "var" means
// this variable will be global so available to all, nice :)
mystore = typeof( mystore ) != "undefined" ? mystore : [];
// Add in this loops data
mystore.push({
name: '<xsl:value-of select="name" />',
latlng : '<xsl:value-of select="latlng" />',
url : '<xsl:valur-of select="umbraco.library:NiceUrl(pageId)" />'
});
</script>
An alternative is to inject the content in hidden HTML elements
or Form elements, depends on your needs.
Thats about it for this one. Hope its helpful. By all means if
you have a tip share it with us below :)
blog comments powered by