Category Archives: dojo

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
    });

});

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
})

dojo.hitch

The first time I read about dojo.hitch I didn’t understand anything. I read in a book dojo.hitch is a very important function and widely used into dojo library but I didn’t understand why. I am using my learning of dojo to improve my skill in javascript. I remember the time when I hate javascript. I thought it was a very poor program language and everything I need to do with js was a nightmare. If browser was Netscape one way to to do one thing, if browser was IE other (of a other and a couple of hacks). But the times have changed. XHR and Ajax has reinvented the web. Web pages had became into Web Applications. Asynchronous request had opened our minds to a new generation of web applications, and all of it is thanks to javascript. Each day I spent learning js I see how much I was wrong.

Javascript literals are really powerful but the concept of scope is strange when you come from POO. this.foo in js sounds like $this->foo in PHP but its not the same.

For example in the following example:

dojo.declare("gam.desktop", null, {
    variable1: 1,
    foo: function() {
        dojo.xhrPost({
            url: myUrl,
            load: function(responseObject, ioArgs){
                console.log(this.variable1);
            }),
            handleAs: "json"
        });
    });

console.log(this.variable1); will not display 1 in firebug console. Its strange for me when I started with dojo. The problem is that here this points to the scope of the function foo and not to the scope of class gam.desktop. You can do strange tricky-hacks to solve the problem with global variables or something like that, or use dojo.hitch.

dojo.declare("gam.desktop", null, {
    variable1: 1,
    foo: function() {
        dojo.xhrPost({
            url: myUrl,
            load: dojo.hitch(this, function(responseObject, ioArgs){
                console.log(this.variable1);
            }),
            handleAs: "json"
        }));
    });

elegant isn’t it?

Dojo and custom widgets

I want to extend Dojo library with some custom widgets. Dojo widgets are really cool. You can use them from JavaScript and from HTML with the Dojo markup.

From js:

var dialog = new dijit.Dialog({
            title: title,
            href: href,
            preventCache: false,
            parseOnLoad: true
            });

From HTML:

<button DojoType="dijit.form.Button" type="submit" onClick='Desktop.login()'>Login</button>

Using Dojo widgets from HTML gives you errors when you validate your HTML files because Dojo attributes are non HTML attributes. If you are strict with HTML you have a problem using Dojo but its really easy to develop rich application with Dojo. so it’s your choice ;). But remember: validation tools are just that: validation tools

For my tests I use Dojo from CDN. Dojo library is very big so I don’ t want to upload all the library to my hosting. My hosting (a free one) has a monthly traffic usage limit so I want to limit the trafic to my hosting as far as I can (poor man techniques). Dojo library is in some CDNs (AOL and google for example). You only need to point your scripts to CDN and use cross domain (xd) of Dojo library and you are using the CDN. Really simple.

But If you create a custom widget you can’t upload your widget to the CD. If you paid for a CDN (akamai for example) you can do it but according my poor man’s techniques I use a free CDN so I can’t upload anything to the CDN.

For example when you use a dijit.form.TextBox with Dojo library pointing to google’s CDN you are using the following url:
http://ajax.googleapis.com/ajax/libs/Dojo/1.2.3/dijit/form/TextBox.xd.js
But if you are going to use your wonderfull custom widget gam.widget.coolwidget your browser will try to load:
http://ajax.googleapis.com/ajax/libs/Dojo/1.2.3/gam/widget/coolwidget.xd.js
and you will get a flaming 404 file not found error.

My first solution was upload all Dojo library to my hosting. With this solution I will can develop custom widgets without any problem but this is not the Dojo way. You can use xd version of Dojo and custom library in your server without problems. You only need to say Dojo in the configuration where are your widgets

djConfig = {
    parseOnLoad: false,
    modulePaths:{
        gam: './js/gamjs'
    },
    baseUrl: '/'
};

With this configuration Dojo will continue trying to get dijit.form.TextBox from http://ajax.googleapis.com/ajax/libs/Dojo/1.2.3/dijit/form/TextBox.xd.js but gam.widget.coolwidget from /js/gamjs/widget/coolwidget.xd.js.

Really easy. isn’t it?

Dojo series

I will start a new series of posts based on my experiences learning Dojo. This is not a tutorial of Dojo. Those posts want to help me to get new skills. The learning of Dojo is a bit frustrating sometimes. When you have written a dozens of source code and you realized all its wrong and that isn’t the Dojo way of doing this and you need to rewrite all. But you feel really happy when your widget appear on the browser. I have in my mind some post-project now and I hope I will post them soon

Follow

Get every new post delivered to your Inbox.

Join 998 other followers