Why Dojo Matters

The Dojo framework is a javascript library that WaveMaker is built on top of.

In addition to providing a set of libraries useful for building applications, it also provides sets of widgets. WaveMaker tries to take the best of dojo's widgets and where we weren't satisfied with what dojo had to offer, we provided some of our own widgets as well.

WaveMaker is built using the dojo javascript toolkit; all classes are declared using dojo's object oriented class management system; and in this sense, WaveMaker and any project built with wavemaker is built using the dojo toolkit.

So where and why does WaveMaker diverge from Dojo?

Containers

Containers, panels, tabs, dialogs all depend upon a common set of base classes, so any widget whose purpose is to lay out widgets are fundamentally different between dojo and WaveMaker. Why is that?

Dojo's model of its users is as someone who opens up a text editor, enters a bunch of dijits, along with some CSS to help lay them out. These users will use containers when they want tabs. They might use them to separate the table of contents from the header from the body of a document. But within each of these containers, the dijits are laid out by the developer using CSS.

WaveMaker's model is that the WaveMaker framework handles the layout for the user, the user simply drags and drops things where they are supposed to go, and the panel helps to position things, an especially resize things dynamically if they use % sizing.

Having tried to use dojo containers to lay out every single widget, and comparing performance of dojo containers to wavemaker containers, their performance (as of dojo 1.2 or 1.3) was orders of magnitude worse than WaveMaker. This is not a criticism but simply a recognition of the different models of how a user will use their toolkit vs our designer.

By chosing not to use dojo containers, we've made it noticably harder to use their tabs, dialogs, dashboards and really, and dojo widget that depends upon their container model.

dojo.extend

dojo.extend provides a way of modifying the definition of a class. You can use this to add methods to a class definition or to modify an existing method. Lets take for example a trivial example where we want the wm.Lookup editor to always do an alert whenever it gets a new value:

Now, the concept we have to understand when looking at the above onclick function, is what does "this" refer to. Is the "this" in "this.button2" the same as the "this" in "this.button1"? In fact, the answer here is no; most commonly, "this" will refer to the window, or in this case, it refers to "button1" whose onclick function is being called. Its always important to know and control what "this" refers to, and dojo.hitch lets us do that.

The above code specifies that button1's onclick event handler is the "myOnClick" method of "this".

dojo.connect

The connect function is a very powerful tool that lets a developer say "any time A happens, I want B to happen as well". By providing a flexible way to express this request, it becomes possible to build more flexible and modular applications. Lets compare this with a traditional development style. Lets take the case where the user clicks on a button. A traditional development approach would expect the button to know everything that must happen when it is clicked:

Any time your application evolves, you have to go back, find the button1 onclick event handler and modify it to account for your changes.

In contrast, lets suppose that each component that wants to do something when the button is clicked can request to be notified of the click; the onclick code that affects a given component is controlled by that component and not by the button.

PROS: If I want to add a new side effect to clicking on the button, I don't need to further complicate my onclick event handler, I don't need my onclick event handler to build in knowledge of the components to be affected by this. The component that will be affected already knows its own internals and can connect to it without building in any module-specific logic that the button doesn't need to know about.

CONS: I may now have code to be executed onclick in a dozen different places.

Ultimately, using connect makes it far easier to build a well architected MVC style application where widgets can connect to changes in the model; the controller can connect to changes in widget state, and there is no need for the model to have widget code in it, nor the widget to have model code in it.

Any time the user clicks on the button, it will call this.myOnClick().

Services Example:

start: function() {
// Any time either service variable 1 or 2 comes back with data, call mySuccessHandler.
// There is no limit to the number of things that can be connected to "mySuccessHandler"
dojo.connect(this.serviceVariable1, "onSuccess", this, "mySuccessHandler");
dojo.connect(this.serviceVariable2, "onSuccess", this, "mySuccessHandler");
// You can also create as many connections to serviceVariable1's onSuccess event as you want;
// in thiscase, serviceVariable1 will trigger calls to mySuccessHandler, anotherSuccessHandler and
// anotherSuccessHandler2, while serviceVariable2 only calls mySuccessHandler
dojo.connect(this.serviceVariable1, "onSuccess", this, "anotherSuccessHandler");
dojo.connect(this.serviceVariable1, "onSuccess", this, "anotherSuccessHandler2");

dojo.disconnect

Any time you create a connection, you create pointers to objects that will need to be garbage collected. You can deallocate these pointers using dojo.disconnect(). The call to dojo.connect returns a connectionId that you can cache and use in a later call.

start: function() {
/* By putting the disconnect inside of the function, we insure that this function is only called the first time
* the user clicks
*/
this.connectionId = dojo.connect(this.button1, "onclick", this, function() {
alert("CLICK");
dojo.disconnect(this.connectionId);
});
},
destroy: function() {
/* In case the user never clicked on the button, we'll still need to disconnect when this page is destroyed */
dojo.disconnect(this.connectionId);
this.inherited(arguments);
}

this.connect

WaveMaker objects support a simplification of dojo.connect that automatically adds the connection id to a list that needs to be disconnected when destroy is called.

start: function() {
/* The connection id here is disconnected when "this" is destroyed (i.e. the page) */
this.connect(this.button1, "onclick", this, "myOnClick");
/* The connection id here is disconnected when "this.button1" is destroyed (usually but not always at
* the same time that the page is destroyed */
this.button1.connect(this.button1, "onclick", this, "myOnClick");
}

dojo.subscribe/publish

Rather than connecting to a single method, its sometimes offers more flexibility to to subscribe to notifications. A notification does not let you have something called every time an event such as onclick is fired, but does let you cause something to be executed each time a call is made to dojo.publish. For purposes of a WaveMaker developer, this might be useful for one page to let other pages know that something has happened:

dojo.publish takes two parameters:

Notification name: The first parameter is the name of the notification; this is what you must dojo.subscribe to if you want to be notified of this particular call to dojo.publish

Args: an array of arguments to pass to anyone subscribed to this notification