Oh my god. It's full of code!

Experimental: Progressively enhance links for ajax with bookmarking and back button support!

Hey All,

So this is a bit of an ‘in progress/experimental’ kind of post. I think many of us have run into this dilemma. We want to make an awesome ajax powered website with fast loading pages and neat interface. Problem is ajax content sucks for search engine optimization, can be tricky to get bookmarking to work, and of course the back and forward buttons cause problems too. All this seems like it might make ajax a bad idea for navigation, but it’s just too cool to give up. So how can we resolve all these issues and use the awesome ajax navigation we want to? We address each challenge one by one (or just skip the bottom and copy and paste my full code example. Whatever works for you).

Progressive Enhancement (AKA dealing with shitty browsers or search engine)
My first attempts with Ajax navigation where simply to replace the href attributes of my links with javascript function calls. This really is the most straight forward approach, but the most flawed as well. Anyone who doesn’t have javascript support, or search engines trying to crawl your site won’t be able to follow your links. Your site won’t get indexed, and you’ll be abandoned by the search engine gods. Also, if you are using any kind of CMS (such as site.com from Salesforce as I am) the links created will be standard links. Your website people would have to call on you all the time to change their links, if it’s even possible! The answer to all of these problems is progressive enhancement. Use javascript to transform your regular links into javascript ajax links. This ensures that those people/bots not using javascript can still browse your site in the traditional manner. So for this example, my regular link might look like

<a href='contactUs' title='contactUs' class='ajaxLink'>Contact Us</a>

Pretty simple standard link. However I’ve added a class to it that will easily allow me to select it later with some jQuery magic later on. Now we need some javascript to turn that link from a plain jane href into a sexy ajax link. Something like this oughtta do the trick.

    $('.ajaxLink').each(function(index){
        $(this).attr('href', $(this).attr('href').replace('/','#'));
    });
    
    $('.ajaxLink').bind('click', function() {
            loadLink($(this).attr('href').replace('#','/')) 
    });  

(Yes I know it’s a bit sloppy with the replace statement. With the CMS we are using it’s a flat hierarchy, so I don’t need to worry about multiple slashes in the URL. Also I’m purposely leaving it a little less than maximally elegant to increase readability for my readers. I know I could consolidate the two loops.)

What’s happening here is that we are using jQuery to modify every link that has the ajaxLink class to replace the initial slash (which all my links will have) with a # sign. That # is magical. It’s called a hash mark and it’s original use was to make bookmarkable locations in your document. You click the link with the # you go to that location in the same document designated by the #. The # and it’s content is never sent to the server, it exists entirely client side (not that that really matters right now though). So when a user clicks it, their URL changes in their browser now, but it doesn’t cause a page reload. You hear that? Let me repeat. IT CHANGES THE URL, BUT DOES NOT CAUSE A PAGE RELOAD. That’s important. The second part creates a bound function that when you click our link it’s going to call a function called loadLink which expects to receive a valid URL (relative to the current document) so we need to flip the hash back to being a slash (I guess we could probably leave the slash out and just remove the # but whatever). We now have a system that will leave function links for those without javascript and transform them into ajax links for those who do. Sweet.

Bookmarking and unique page urls (The magic of the hash)
You may ask why even bother with the hash at all if we are just flipping it back to a slash. The reason is since it causes the URL to change, the user now has something they can bookmark. It also gives each page a unique URL with which to access it. As the user is navigating around your site, if they end up at a some buried 3 level deep page but the URL hasn’t changed at all they have no idea where they are really at. They don’t have a bookmarkable link, or one they can share with their friends. Of course the each page does have it’s own unique URL (thats how search engines and non javascript browsers will get to them) but your ajax enabled users won’t know that without the hash. With our function we wrote above, regular links now act as javascript and since they links have a # in front of them, the browser treats them as anchors. The URL changes when the link is clicked, but no page reload is preformed. This is a good thing. But wait, just because the hash is in the URL that doesn’t mean it’s really doing anything yet. If someone bookmarks your page with the hash in it, but you don’t have any handler for it nothing really happens. When our page loads we need to check and see if there is a hash in the URL. If so load the page indicated by it, if not then just load your default page. That functionality looks a bit like this.

$(document).ready(function()
{
          var hashMark = getHash();
          if(hashMark.length > 0)
          {
              loadLink (hashMark);  
          }          
    });    
});

