Saturday, July 14, 2012

A Knockout History.js ajaxify bindingHandler

I've been playing around with balupton's History.js and Ajaxify scripts for my current project. I had tried both a year or so ago and, while they worked well at first I ran into some problems here and there. I'm making a second attempt and so far it's going well.

However, balupon's ajaxify code is run once on the initial page load or the return of the ajax load event so it does not catch template fragments that are loaded or bound after the load completes.

As I am using Knockout extensively with a lot of dynamically loaded content, I wanted extend balupton's ajaxify function to my dynamically loaded content using a knockout bindingHandler:

This is the helper function:


// Ajaxify Helper
$.fn.ajaxify = function(){
    // Prepare
    var $this = $(this);

    // Ajaxify
    $this.find('a:internal:not(.no-ajaxy)').click(function(event){
        // Prepare
 var
     $this = $(this),
     url = $this.attr('href'),
     title = $this.attr('title')||null;

 // Continue as normal for cmd clicks etc
 if ( event.which == 2 || event.metaKey ) { return true; }
            // Ajaxify this link
     History.pushState(null,title,url);
     event.preventDefault();
     return false;
 });

 // Chain
 return $this;
};

And here it is, amd style:


define(['jquery', 'ko'], function($, ko) {
    "use strict";
    ko.bindingHandlers.ajaxify = {
        update: function(element) {
            // Prepare
            var $this = $(element);
            // Ajaxify
            $this.find('a:internal:not(.no-ajaxy)').click(function(event) {
                // Prepare
                var $this = $(this),
                    url = $this.attr('href'),
                    title = $this.attr('title') || null;

                // Continue as normal for cmd clicks etc
                if (event.which == 2 || event.metaKey) {
                    return true;
                }

                // Ajaxify this link
                History.pushState(null, title, url);
                event.preventDefault();
                return false;
            });
        }
    };
});

This assumes you have the other 5000 scripts already on the page (JQuery, History, ScrollTo, Ajaxify, Knockout, Require to name a few) of course. After which usage is simple (well after all that pretty much anything is simple):

<div data-bind="foreach: item, ajaxify: true">
   //any links loaded here will get ajaxified
</a>

Now this works well when I'm loading the content from the ko native template and the html is already on the page. When trying to do this when loading the html from templates, no dice. However, by putting the 'ajaxify' binding on the template element being bound, it worked nicely.

1 comment:

  1. Actual URLs for History.js and the Ajaxify.js gist:

    https://github.com/browserstate/history.js

    https://github.com/browserstate/ajaxify

    ReplyDelete