Monthly Archives: April 2009

mixin dojo and google api libraries

I’m working in a dojo application and I also need to use some goolge api like feeds, maps and books. Dojo is very versatile adding new components using dojo.require. when all dojo components are loaded dojo.addOnLoad callback is fired.

dojo.require("dojo.io.script");
dojo.require("dojo.data.ItemFileReadStore");
dojo.addOnLoad(function(){
    console.log('all is ready');
});

dojo.require is great. It also alloy us to create nested onLoad callbacks

dojo.require("dojo.io.script");
dojo.require("dojo.data.ItemFileReadStore");

dojo.addOnLoad(function(){  // <------------
    console.log('all is ready1');
    dojo.require("dijit.TitlePane");
    dojo.require("dijit.Dialog");

    dojo.addOnLoad(function(){ // <------------
        console.log('all is ready 2');
     });
});

google API uses his own loader google.load.

google.load("jquery", "1.3.2");
google.load("feeds", "1");
google.setOnLoadCallback(function() {
    console.log('all is ready');
});

If your application uses both libraries you must take care about onLoad callback of dojo and google because they are not the same.
You can create your own dojo widget for loading google api and forget google.setOnLoadCallback but I want to use libraries as standard as I can (without hacking code every time I have a problem). So I prefer to live with both callbacks.

You can try to do something like this:

google.load("dojo", "1.3");
google.load("feeds", "1");

dojo.require("dijit.layout.BorderContainer");
dojo.require("dijit.layout.TabContainer");
dojo.require("dijit.layout.ContentPane");

dojo.addOnLoad(function(){
    // start dojo application
});

This code will work but sometimes will crash. Then you press F5 and all works.
As far as I know you can’t do nested onLoad callbacks with google (it’s a pity), so first you must load google api and load dojo components when google api is ready

So it’s better to use this other version of code:

google.load("dojo", "1.3");
google.load("feeds", "1");
google.setOnLoadCallback(function() {
    dojo.require("dijit.layout.BorderContainer");
    dojo.require("dijit.layout.TabContainer");
    dojo.require("dijit.layout.ContentPane");

    dojo.addOnLoad(function(){
        // start dojo application
    });

});

Speed up page load with asynchronous javascript

JavaScript an important part of or web applications. Normally or web is not usable until js is full loaded. Almost all js framework implements an event to notice when the js is ready (dojo.addOnLoad(); $(function() {});) and the page is usable. The page is usable when js is loaded. Sometimes if you are working with dojo you need all js and maybe is better to create an splash screen until all is loaded. But sometimes your app don’t need all js to be usable. I give you a example: I’ve been working in a project with jQuery. I load jQuery library from google cdn

<script type="text/javascript" src="http://www.google.com/jsapi?key=mygoogleApiKey"></script>
<script type="text/javascript">
    google.load("jquery", "1.3.2");
</script>

jQuery is mandatory. The site doesn’t work without this library.

google.setOnLoadCallback(function() {
    $(function() {
        // application code ...
    });
});

I want to put rss feeds of some blogs on the left bar of the application and I need to do it with js. I’m going to use google’s feed api to do it so:

<script type="text/javascript" src="http://www.google.com/jsapi?key=myGoogleApiKey"></script>
<script type="text/javascript">
    google.load("jquery", "1.3.2");
    google.load("feeds", "1"); // <-------------
</script>

And I call to the js function to populates RSS feed into google’s onready callback (setOnLoadCallback)

google.setOnLoadCallback(function() {
    initFeeds() // <-------------
    $(function() {
        // application code ...
    });
});

This version of code works but it has a problem. All application will not be usable until initFeeds ends. The fedds on the left bar are cool but the user don’t need them to use the application. It’s just a decoration so: why we force user to wait until feeds are loaded? The solution is quite simple. Put a timer to free the main js file and populate feed asynchronously

