I'm interested in taking the speed of rails and displaying in the very ajax way's of dojo.
Some quick pointers on getting the backend to play nicely with the front end.
1. In your rails app go to Configuration -> Initializers -> new_rails_defaults.rb
2. set the following to false: ActiveRecord::Base.include_root_in_json
Reason being that the response when encoded to json, natively will have the object name preceding every item in the returned list where as dojo.data just wants the items listed in an array.
eg.
Native: [{something:{data:1}}. {something:{data:2}}]
After change: [{data:1},{data:2}]
3. In your controller copy the format.xml line in each block to a line just below and change the .xml to .json and "render :json". This gives the controller the ability to respond to JSON requests.
eg:
format.xml { render :xml => @something }
format.json { render :json => @something }
4. use the dojox.data.RailsStore in your javascript. This will tag ".json" on to your requests and correctly set header information for JSON interaction.
At this point you should be able to create a dojo.data store and connect it into a widget to see some results.
The last thing is that the store will have functionality for querying and sorting. This isn't in the default rails controllers and is the next thing I'm working on for a good solution.
Be aware that Rails as of the 2ish version will happily work with JSON so requests to and from the server can be handled without the need for plugins.
To get a service going is as easy as:
var store = new dojox.data.RailsStore({target:"/something"});
where in this case something is the base REST path.
Note that writing back to the server with dojo.data doesn't not currently work as the message sent is the plain data object where as rails wants the object to be named. Ie
We send: {data:1}
server wants: {something:{data:1}}
as a quick hack, changes to the dojox.rpc.Rest class can be made look at the method (drr._change). This is too much of a hack at the moment though and I'm looking for a better way.
Thursday, 5 March 2009
Thursday, 19 February 2009
Dojo..not in 6K but comparable to JQuery
Firstly, I think fundamentalism when it comes to the JS library selection is a really poor way to go. I prefer the positive competition and innovation that comes from multiple libraries in development. However JQuery is being heavily used by a vocal web community that parts of which seem very quick to throw out negative (and now incorrect) ideas about other libraries, including the Dojo toolkit.
JQuery has the many positives including that it's all about DOM work, it's exceptionally fast (which is why everyone is looking at 'sizzle') and it's relatively small. This is what John meant it to be and he's really stuck to his vision. But others have started coming in with plugins and this is where I feel things are less clear.
People say JQuery is small, and for the core it is. But if you load plug-in code along side it then the total code is not as small. Now conversely people say Dojo is big.. but in truth the core is fairly small. It's when you load the code to support features such as widgets that things get bigger. So the ideas here are a little misleading.
In an effort to investigate dojo's big-boned reputation I decided to see how small we can make things. So where are we to start with? A basic dojo build makes a core dojo.js file that includes the full _base weighing in at around 80kb. This compared to JQueries 54kb is a little heavier.
I found the article describing dojo-mini which is how to make a small build of dojo. But I'm looking to it's heart. What about those guys that pull in JQuery, make something fade out and scream "AH HA! BEST LIBRARY EVER!".
So here's what I did. I found the "Dojo in 6K" article. A promising start as we can load up the core dojo in a ridiculously fast way. I particularly like the "stubs" idea.
This however still spawns off numerous requests if I want to get in "dojo._base.fx" for some basic animation work. So next off we turn to the build system. Here I created the following profile:
Note there is no inclusion of the dijit or dojox prefixes. We're going for tiny animation grade system here. Note also that I'm using the "stubs" file for my main dojo.js file.
Next up the dojo._baseFx file:
Here all we're doing is including the core fx file and this file will be rebuilt so we can include it via dojo.require() later.
One last change. When you build using profiles that use "customBase" there is a new regex approach to making sure you don't produce a bad build. The build system reads your code looking for references relating to _base you may have forgotten and throws them in. This system called "injection" is not what we're after here. Hence I modified the file "jslib/buildUtil.js" in the method "buildUtil.addGuardsAndBaseRequires" added the line "needBaseRequires=0;" to the top. This means we always ignore the injection for now. Note this means builds may not always have what you need so there's a level of developer responsibility that comes with turning off this helpful code.
Finally we run the build. This will produce a dojo.js file that for me was about 17k. And a _baseFx.js file that was around 28k. It also moves over the other dojo code but for something to fadeIn / fadeOut I just want some key files. I copied over the two mentioned files along with the _base directory and we're now ready to go.
In the HTML I included dojo.js in the usual way and then added the following:
When the page is ready the addOnLoad causes the extra code to load (baseFx) and then instantly uses it to find a node called "nodeName" and hide it with a nice fade out effect.
This not only works but does something that JQuery currently does not. It lazy loads over half of the code meaning the page will appear very quickly for an end user after the 17k initial dojo.js load and while they are sitting there thinking what to do next the remainder of the code is pulled in. In reality this happens faster than you can think and if sent over the wire with gzip the code content will be even tinier.
Remember back to the stubs though? why did we do that? Well it's a safety net. Say we follow up the previous code with:
dojo.query is not currently in our environment due to the small custom _base. But the stubs package knows that any call to query should load it. The code is loaded as it is needed and we carry on.
For web applications this approach isn't really optimal. But for the designers out there that complain dojo is too bloated to be used for simple web page work, think again. 17k and Dojo is usable. A moment later we're animating.
Don't get me wrong, John Resig continues to amaze me with his work and JQuery in general. But I'm really hoping one day people will stop uttering things about Dojo that just aren't true, especially not on a podcast (Rubyology Ep73).
Final thought
- JQuery 1.3.1 minified = 54Kb
- Dojo (as above) 17Kb loader + 28Kb baseFx = 55Kb
(To add lazy loading to JQuery)
- 54kb JQuery 1.3.1 + 3kb xLazyLoader = 57Kb
To load the page initially with Dojo in the above way you need to load 17Kb
To load the page initially with JQuery + loader you need 57Kb
JQuery has the many positives including that it's all about DOM work, it's exceptionally fast (which is why everyone is looking at 'sizzle') and it's relatively small. This is what John meant it to be and he's really stuck to his vision. But others have started coming in with plugins and this is where I feel things are less clear.
People say JQuery is small, and for the core it is. But if you load plug-in code along side it then the total code is not as small. Now conversely people say Dojo is big.. but in truth the core is fairly small. It's when you load the code to support features such as widgets that things get bigger. So the ideas here are a little misleading.
In an effort to investigate dojo's big-boned reputation I decided to see how small we can make things. So where are we to start with? A basic dojo build makes a core dojo.js file that includes the full _base weighing in at around 80kb. This compared to JQueries 54kb is a little heavier.
I found the article describing dojo-mini which is how to make a small build of dojo. But I'm looking to it's heart. What about those guys that pull in JQuery, make something fade out and scream "AH HA! BEST LIBRARY EVER!".
So here's what I did. I found the "Dojo in 6K" article. A promising start as we can load up the core dojo in a ridiculously fast way. I particularly like the "stubs" idea.
This however still spawns off numerous requests if I want to get in "dojo._base.fx" for some basic animation work. So next off we turn to the build system. Here I created the following profile:
dependencies = {
layers: [
{
name: "dojo.js",
customBase: true,
dependencies: [
"dojo._base.window",
"dojo._base._stubs"
]
},
{
name: "_baseFx.js",
customBase: true,
layerDependencies: [
"dojo.js"
],
dependencies: [
"dojo._baseFx"
]
}
],
prefixes: []
}
Note there is no inclusion of the dijit or dojox prefixes. We're going for tiny animation grade system here. Note also that I'm using the "stubs" file for my main dojo.js file.
Next up the dojo._baseFx file:
dojo.provide("dojo._baseFx");
dojo.require("dojo._base.fx");
Here all we're doing is including the core fx file and this file will be rebuilt so we can include it via dojo.require() later.
One last change. When you build using profiles that use "customBase" there is a new regex approach to making sure you don't produce a bad build. The build system reads your code looking for references relating to _base you may have forgotten and throws them in. This system called "injection" is not what we're after here. Hence I modified the file "jslib/buildUtil.js" in the method "buildUtil.addGuardsAndBaseRequires" added the line "needBaseRequires=0;" to the top. This means we always ignore the injection for now. Note this means builds may not always have what you need so there's a level of developer responsibility that comes with turning off this helpful code.
Finally we run the build. This will produce a dojo.js file that for me was about 17k. And a _baseFx.js file that was around 28k. It also moves over the other dojo code but for something to fadeIn / fadeOut I just want some key files. I copied over the two mentioned files along with the _base directory and we're now ready to go.
In the HTML I included dojo.js in the usual way and then added the following:
dojo.addOnLoad(function(){
dojo.require("dojo._baseFx");
dojo.fadeOut({node:"nodeName"}).play();
})
When the page is ready the addOnLoad causes the extra code to load (baseFx) and then instantly uses it to find a node called "nodeName" and hide it with a nice fade out effect.
This not only works but does something that JQuery currently does not. It lazy loads over half of the code meaning the page will appear very quickly for an end user after the 17k initial dojo.js load and while they are sitting there thinking what to do next the remainder of the code is pulled in. In reality this happens faster than you can think and if sent over the wire with gzip the code content will be even tinier.
Remember back to the stubs though? why did we do that? Well it's a safety net. Say we follow up the previous code with:
dojo.addOnLoad(function(){
dojo.query("something").innerHTML = "blah";
})
dojo.query is not currently in our environment due to the small custom _base. But the stubs package knows that any call to query should load it. The code is loaded as it is needed and we carry on.
For web applications this approach isn't really optimal. But for the designers out there that complain dojo is too bloated to be used for simple web page work, think again. 17k and Dojo is usable. A moment later we're animating.
Don't get me wrong, John Resig continues to amaze me with his work and JQuery in general. But I'm really hoping one day people will stop uttering things about Dojo that just aren't true, especially not on a podcast (Rubyology Ep73).
Final thought
- JQuery 1.3.1 minified = 54Kb
- Dojo (as above) 17Kb loader + 28Kb baseFx = 55Kb
(To add lazy loading to JQuery)
- 54kb JQuery 1.3.1 + 3kb xLazyLoader = 57Kb
To load the page initially with Dojo in the above way you need to load 17Kb
To load the page initially with JQuery + loader you need 57Kb
Tuesday, 14 October 2008
Polymorphism
I love that word.. anyway, I stumbled on an article by John Resig that I'd read a while back talking about method overloading in JS.
Looking through the article and comments was quite interesting and inspired me to write this down just in case I feel the need to revisit the topic one day.
Edit: I extended the "Object" prototype previously.. a big no no but one that made proof of concepts quick and easy.. I've updated the code to follow the JR way of leave JS objects untouched.
I noticed if you were to borrow the function via call or apply the scoping would go badly so I used some closure hackery to preserve this. It's possibly a bit suspect but it works.
Usage and example of scope preservation:
Looking through the article and comments was quite interesting and inspired me to write this down just in case I feel the need to revisit the topic one day.
Edit: I extended the "Object" prototype previously.. a big no no but one that made proof of concepts quick and easy.. I've updated the code to follow the JR way of leave JS objects untouched.
var poly = {
addMethod: function(object, name, fn){
object._store = object._store || {};
object._store[name] = object._store[name] || {};
object._store[name][fn.length] = fn;
object[name] = function(){
if(object._store[name][arguments.length])
return object._store[name][arguments.length].apply(this, arguments);
else
throw new Error("Wrong number of arguments");
}
}
}I noticed if you were to borrow the function via call or apply the scoping would go badly so I used some closure hackery to preserve this. It's possibly a bit suspect but it works.
Usage and example of scope preservation:
var n = {name:"I am n"};
poly.addMethod(n, "getName", function(){ return (this.name);})
n.getName()
>>I am n
var s = {name:"I am s"};
s.do = function(){ return n.getName.apply(this, []); }
s.do()
>>I am s
Sunday, 3 August 2008
Kicking the dijit toolbar up a notch
I love that dijit has a menu system built in using dijit dropDownButtons and the dijit toolbar. I don't love that interacting with a mouse requires more clicking than the native windows menu system most users are familiar with.
The key is that the dropDownButtons work independently from one another. Click one and that menu shows, hover over the next menu and you can see focus but it doesn't show the menu till you click on it. Under windows once we click a menu open, everything starts responding to a hover event.
Rather than grumble, I decided to fix this behaviour:
Here the buttons work as a team. When one opens it lets the others know its time to respond to the hover. When one closes due to clicking off the focus or selecting an option it keeps the others in the loop and they stop worrying about the hover. Dojo's pub/sub is a wonderfully simple networking tool for your widgets.
The key is that the dropDownButtons work independently from one another. Click one and that menu shows, hover over the next menu and you can see focus but it doesn't show the menu till you click on it. Under windows once we click a menu open, everything starts responding to a hover event.
Rather than grumble, I decided to fix this behaviour:
dojo.declare(
"widget.DropDownButton",
dijit.form.DropDownButton,
{
respondToMouseOver: false,
postCreate: function(){
this.inherited(arguments);
dojo.connect(this, "_openDropDown", this, "_updateRespondOpen");
dojo.connect(this, "_closeDropDown", this, "_updateRespondClose");
dojo.connect(this.domNode, "onmouseover", this, "_respondToMouseover");
dojo.subscribe("/dropDownOpen", this, "_setRespondState");
dojo.subscribe("/dropDownCloseAll", this, "_closeDropDown");
},
_setRespondState: function(state){
this.respondToMouseOver = state;
},
_respondToMouseover: function(){
if(this.respondToMouseOver){
dojo.publish("/dropDownCloseAll", [true]);
this._openDropDown(arguments);
}
},
_updateRespondOpen: function(){
dojo.publish("/dropDownOpen",[true]);
},
_updateRespondClose: function(){
dojo.publish("/dropDownOpen",[false]);
}
}
)Here the buttons work as a team. When one opens it lets the others know its time to respond to the hover. When one closes due to clicking off the focus or selecting an option it keeps the others in the loop and they stop worrying about the hover. Dojo's pub/sub is a wonderfully simple networking tool for your widgets.
Sunday, 13 July 2008
JavaScript + Rhino + SQLite + Dojo + Jetty +..what's left?
As a small side project I decided to see what things would look server side if JavaScript was the driving force.
I'm using Rhino (Mozillas JavaScript interpreter) to start the ball rolling, get a Jetty server instance up and load some dojo into the background for the hell of it. From there you can open up a SQLite connection to a local database and start writing things out via servlets.
My driving force was what does a server have to be these days? given that JavaScript libraries such as Dojo, YUI, EXT and JQuery UI are all creating extremely dynamic front ends, we're leveraging server-side rendering technologies less and less. In fact they are starting to conflict with wanting to do the same things. So if all I need is data from my server, then all I need is some clever servlets and a hint of JSON.
So from my simple hackery I have the basics working. It's not robust, scalable or designed to handle enterprise smarts. But as an after hours proof of concept it's an odd and cool feeling to think I can build a servlet response with JavaScript that is reading database objects from a tiny local DB and spitting it straight to JSON.
Oh and since all of it is hosted in java I've been developing this on Windows, Ubuntu and an OSX box. Amusingly Jetty and the DB are smaller than the dojo source install I'm using. Note you have to grab the source install of dojo if you want load it in Rhino. The source is intentionally stripped down on release to work only in browsers.
So the trickiest thing so far has been figuring out the Jetty API. Damn thing keeps changing leaving some of the tutes to be misleading. As I gradually become more familiar with it, it's becoming less of a hassle.
I'm using Rhino (Mozillas JavaScript interpreter) to start the ball rolling, get a Jetty server instance up and load some dojo into the background for the hell of it. From there you can open up a SQLite connection to a local database and start writing things out via servlets.
My driving force was what does a server have to be these days? given that JavaScript libraries such as Dojo, YUI, EXT and JQuery UI are all creating extremely dynamic front ends, we're leveraging server-side rendering technologies less and less. In fact they are starting to conflict with wanting to do the same things. So if all I need is data from my server, then all I need is some clever servlets and a hint of JSON.
So from my simple hackery I have the basics working. It's not robust, scalable or designed to handle enterprise smarts. But as an after hours proof of concept it's an odd and cool feeling to think I can build a servlet response with JavaScript that is reading database objects from a tiny local DB and spitting it straight to JSON.
Oh and since all of it is hosted in java I've been developing this on Windows, Ubuntu and an OSX box. Amusingly Jetty and the DB are smaller than the dojo source install I'm using. Note you have to grab the source install of dojo if you want load it in Rhino. The source is intentionally stripped down on release to work only in browsers.
So the trickiest thing so far has been figuring out the Jetty API. Damn thing keeps changing leaving some of the tutes to be misleading. As I gradually become more familiar with it, it's becoming less of a hassle.
Thursday, 12 June 2008
Dojo.query, dojo.Nodelist and Chaining Actions
I've recently becoming more and more reliant on dojo.query for finding the nodes I want to work on. Gone are the days of trying to cleverly use name and id as the only two distinguishing features of a node. Now we can use almost any attribute on a node. To see how this can be useful I'll talk about a recent case.
To begin with we are given a HTML form that is arranged so that there are lines of input elements and at the beginning of each line is a checkbox. The checkbox is used to enable or disable a row of elements depending on its checked state.
To do this in the old days we could either assign some id's to the nodes and do some string manipulation on the id so that items like "row1_1, row1_2, row1_3" were toggled (not pretty) or we could walk the dom tree and start going through parentNode, childNodes etc checking tagNames and so on. This is pretty hard work. Lets see how it could be done with a hint of dojo.
if our row looks like the following:
What do we want our code to do to it? Well when the pages loads, we need to disable the entry fields, uncheck all checkboxes and setup our events so that clicking a checkbox toggles the rows state. Right.. time for some code
What do we have here? Lets walk through how the page uses this code.
We can see at the end, a dojo.addOnLoad is used to link up the formHelper.init function. We wrap that with dojo.hitch to make sure that when the function is called by the window onload event, any references inside the method correctly know that "this.{method}" means "formHelper.{method}", not "window.{method}". You'll have to trust me on this one and if you want to know more, look up "scoping"
When the init is called we use dojo.query to get all the elements on the page that use the style class "checkboxTrigger". Easy. On those elements we setup an onclick action that points to the "toggleRow" method. Again see the use of hitch to keep the scope in check. Notice what's next? straight after the onclick we can call the further ".attr" method to set the checked state on the nodes. This is because query and it's methods keep returning Nodelists, so we can keep chaining the calls.
Next we call the toggleNodes method. This methods goal is to set everything other than the trigger checkbox nodes to be either enabled or disabled. Note that in this method we are doing a query for all inputs that don't have the checkboxTrigger class and that don't have the submits class. I put the submits style class on the save and cancel buttons to make sure that they're never impacted upon. Also note that this query can grab other things like select boxes etc. On each of these nodes we simply set the disabled state via the "attr" method. Also note that if we don't give it a specific node to focus on we just apply the query to the body.
Finally the toggleRow is simply a wrapper to toggleNodes but with the additional step that we pick which row to dojo.query inside. That is we narrow the search for nodes to toggle to one row.
And that's it. The code can be dropped on to any page of a similar structure with the right class names. You can also add / remove the number of form elements in a row without worrying about changing a thing. Compact, reusable, robust.
To begin with we are given a HTML form that is arranged so that there are lines of input elements and at the beginning of each line is a checkbox. The checkbox is used to enable or disable a row of elements depending on its checked state.
To do this in the old days we could either assign some id's to the nodes and do some string manipulation on the id so that items like "row1_1, row1_2, row1_3" were toggled (not pretty) or we could walk the dom tree and start going through parentNode, childNodes etc checking tagNames and so on. This is pretty hard work. Lets see how it could be done with a hint of dojo.
if our row looks like the following:
<div>
<input type="checkbox" class='checkboxTrigger'>
<label for='asd'>Test</label>
<input type="text" />
</div>
What do we want our code to do to it? Well when the pages loads, we need to disable the entry fields, uncheck all checkboxes and setup our events so that clicking a checkbox toggles the rows state. Right.. time for some code
var formHelper = {
toggleRow: function(e){
this.toggleNodes((!e.target.checked), e.target.parentNode);
},
init: function(){
dojo.query(".checkboxTrigger").onclick(dojo.hitch(this,this.toggleRow)).attr("checked",false);
this.toggleNodes(true);
},
toggleNodes: function(status, rootNode){
rootNode = rootNode||dojo.body();
dojo.query("input:not(.checkboxTrigger):not(.submits),select,radio", rootNode).attr("disabled",status);
}
}
dojo.addOnLoad(dojo.hitch(formHelper,formHelper.init));What do we have here? Lets walk through how the page uses this code.
We can see at the end, a dojo.addOnLoad is used to link up the formHelper.init function. We wrap that with dojo.hitch to make sure that when the function is called by the window onload event, any references inside the method correctly know that "this.{method}" means "formHelper.{method}", not "window.{method}". You'll have to trust me on this one and if you want to know more, look up "scoping"
When the init is called we use dojo.query to get all the elements on the page that use the style class "checkboxTrigger". Easy. On those elements we setup an onclick action that points to the "toggleRow" method. Again see the use of hitch to keep the scope in check. Notice what's next? straight after the onclick we can call the further ".attr" method to set the checked state on the nodes. This is because query and it's methods keep returning Nodelists, so we can keep chaining the calls.
Next we call the toggleNodes method. This methods goal is to set everything other than the trigger checkbox nodes to be either enabled or disabled. Note that in this method we are doing a query for all inputs that don't have the checkboxTrigger class and that don't have the submits class. I put the submits style class on the save and cancel buttons to make sure that they're never impacted upon. Also note that this query can grab other things like select boxes etc. On each of these nodes we simply set the disabled state via the "attr" method. Also note that if we don't give it a specific node to focus on we just apply the query to the body.
Finally the toggleRow is simply a wrapper to toggleNodes but with the additional step that we pick which row to dojo.query inside. That is we narrow the search for nodes to toggle to one row.
And that's it. The code can be dropped on to any page of a similar structure with the right class names. You can also add / remove the number of form elements in a row without worrying about changing a thing. Compact, reusable, robust.
Tuesday, 3 June 2008
dojo.query - not just another dojo.byId
The more I find out about the magical function that is dojo.query, that more that I'm blown away by it's potential.
It feels so unfamiliar at first using javascript and knowing that I'm grabbing and working with node objects rather than using string ID's all the time but once you get used to it, it's liberating.
Finding and filtering nodes by any number of attributes and classes is only just scratching the surface though. Dojo.query not only makes getting things easy but what it returns is just as powerful.
dojo.nodeList is a fairly new entity to me but one that has a similarly great potential. It's intention is to hold a bunch of node elements and make working on them easier than you'd expect.
In one of my last posts I used dojo.forEach to loop through nodes adding a connect on each item, but as Alex Russell pointed out, we needn't worry about half of that code.
Instead we can write:
I love the fact that it not only makes things shorter, but somewhat more readable. It applies the updateStatus function as the onclick for all the return nodes. Easy.
Looking into the api for the dojo.NodeList there are plenty of things we can do to our nodes. We can create animations, addContent, clear content, etc.
I highly recommend a bit of exploring in both the dojo.query and dojo.NodeList areas as I'm continuing to find more and more things of interest.
It feels so unfamiliar at first using javascript and knowing that I'm grabbing and working with node objects rather than using string ID's all the time but once you get used to it, it's liberating.
Finding and filtering nodes by any number of attributes and classes is only just scratching the surface though. Dojo.query not only makes getting things easy but what it returns is just as powerful.
dojo.nodeList is a fairly new entity to me but one that has a similarly great potential. It's intention is to hold a bunch of node elements and make working on them easier than you'd expect.
In one of my last posts I used dojo.forEach to loop through nodes adding a connect on each item, but as Alex Russell pointed out, we needn't worry about half of that code.
Instead we can write:
dojo.query(".checkboxTrigger").onclick(updateStatus);
I love the fact that it not only makes things shorter, but somewhat more readable. It applies the updateStatus function as the onclick for all the return nodes. Easy.
Looking into the api for the dojo.NodeList there are plenty of things we can do to our nodes. We can create animations, addContent, clear content, etc.
I highly recommend a bit of exploring in both the dojo.query and dojo.NodeList areas as I'm continuing to find more and more things of interest.
Subscribe to:
Posts (Atom)