views:

92

answers:

4

I'm building a site that is going to consist of components. A component defined as a particular set of HTML and CSS and jQuery. Each page of the site will consist of many components.

Per best practices, we're putting our javascript block at the bottom of the page. We load the needed .js files, and then I'm planning on calling the functions needed:

doThisThing();
doThatThing();

Let's say I have Component X. I want to call a function whenever that component appears on the rendered page. From a jQuery perspective, what would be the ideal way to handle this? Some options:

1) Always call the function regardless of whether the component is on the page or not:

$('.componentX').doYourThing()

This is easy, as we can just have one universal block of jQuery function calls. But there's a slight performance hit as it's searching the DOM looking for something that may not be there.

2) Attach the call to the component itself:

<div id="componentX">my component</div>
<script>$('.componentX').doYourThing()</script>

This is nice as it self contains the markup and .js calls in the same component. Drawbacks?

3) Integrate our component architecture with the back end system to allow the instantiation of components in the .js block. In otherwords, it'd check to see if the component is placed on the page temlate and, if so, will add the js function calls it depends on to the main script block.

4) other options I should consider?

UPDATE:

Based on kemp's answer, I thought I should clarify a bit. All of our jQuery functions will be wrapped up into one large compressed .js file, so in term of server hits, it's all the same. I'm more interested in how to best handle all the individual function calls for each component on the page in the context of individual page templates.

For instance, component X might be used on 90% of all pages. As such, calling the jquery function for those other 10% of pages doesn't seem like a big deal.

However, component Y might only be used on 5% of all the pages. I probably don't want to call the jquery function on each and every page as 95% of the time, it'd be unecessary.

A further scenario that might further complicate things: component Z might be used once on 100% of all pages, but twice on 5% of the pages.

A: 

Personally I would put all the code in one .js file (unless you have some very specific tasks done only on a few pages not often loaded), this way it can be cached once with a single request. I believe the overhead of multiple requests is greater than a few more DOM scans (which are done by the client).

Option #2 is against one of the main principles of jQuery, which is separating the javascript code from the markup, so I'd never go down that path.

kemp
Ah, to clarify, all of the actual .js *will* be in one file (and compressed). My question was more along the lines of the actual function calls and how to associate them with a particular element on the page when that particular element may or may not exist universally site-wide.
DA
+1  A: 

Depending on the size of the project, I would go with option #1 because of its simplicity, or option #3 because it is proper.

With #1, if you setup your selectors properly, the performance impact will probably be insignificant. Id based selectors are the best (#elementid), then element.classname (just .classname is quite slow in comparison).

With #3, each component needs to know which JS file is required for its functionality. When the component is defined on a page, that JS file must be added to the <head> of the page. Without knowing your server side language and framework (if any), it is hard to say more, but if the components are represented via code on the server in any way, they should have a constructor or initialization routine, and within that code is where you'd place the logic to modify the page's <head>, or some collection that is later read from to construct the page's <head>.

I don't like #2 because you'll have JavaScript all over the page then. That seems less than ideal.

CalebD
+1  A: 

you can go for a hybrid solution, compile and compress your js file and call functions inline let's say we will use 2 different functions heres' example:

var DA = {
    animateStuff:function(element){
        $(element).animate({height:500},normal);
        $(element).doSomethingElse();
    },
    doAnotherStuff:function(element){
        $(element).doOtherThings();
    }
};

pack your js with jquery lib and load it in <head> section. then,

in html part:

<div id="componentX">my component</div>
<script>DA.animateStuff('#componentX');</script>

<div class="componentY">my component</div>
<script>DA.doAnotherStuff('.componentY');</script>

in this way your html will be cleaner, js file will be cleaner, you won't wait dom to be loaded for invoking your functions. as soon as <script> tag loaded your function will be working. you can pass other options to your function as much as you want.

for instance, you may decide to change your DA.animateStuff function later to this:

animateStuff:function(element, desiredHeight){
                if(!desiredHeight){
                   var desiredHeight = 500
                }
            $(element).animate({ height: desiredHeight },normal);
            $(element).doSomethingElse();
        },

and you can change html like:

<div id="componentX">my component</div>
<script>DA.animateStuff('#componentX',900);</script>

in this way you can define height of element when calling your function. if you don't define it'll be 500.

hope this was helpful. cheers

ilhan negis
A: 

Personally, though I know it's messy and maybe not ideal practice, if you are worried about overhead, I would go with option #2, modified.

Each of your components are assigned an ID as well, I assume? If you do $('#componentX1').doSomething() each time you output the component, then you will have the least overhead, as the DOM is not being scanned anywhere near as heavily as it would be if you were accessing the components via class name. See http://geekswithblogs.net/renso/archive/2009/07/14/jquery-selector-efficiencycost-impact.aspx.

Another idea -- I'm not sure how your whole templating system works either, but perhaps you could store the ID of each component X in a global variable, and then loop through and print out the .doSomething() javascript at the bottom of the template for each one.

jessica