function getHash() 
{
          var hash = window.location.hash;
          return hash.substring(1); // remove #
}

Pretty simple. All you are doing is saying when the document loads, see if there is a hash mark. If so, load the link indicated by it (by passing the hash mark content to the loadLink function). This works great. Now you can have bookmarkable links that actually work. But the back button is still broken….

Dealing with the back button

Man, I love jQuery. Every time I have some crazy issue to deal with, it’s got my back. Like if me and jQuery were in a bar and some big biker dude was trying to hassle me, jQuery would like tap on his shoulder, the biker would turn around and jQuery would just knock like all his teeth out with one right hook. I’d then jQuery a drink and we’d talk about how much mootools sucks (just kidding, I don’t know anything about it). Anyway where I’m going with this is that something that could be really hard to do jQuery makes really easy for us. What we need to do to get the back button to work is to detect when the hash in the URL changes. When a user clicks back or forward using your links the only thing that is going to change is that hash mark content. Nothing gets sent to the server. There is no get/post request going on here. Many hackey approaches are out there from disabled the back button to overriding it’s behavior. Thankfully we aren’t savages. We have an elegant solution. It looks like this.

          $(window).bind('hashchange', function() {
              var hashMark = getHash();
              if(hashMark.length > 0)
              {
                 loadLink (hashMark);  
              } 
          });

Just that easy. A topic that has stumped top web developers for years all wrapped up 7 lines. This just says bind a function to the hashchange function. When it changes, get the hash and pass it to the loadLink function. Boom. Done.

Loading the content (The grand finally)

So we are just about home now. We have progressive enchantments, bookmarking/link sharing ability, and even back/forward functionality. But now we need to actually load the content. Here is one last issue to deal with. Since all of your pages contain all the content/styles/scripts needed to be seen on their own (again for the non ajax users) if you try and load the entire page when you click the link you are going to end up with recursive pages nesting inside each other, duplicate script errors all kinds of crazy shit. So you need to leave the full pages intact for your non ajax users, but still be able to extract just the content you want from it to display on your page. Here we are going to use a little bit of jQuery’s find magic to extract just the content we want.

function loadLink(link)
{
     try
     {
         $("#leftText").html('');
         $('#loader').show();
         
         $.get(link, function(html) {
               $('#loader').hide();
               $("#leftText").html($(html).find("#leftText").html());
         });
     }
    catch(ex)
    {
        console.log(ex);
        $('#loader').hide();
    }
}

So here is whats happening here; the function loadLink expects to receive a valid URL fragment to load. It’s going to blank out my content area (which is called leftText) and then show an ajax loading spinner. jQuery is going to create a get request to get the link and with the result it’s going to extract the content from it’s leftText div, and insert it into this pages leftText div. Since every page is structured basically the same, it works pretty slick. That’s it. You’re done! Of course these scripts need some refining, error handling, edge case handling but I’ll leave that to the reader. The hard shit is done, what do you want me to do your whole job for you? XD Below is the entire script. Enjoy!

$(document).ready(function () {

        markupLinks();

        $(window).bind('hashchange', function () {
            var hashMark = getHash();
            if (hashMark.length > 0) {
                loadLink(hashMark);
            }
        });

        var hashMark = getHash();
        if (hashMark.length > 0) {
            loadLink(hashMark);
        }
});



function markupLinks() {
    $('.ajaxLink').each(function (index) {
        $(this).attr('href', $(this).attr('href').replace('/', '#'));
    });

    $('.ajaxLink').bind('click', function () {
        loadLink($(this).attr('href').replace('#', '/'))
    });
}

function loadLink(link) {
    try {
        $("#leftText").html('');
        $('#loader').show();

        $.get(link, function (html) {
            $('#loader').hide();
            $("#leftText").html($(html).find("#leftText").html());
        });
    } catch (ex) {
        console.log(ex);
        $('#loader').hide();
    }
}

function getHash() {
    var hash = window.location.hash;
    return hash.substring(1); // remove #
}