google.setOnLoadCallback(function() {
    setTimeout(initFeeds, 1000); <-------------
    $(function() {
        // application code ...
    });
});

fetching book cover with google API and dojo

I want to put the cover of one book into my dojo application. I can use amazon Web service but google API has a nice JSONP interface and also google API uses ISBN instead ASIN to fetch book info and for me is easier to know the ISBN (it is in the first page of every book).
I have a previous post explaining how to use use JSONP with javascript, but now I want to do the same in a dojo-way using dojo.io.script.get

dojo.io.script.get({
    url:"http://books.google.com/books?bibkeys=" + isbn + "&jscmd=viewapi",
    callbackParamName: "callback",
    load: dojo.hitch(this, function(booksInfo){googleCallback(booksInfo);})
});

And finally we are going to use booksInfo to to show our flaming cover:

googleCallback: function(booksInfo) {
        var div = dojo.byId('divId');
        div.innerHTML = '';
        var mainDiv = dojo.doc.createElement('div');
        var x = 0;
        for (i in booksInfo) {
            // Create a DIV for each book
            var book = booksInfo[i];
            var thumbnailDiv = dojo.doc.createElement('div');
            thumbnailDiv.className = "thumbnail";

            // Add a link to each book's informtaion page
            var a = dojo.doc.createElement("a");
            a.href = book.info_url;
            a.target = '_blank';

            // Display a thumbnail of the book's cover
            var img = dojo.doc.createElement("img");
            img.src = book.thumbnail_url + '&zoom=1';
            img.border = 0;
            a.appendChild(img);
            thumbnailDiv.appendChild(a);

            mainDiv.appendChild(thumbnailDiv);
        }
        div.appendChild(mainDiv);
}

Consuming external javascript services with Dojo

I want to include goggle’s GSbookBar in one dokjo application. Unfortunately this API doesn’t have a JSONP interface. I need to include one external js file and use GSbookBar object. It’s really simple but I want to so something different. The book bar appears only in one pop up of one tab in my application. It isn’t a main part so I don’t want to load the external script every time the user loads the application.

Dojo has dojo.io.script.get to load external scripts. Its a cool way to do the traditional:

var scriptElement = document.createElement("script");
scriptElement.setAttribute("id", "jsonScript");
scriptElement.setAttribute("src", "http://external/script.js");
scriptElement.setAttribute("type", "text/javascript");
document.documentElement.firstChild.appendChild(scriptElement);

dojo.io.script.get is an elegant way load external scripts. It provides us the same interface to consume JSONP and no-JSONP scripts. One important thing when we include some external js functionality in our projects is that we need to know when the external js script is loaded to use its functionality. To do it dojo.io.script.get fires load event. In scripts without JSONP interface dojo uses checkString. Dojo evaluates checkString
“typeof(” + checkString + “) != ‘undefined’ and fires load event when is loaded.

The trick I use to load external scripts is find one js object in the script and use it as checkString. In this example the checkString is GSbookBar js object

GSbookBar = undefined;
dojo.io.script.get({
    url:"http://www.google.com/uds/solutions/bookbar/gsbookbar.js?mode=new",
    checkString: "GSbookBar",
    load: dojo.hitch(this, function(){
    window._uds_bbw_donotrepair = true;
    var bookBar;
    var options = {
        largeResultSet : !true,
        horizontal : true,
        autoExecuteList : {
            cycleTime : GSbookBar.CYCLE_TIME_MEDIUM,
            cycleMode : GSbookBar.CYCLE_MODE_RANDOM,
            thumbnailSize: GSbookBar.thumbnailsSmall,
            executeList : [data.title, data.author]
        }
    }
    bookBar = new GSbookBar(this.bookBar, options);
    dialog.resize(); // hack because of a bug in dojo 1.3
    dialog.show();  // I have created dialog dijit widget previosly
})

Follow

Get every new post delivered to your Inbox.

Join 976 other followers