Bootstrap sequence for portable web applications

AID: 9610
  • Status: Published

1450 points

  • ByRoonaan
  • TypeBest Practices
  • Posted on2012-02-11 at 14:11:38
Having worked on larger scale sites, we found out that you are bound to look at more scalable solutions to integrating widgets, code snippets or complete applications and mesh them into functional sites, in any given composition.

To share some of our best practices, possibly the most important thing we changed is to eliminate all body onloads and instead rely on a different loading design, which is extremely friendly when your application is to be included by many webpages.

Because it scales both in case of server-side rendering as well as cases of lazy loading content, we are pleased to share a simplified version of the approach as a best practices with Experts Exchange.

So lets start with some code and take, for example, a simple AJAX driven search application.

<html>
  <head>
    <script type="text/javascript" src="jquery-1.6.2.min.js"></script>
  </head>
  <body>
    <div class="my-search-app">
       <form action="/search">
         <input type="text" name="q" /><input type="submit" value="search" />
       </form>
       <div class="my-search-results"></div>
       <script type="text/javascript" src="my-search-app.js"></script>
     </div>
  </body>
</html>
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:

Select allOpen in new window



In any other, non-portable, application the most sensible JQuery logic to add in my-search-app.js would be:

// Closure
(function(window, document, $) {

  $(document).ready(function() {
     // Capture search form submit and transfor into AJAX request
     $('form').submit(function() {
       // AJAX Logic and stuff
       fnResults = function(data) {
          $('.my-search-results').html('Results ... ');
       }
     });
  });

// End of closure
})(window, document, jQuery);
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:

Select allOpen in new window



This portable approach is more complex but we'll explain later on.

(function(window, document, $) {

  // Generic bootstrap function for each
  // instance of my-search-app
  function init(node) {
     
     // Prevent duplicated execution of
     // the bootstrapping logic
     if (node.isInitialized) {
        return;
     }
     node.isInitialized = true;

     // Store reference to the JQuery wrapped node.
     var $node = $(node);

     // Capture search form submit and transfor into AJAX request
     $node.find('form').submit(function() {
       // AJAX Logic and stuff
       fnResults = function(data) {
          $node.find('.my-search-results').html('Results ... ');
       }
     });
  }

  // When this code executes, trigger the
  // bootstrapping if all instances
  $(document).ready(function() {
     $('.my-search-app').each(init);
  });

})(window, document, jQuery);
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:

Select allOpen in new window



The most important change one notices is that we use the classname of the outer div element to look up the functional scope of the search application and in further code only execute changes within the scope of that application root node. This is the core principle of portable applications and sometimes called the Isolation Ground Rule: Don't change things outside your application scope, even though javascript and browsers allow you to do so.

So nothing exiting just jet, so let's continue. From this point onwards I can include the code anywhere in other pages and it will work as expected, even when we include it multiple times:

<body>
   <div id="my-header-wrapper">
      <div id="my-search-box">
         <div class="my-search-app">
            <form action="/search">
               <input type="text" name="q" /><input type="submit" value="search" />
            </form>
            <div class="my-search-results"></div>
         </div>
       </div>
   </div>

  <div id="my-full-page-search">
    <div class="my-search-app">
      <form action="/search">
        <input type="text" name="q" /><input type="submit" value="search" />
      </form>
      <div class="my-search-results"></div>
    </div>
  </div>

  <script type="text/javascript" src="my-search-app.js"></script>
</body>
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:

Select allOpen in new window



The power of this loading sequence however is shown when you start lazy loading the applications:

<body>
  <div id="my-search-form"></div>

  .. more html ..

  <script type="text/javascript">
  // Lazy load the search box application
  $(document).ready(function() {
     $('#my-search-form').load('my-search-box.html');
  });
  </script>
</body>
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:

Select allOpen in new window



When you scale this up to the size of enterprise applications the design pattern holds and some additional patterns are added:

<body>
  <div class="my-lazy-app" data-src="my-search-box.html"></div>
  <div class="my-lazy-app" data-src="login-app.html"></div>
  <div class="my-lazy-app" data-src="contextual-navigation.html"></div>
  <div class="my-lazy-app" data-src="user-profile.html"></div>
  <div class="my-lazy-app" data-src="social-buttons.html"></div>
  <script type="text/javascript">
   $(document).ready(function() {
     // Load all applications based on their 
     // declarative application src.
     $('.my-lazy-app').each(function() {
        $(this).load($(this).data('src'));
     });
   });
  </script>