24 responses

  1. Having Ajax page navigation like you mention has been in my dreams for some time now.

    I always thought the only solution was to have special server functions that send just specific content, in JSON or w/e, and then have JS update the DOM. This enters hard-mode pretty quickly when I start to think about creating a custom CMS thing to manage these endpoints.

    Your solution is well-presented! I love the simplicity, and I will certainly try it out sometime. I just wonder about page load times… That is, when you use the jQuery.get function, will each JS, CSS, and image on the page be re-requested? I always presumed it would, but when I think about it now, I’m not so sure. I believe that loading these resources is the majority of page’s load time.

    Can you comment on the page load time of your solution? How about load time feel?

    July 6, 2012 at 6:37 pm

    • Alex,

      Glad you liked the write up. As for page load times, yes everything gets re-requested, however browser caching should mitigate the load times pretty substantially. Granted it’s not quite as fast as only delivering the required content, but I think it’s an okay compromise between speed and easiness. So far the load times have been quite tolerable, and the lack of page flicker/reload makes it all the sweeter. Throw in a little content loading ajax spinner image and it’s almost fun waiting for the content 😛 Granted if you end up trying this with large complicated pages with tons of content it could slow it down, but for my needs and I imagine many others it should be sufficient.

      July 7, 2012 at 6:30 am

  2. Sweet stuff! Capitalizing on jQuery’s hashChange is total awesomeness — had no idea they exposed that as an event in their API. Nice work.

    July 6, 2012 at 8:30 pm

  3. Pingback: Building a mobile site on Salesforce site.com, with cool menu to mobile list code! « I Write Crappy Code

  4. Thanks for finally talking about >Experimental:
    Progressively enhance links for ajax with bookmarking and
    back button support! I Write Crappy Code <Loved it!

    January 12, 2013 at 8:07 pm

    • Your unicode is leaking. If you are going to write a spam bot at least try and get the charset of your bot working right, otherwise you just look like an idiot, especially when your fail bot malfunctions while posting to a programming blog.

      February 19, 2013 at 6:54 pm

  5. You actually made quite a few wonderful ideas in
    ur posting, “Experimental: Progressively enhance links for ajax with bookmarking and back
    button support! I Write Crappy Code”. I’ll wind up returning to ur webpage soon. Thank you ,Anke

    January 20, 2013 at 8:43 pm

  6. I am regular visitor, how are you everybody? This post posted at this web page is actually fastidious.

    February 2, 2013 at 1:30 am

  7. Have you ever thought about writing an e-book or guest authoring on other sites?
    I have a blog based upon on the same information you discuss and would really like to have
    you share some stories/information. I know my audience would appreciate your work.
    If you are even remotely interested, feel free to send me an email.

    February 5, 2013 at 6:50 pm

    • For some reason I doubt an account with the name best porn tubes really has an interest in my programming blog or it’s content. Idiot.

      February 19, 2013 at 6:53 pm

  8. I loved as much as you will receive carried out
    right here. The sketch is attractive, your authored material stylish.
    nonetheless, you command get bought an shakiness over
    that you wish be delivering the following. unwell unquestionably come more formerly again since exactly the
    same nearly a lot often inside case you shield this hike.

    February 7, 2013 at 9:48 pm

    • One day I hope to really understand what the hell it is you spammers get out of messing with stupid little programming blogs like mine. Do you even understand how little traffic I get? There is literally no benefit of posting this crap on my blog. Could you even bother to attempt to use proper English?

      February 19, 2013 at 6:52 pm

  9. If you want to get much from this piece of writing then you have
    to apply these techniques to your won webpage.

    February 14, 2013 at 9:49 am

    • I seem to be doing fine. Thanks anyway.

      February 19, 2013 at 6:50 pm

  10. Silver Greenback Values
    Rule selection eight: Soon after publicity wash all
    dresses in Scorching Very hot drinking water
    with soap. Then and only then clean by yourself in sizzling h2o.
    Be certainly to scrub down with a perfect clean rag to dislodge any at no cost loaders.
    The faster you do all of this, the more effective.

    States Defaulting – The states are amazingly messed up fiscally now.
    They have significant deficits thanks to
    reduced earnings streams just like the metropolitan areas and
    counties. Their bond curiosity payments are preset fees.
    Their point out pension payments are also preset. They are asking the fed for authorization to file individual bankruptcy.
    The fed has said they are accomplished with extra
    bailouts to the states. You know if they you can ask for authorization they will get it.

    If they get the authorization, then they
    will file bankruptcy. Thousands and thousands of aged retired individuals will reduce their pensions and medical features.

    Go through what took place in Vallejo, Ca.
    The diploma of bullishness by the commercial traders in the U.
    S. debatekings.com forces us to study the markets most
    intently relevant to it in buy to observe the spillover outcome a rally
    in the Greenback would possibly design. The inventory current market has traded opposite the Greenback for
    all but 4 months in the past two yrs. The last time these marketplaces
    traded in the very same direction on a month-to-month basis is August of 2008.
    The up-to-date correlation values of -.29 weekly and -.
    43 regular suggest that for any one% larger the Dollar moves, the S&ampP500 really should slide by.29% and.
    43%, respectively. Because of this, a bullish Dollar outlook will have to be coupled with a bearish equity current market forecast.
    In get to glean alot more showings and presents on your residence, examine applying the value selection merchandising software. Listing a scale of two price tags for a house instead of limiting your self to a single specified price. Look at what cost you would concur to immediately if a purchaser offered to be able to write you a look at. Then think of a lower charge that you would be prepared to bargain upwards from in the hopes of achieving some middle floor of acceptance to both of those you and the customer.
    Going on a extensive vehicle ride? Or perhaps you’re just wanting for a thing to retain the youngsters occupied in the cafe? This is the perfect area to choose up modest cars and trucks, puzzles, coloring textbooks and crayons and other exciting toys. For terribly very little cash flow you can set collectively a stellar “interesting bag” to choose along with you on your excursions!
    Tactic #1) Begin selecting a whole lot more from dollar save products suppliers featuring freight caps and prepaid freight. While you are there aren’t a great deal of wholesalers and distributors still providing this as a component of their product sales software, they do exist. Emphasis your buying on these businesses every time probable. As freight is component of the value-of-goods-offered calculation for most who open up a greenback keep, just take benefit of the chance to pay out modest or no freight and conserve.
    All of your tax dollars likely to aid some unlawful foreigner get amazing benefits, but you do not get aid from chiggers or the chigger’s maddening itch. Isn’t going to that just make you want to go scratch?
    Rule variety 2: Use a solid insect repellent to your apparel. Implement approximately the cuffs, the belt line, up and down your legs. DO NOT use to your pores and skin and for heaven sakes do implement to your children. Most animal feed retail store have pet materials. They quite possibly carry a quality repellent for animals that is substantially much better than designed for individuals at considerably less amount. Just use with care and warning.

    February 19, 2013 at 6:47 pm

    • I’m going to keep this comment here because it is so wonderfully absurd. Honestly, what in the hell is going on here? Did this guy have a stroke or what?

      February 19, 2013 at 6:50 pm

  11. Hi every one, here every one is sharing these kinds of
    experience, therefore it’s pleasant to read this website, and I used to pay a quick visit this weblog daily.

    March 30, 2013 at 6:34 pm

  12. If you would like to improve your experience simply keep visiting this web page and be updated
    with the latest information posted here.

    April 6, 2013 at 2:43 am

  13. It’s very effortless to find out any topic on net as compared to textbooks, as I found this piece of writing at this site.

    April 8, 2013 at 8:59 pm

  14. Hello, I enjoy reading through your article post. I
    wanted to write a little comment to support you.

    July 30, 2013 at 1:38 pm

  15. Write more, thats all I have to say. Literally, it seems as though you relied on
    the video to make your point. You obviously know what youre talking about, why throw away your intelligence on just posting videos to your
    blog when you could be giving us something enlightening to read?

    August 1, 2013 at 6:06 am

  16. All you need to do is to coat the chicken by rolling them over the seasoning mixture.
    And according to my short research, celery stalk contains PHTHALIDE
    which can lower blood pressure, and also it lessens the production of catecholamine (exists if physically and emotionally
    stressed) which causes the imbalance flow of blood by
    restricting or blocking the blood vessels. The final decision to
    use a roasting method to cook the chicken is a good one because
    this type of cooking will allow us to compose the item in one large single batch and place them on sheet pans for the oven.

    August 6, 2013 at 2:57 am

  17. Hmm is anyone else encountering problems with the pictures on this blog loading?
    I’m trying to figure out if its a problem on my end or if it’s the blog.
    Any feed-back would be greatly appreciated.

    August 20, 2013 at 7:38 am

  18. If some one desires to be updated with most
    up-to-date technologies therefore he must be go to see this
    web site and be up to date everyday.

    October 24, 2013 at 3:20 am

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s