</body>
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:

Select allOpen in new window



If you add to the mix that some of the applications, themselves include sub-applications, you can see the increasing benefit to software reuse that is delivered by this design.

In reality the code is far more complex, including cancellable loading events, plugin points and in general a more complete application lifecycle. But as a best practice this is the minimum baseline we used for our increasing number of applications. As indication that this approach works in reality, let's add that in the latest project we currently number 36 applications that have different compositions running throughout the clients legacy site; it's new internet site; it's intranet site; and ramping up to social networks such as Facebook apps.
Asked On
2012-02-11 at 14:11:38ID9610
Tags

Javascript

,

bootstrap

,

web applications

,

portable

,

lazy loading

,

scalability

,

html

Topic

JavaScript

Views
755

Comments

Author Comment

by: Roonaan on 2012-02-19 at 04:59:42ID: 43363

Thanks, I can see the total, but was wondering if there was a breakdown somewhere.

Add your Comment

Please Sign up or Log in to comment on this article.

Join Experts Exchange Today

Gain Access to all our Tech Resources

Get personalized answers

Ask unlimited questions

Access Proven Solutions

Search 3.2 million solutions

Read In-Depth How-To Guides

1000+ articles, demos, & tips

Watch Step by Step Tutorials

Learn direct from top tech pros

And Much More!

Your complete tech resource

See Plans and Pricing

30-day free trial. Register in 60 seconds.

Loading Advertisement...

Top JavaScript Experts

  1. leakim971

    511,289

    Sage

    2,168 points yesterday

    Profile
    Rank: Genius
  2. mplungjan

    291,279

    Guru

    2,800 points yesterday

    Profile
    Rank: Savant
  3. nap0leon

    195,491

    Guru

    0 points yesterday

    Profile
    Rank: Sage
  4. Proculopsis

    182,948

    Guru

    0 points yesterday

    Profile
    Rank: Sage
  5. COBOLdinosaur

    157,309

    Guru

    0 points yesterday

    Profile
    Rank: Genius
  6. chaituu

    130,684

    Master

    0 points yesterday

    Profile
    Rank: Sage
  7. Ray_Paseur

    130,217

    Master

    330 points yesterday

    Profile
    Rank: Savant
  8. tommyBoy

    125,345

    Master

    0 points yesterday

    Profile
    Rank: Genius
  9. StingRaY

    114,318

    Master

    0 points yesterday

    Profile
    Rank: Wizard
  10. DaveBaldwin

    80,081

    Master

    336 points yesterday

    Profile
    Rank: Genius
  11. ansudhindra

    79,054

    Master

    2,000 points yesterday

    Profile
    Rank: Wizard
  12. ChrisStanyon

    62,768

    Master

    800 points yesterday

    Profile
    Rank: Sage
  13. hielo

    61,266

    Master

    0 points yesterday

    Profile
    Rank: Savant
  14. HainKurt

    59,030

    Master

    0 points yesterday

    Profile
    Rank: Genius
  15. BuggyCoder

    54,739

    Master

    0 points yesterday

    Profile
    Rank: Sage
  16. mroonal

    54,339

    Master

    10 points yesterday

    Profile
    Rank: Sage
  17. tagit

    54,093

    Master

    1,600 points yesterday

    Profile
    Rank: Genius
  18. gurvinder372

    52,824

    Master

    10 points yesterday

    Profile
    Rank: Genius
  19. basicinstinct

    52,586

    Master

    0 points yesterday

    Profile
    Rank: Genius
  20. JonNorman

    45,158

    2,200 points yesterday

    Profile
    Rank: Master
  21. Lalit-Chandra

    44,420

    0 points yesterday

    Profile
    Rank: Master
  22. xmediaman

    36,450

    3,800 points yesterday

    Profile
    Rank: Guru
  23. kozaiwaniec

    33,100

    0 points yesterday

    Profile
    Rank: Guru
  24. Kravimir

    32,700

    0 points yesterday

    Profile
    Rank: Genius
  25. designatedinitializer

    32,300

    0 points yesterday

    Profile
    Rank: Master

Hall Of Fame