|
|
Docs
DOJO Classes
Classes in Dojo are declared with a declare statement with a class name, super-class information, and body. Within the body can be variables and methods. dojo.declare("ClassName", null, {/*class body*/}); dojo.declare("Person", null, { constructor: function(name, age, currentResidence){ this.name=name; this.age=age; this.currentResidence=currentResidence; }, moveToNewState: function(newState){ this.currentResidence=newState; } }); The function named "constructor" is special. It gets called when you create an object with the "new" operator of JavaScript. //create an instance of a new person var matt= new Person('Matt', 25, 'New Mexico'); Arrays and Objects as Member VariablesIf your class contains arrays or other objects, they should be declared in the constructor so that each instance gets it's own copy. Simple types (literal strings and numbers) and are fine to declare in the class directly. dojo.declare("my.classes.bar", my.classes.foo, {
someData: [1, 2, 3, 4], // doesn't do what I want: ends up being static numItem : 5, // one per bar strItem : "string", // one per bar constructor: function() { this.someData = [ ]; // better, each bar has it's own array this.expensiveResource = new expensiveResource(); // one per bar } }); On the other hand, if you want an object or array to be static (shared between all instances of my.classes.bar), then you should do something like this: dojo.declare("my.classes.bar", my.classes.foo, {
constructor: function() { dojo.debug("this is bar object # " + this.statics.counter++); }, statics: { counter: 0, somethingElse: "hello" } }); "Statics" is not a special dojo construct - you can use any name you want, like "constants". In this example, you'd refer to the variable as myInstance.statics.counter both inside and outside the class definition. Why is this true for arrays and objects, but not primitives? It's because, like most OOP languages, JavaScript uses object references. For example, given: x = { fruit: "apple" };
y = x; Now x and y both refer to the same object. Modifying x.fruit will also affect y.fruit. Inheritance A person can only do so much, so let's create an Employee class that extends the Person class.The second argument in the dojo.declare() function is for extending classes. dojo.declare("Employee", Person, { constructor: function(name, age, currentResidence, position){ // remember, Person constructor is called automatically this.password=""; this.position=position; }, login: function(){ if(this.password){ alert('you have successfully logged in'); }else{ alert('please ask the administrator for your password'); } } }); Dojo handles all of the requirements for setting up the inheritance chain, including calling the superclass constructor automatically. Methods or variables can be overridden by setting the name to the same as it is in the parent class. The Employee class can override the Person class moveToNewState(), perhaps by letting the company pay for moving expenses. You initialize the subclass the same as the Person class with the new keyword. var kathryn=new Employee(' Kathryn ', 26, 'Minnesota', 'Designer');
The Employee class passes the first three arguments down to the Person class, and sets the position.Kathryn has access to the login() function found in the Employee class, and also the moveToNewState() function by calling kathryn.moveToNewState("Texas"); Matt on the other hand, does not have access to the Employee login() function. matt.login() // ERROR can't log in because he is not an Employee Calling Superclass MethodsOften when you're overriding a method, you want to add something to the superclasses method, not totally replace it. Dojo has helper functions to make this easy. But you don't have to worry in the constructor. As we said above, superclass constructors are always called automatically, and always before the subclass constructor. This convention reduces boilerplate in 90% of cases. For all other methods, you can use someMethod: function() { // call base class someMethod this.inherited(arguments); // now do something else } The argument is always literally arguments, a special Javascript array variable which holds all the arguments (like argv in C).There are a few variations to inherited() for special cases. If you have a method that was put into your object outside of declare, you need to specify the name of the calling function like this: this.inherited("someMethod", arguments);
And you can send custom parameters to the ancestor function. Just place the extra arguments in array literal notation with brackets: this.inherited(arguments, [ customArg1, customArg2 ]) Multiple inheritance - Mixins Suppose, for example, you have a class called VanillaSoftServe, and classes MandMs and CookieDough. Here's how to make a Blizzard: dojo.declare("VanillaSoftServe",null, {
constructor: function() { console.debug ("mixing"); } }); dojo.declare("MandMs",null, { constructor: function() { console.debug("never called"); }, kind: "plain" }); dojo.declare("CookieDough",null, { chunkSize: "medium" }); dojo.declare("Blizzard", [VanillaSoftServe, MandMs, CookieDough], { constructor: function() { console.debug("A blizzard with "+ this.kind+" M and Ms and "+ this.chunkSize+" chunks of cookie dough." ); } }); Then the following: new Blizzard();
Will first print "mixing" on the debug console because VanillaSoftServe is the superclass of Blizzard. In fact, VanillaSoftServe is the only superclass of Blizzard - the first mixin is always the superclass. Then "A blizzard with plain M and Ms and medium chunks of cookie dough." will appear. Mixins are used a lot in defining Dijit classes, with most classes extending Dijit._Widget and mixing in Dijit._Templated. DOJO Programming 1 - infrastruttura necessaria a creare/"simulare" l'object orientation in javascript DOJO Parser
This machinery layers on top of dojo.query() to provide a way to declare instances of any class
via markup in your page. The
parser is:
<script type="text/javascript" src="http://o.aolcdn.com/dojo/0.9.0/dojo/dojo.xd.js"
djConfig="parseOnLoad: true"></script> <script type="text/javascript"> dojo.require("dojo.data.JsonItemStore"); dojo.require("dijit.Tree"); dojo.require("dojo.parser"); var countries = new dojo.data.JsonItemStore({ url: "countries.json" }); </script> </head> <body class="tundra"> <div dojoType="dijit.Tree" store="countries" labelAttr="name" typeAttr="type" query="{type:'continent'}" ></div> In this case, we see the familiar use of the dojoType attribute to denote where an instance of our widget should be created. This is the functional equivalent of writing: <script type="text/javascript" src="http://o.aolcdn.com/dojo/0.9.0/dojo/dojo.xd.js" djConfig="parseOnLoad: true"></script> <script type="text/javascript"> dojo.require("dojo.data.JsonItemStore"); dojo.require("dijit.Tree"); dojo.require("dojo.parser"); dojo.addOnLoad( var countries = new dojo.data.JsonItemStore({ url: "countries.json" }); var tree = new dijit.Tree({ store: countries, labelAttr: "name", typeAttr: "type", query: {type: "continent"} }, dojo.byId("treePlaceHolder")); }); </script> </head> <body class="tundra"> <div id="treePlaceHolder"></div> They're identical. The only difference is that in the first example, the work of locating and creating the widget instance is handed off to the Dojo parser. To fully understand the parser, it's important to understand it's operation in broad terms. The parser operates by:
<script type="text/javascript" src="http://o.aolcdn.com/dojo/0.9.0/dojo/dojo.xd.js" djConfig="parseOnLoad: true"></script> <script type="text/javascript"> dojo.require("dojo.parser"); dojo.declare("example.Class", null, { constructor: function(args, node){ // this class constructor is designed for the // parser's "args, node" convention dojo.mixin(this, args); }, }); </script> </head> <body class="tundra"> <div dojoType="example.Class" foo="bar" jsId="thinger"> <script type="dojo/method"> // this block is executed as the class is created but // after the class constructor is finished console.debug(this.foo); // Prints "bar" </script> </div> Each script of type "dojo/method" is executed after the constructor runs. We saw examples of this in Part 1, Example 2.. Finally, the class constructor uses a mixin to copy the attributes from tag to properties in the instance. Thus thinger is created by calling the constructor with args = {foo: "bar"} and node as the div node itself. Foo is created as a property by mixin.Type ConversionsLightweight type conversions are done on the attribute values. The types are based on the property types used in the definition of the class. For example: <script type="text/javascript" src="http://o.aolcdn.com/dojo/0.9.0/dojo/dojo.xd.js"
djConfig="parseOnLoad: true"></script> <script type="text/javascript"> dojo.require("dojo.parser"); dojo.declare("example.Class", null, { constructor: function(args, node){ // this class constructor is designed for the // parser's "args, node" convention dojo.mixin(this, args); }, title: "Hello", isEnabled: true, dayCount: 45, onClick: function(){}, names: ["Monday", "Tuesday", "Wednesday"], startDate: new Date() }); </script> </head> <body class="tundra"> <div dojoType="example.Class" title="Good Morning" isEnabled="false" dayCount="4" onClick="alert(thinger.dayCount)" names="Thursday, Friday" startDate="2008-01-01" jsId="thinger"> <script type="dojo/method"> // this block is executed as the class is created but // after the class constructor is finished console.debug(this.foo); // Prints "bar" </script> </div> In this example, the attributes will be converted to their correponding types that were used in the definition of example.Class:
If the property type does not match one of the types listed above, then dojo.fromJson() will be used to convert the attribute value. Markup FactoryIf the class declares a method with the name markupFactory, that function will be used to create the object instance, instead of the constructor. This is useful if the class has special initialization for instances created via markup, versus instances created in script via the class constructor. An example class that defines a markupFactory method: <script type="text/javascript" src="http://o.aolcdn.com/dojo/0.9.0/dojo/dojo.xd.js" djConfig="parseOnLoad: true"></script> <script type="text/javascript"> dojo.require("dojo.parser"); dojo.declare("example.Class", null, { constructor: function(args, node){ // this class constructor is designed for the // parser's "args, node" convention dojo.mixin(this, args); }, title: "Hello", isEnabled: true, dayCount: 45, onClick: function(){}, names: ["Monday", "Tuesday", "Wednesday"], startDate: new Date(), markupFactory: function(params, domNode, constructorFunction){ //params: object that contains the markup attribute values, //with type conversion already completed. //domNode: the DOM node (the div in the code below) //constructorFunction: The constructor function matching //the dojoType in markup. In this example, example.Class var instance = new constructorFunction(params, domNode); //Do special initialization intialization here return instance; } }); </script> </head> <body class="tundra"> <div dojoType="example.Class" title="Good Morning" isEnabled="false" dayCount="4" onClick="alert(thinger.dayCount)" names="Thursday, Friday" startDate="2008-01-01" jsId="thinger"> <script type="dojo/method"> // this block is executed as the class is created but // after the class constructor is finished console.debug(this.foo); // Prints "bar" </script> </div> DOJO Programming 2 - the Parser DOJO Creating a Widget Programmatically
In Part 2: Dijit, you saw how to instantiate (create an instance of) a dojo widget declaratively, using the "dojoType" attribute: <div dojoType="dijit.TitlePane" title="Outer Pane">
This is a title pane containing another title pane <div dojoType="dijit.TitlePane" title="Inner Pane"> And this is the inner title pane... </div> </div> While this method is very convenient, widgets declared in this way are instantiated only when the page first loads. What if, however, you want to create a widget at some later time, e.g. as the result of a user-action? This is one case where we would want to instantiate a widget programmatically, which looks like: var button1 = new dijit.form.Button(params, srcNodeRef);
Let's pick that programmatic example apart:
Thus, the programmatic equivalent of: from the example above would be:var innerPane = new dijit.TitlePane( {title:"Inner Pane"}, dojo.byId("someDiv")); When that line executes, the div with the id "someDiv"
will be replaced with a TitlePane widget, with title "Inner Pane".
Programmatically creating widgets allows extra freedom in the parameters. The following is perfectly legal: var innerPane2 =
new dijit.TitlePane({ title: 'Creating New '+docType, duration: 5 * 1000 /* 5 seconds, converted to ms */ }, dojo.byId("someDiv")); In declarative widgets, you may only pass strings. In programmatic
ones, you can pass arrays, nested objects, Dates or Numbers as
parameters. This isn't important for bundled Dijit components - they
all work with strings - but it can make building your own widgets
easier. <script>
// Doesn't work in 1.0. Class and style will be overwritten new dijit.form.Button({},,dojo.byId("someDiv")); </script> <div id="someDiv" class="large" style="color:red"></div> The correct code: // Works in 1.0 new dijit.form.Button({ "class": "large", style: "color: red" }, dojo.byId("someDiv")); startup()Certain widgets require a startup() method to be called. When building widgets programmatically, you create the parent first, then add the children, and grandchildren... and finally call startup(). Startup() is called once on the top element in the hierarchy, after the whole hierarchy has been setup and the element inserted. It's good practice to include the startup() call, even for widgets that have no children or do not require it. accordion = new dijit.layout.AccordionContainer({}, dojo.byId("accordionShell")); accordion.addChild(new dijit.layout.ContentPane()); accordion.addChild(new dijit.layout.ContentPane()); accordion.addChild(new dijit.layout.ContentPane()); accordion.startup(); Interacting With Widgets
Using the Reference
DOJO Programming 3 - Creating a Widget Programmatically DOJO Events
Dojo.connect has the following signature (acceptable types in square brackets): handle = dojo.connect(Scope of Event [object or null], Event [string], Context of Linked Method [string or null], Linked Method [string or function], Don't Fix Flag [boolean])
All of the options for calling dojo.event are explored further below. Example Code for Reference<head> <title>Dojo Events are Great</title> <script src="dojo/dojo.js" type="text/javascript"></script> <script type="text/javascript"> function foo() { console.debug("A click upon your houses!"); } function globalGuy() { console.debug("Global Guy fired!"); } var someObject = { bar: function() { console.debug("Bar fired!"); return 7; }, baz: function() { console.debug("Baz fired!"); return 14; } } var anotherObject = { afterBaz: function () { console.debug("afterBaz fired!"); } } </script> <body> <a id="firstLink" href="http://dojotoolkit.org/">Dojo</a> is an excellent tool kit. </body> Connecting to a DOM Event To connect a function to a DOM event with Dojo, you first need to
get the node that you want to connect to. Here, I'll use the venerable dojo.byId. To summarize how things have been since dojo 0.1/0.2 time.... firstLinkNode = dojo.byId("firstLink"); Now, to fire foo when a user clicks #firstLink, and I have the node, so I just need to use dojo.connect for the heavy lifting. firstLinkConnections = []; firstLinkConnections[0] = dojo.connect(firstLinkNode, 'onclick', foo) In this example, I passed dojo.connect the object I want my function to listen to (in this case, a DOM node), the name of the function that should trigger my function's call (in this case, the "onclick" event), and the name of my function. Note that I keep a reference to the connection by setting firstLinkConnections[0] to the return value of dojo.connect. This will allow me to disconnect the listener later, if I desire. Now, when a user clicks "Dojo," a message appears in the log Because my function is global in scope, I can pass it directly to connect. The following, however, are equivalent: firstLinkConnections[0] = dojo.connect(firstLinkNode, 'onclick', null, foo);
and firstLinkConnections[0] = dojo.connect(firstLinkNode, 'onclick', null, "foo");
Now, if I also want to connect someObject.bar() to #firstLink, I can do that. firstLinkConnections[1] = dojo.connect(firstLinkNode, 'onclick', someObject, "bar");
Because I've used Dojo's event handling, I can connect an arbitrary number of functions to fire on an event. A note about the event names: In most cases, event names now are lower case, except in special cases (e.g., some Mozilla DOM events). Dojo will add "on" to your event name if you leave it off (e.g., 'click' and 'onclick' are the same thing to dojo). Dojo responds to all of the usual events (e.g., onclick, onmouseover, etc.) and the onkeypress event for capturing typing. A note about return values: Any value returned by a function called by dojo.connect will be lost. Connecting Functions to One AnotherConnecting functions to one another is even simpler than connecting them to DOM events; because you already have a reference to the function, you don't need to do any byId or query work. To have anotherObject.afterBaz fire after someObject.baz fires, use the following: objectConnections = [];
objectConnections[0] = dojo.connect(someObject, "baz", anotherObject, "afterBaz"); In the above code, the first argument is the context of "baz," the second argument is the event (in this case, when baz fires), the third argument is the context of your listener function, and the fourth argument is the listener function itself. Connecting two global functions is even easier: objectConnections[1] = dojo.connect(foo, globalGuy);
Now, whenever foo is called, globalGuy will also fire. As you might expect, connecting a method to a global function, or vice versa, is logical and simple: objectConnections[2] = dojo.connect(foo, anotherObject, "afterBaz");
objectConnections[3] = dojo.connect(someObject, "baz", globalGuy); DisconnectingTo disconnect listeners from events, you simply pass the connection handle (the return value of dojo.connect to dojo.disconnect. To disconnect globalGuy from someObject.baz, I use the following code:dojo.disconnect(objectConnections[3]); Event ObjectSubmitted by MattBowen on Tue, 06/05/2007 - 18:33.
When you connect a function to a DOM event with dojo.connect, dojo passes your function a normalized event object. This means that, regardless of the client's browser, you can count on a set of standard attributes about the event and a set of methods to manipulate the event. SyntaxAssume that your function has been called by dojo.connect and takes an argument named event Dojo provides the following attributes with an event object:
Dojo provides the following methods with an event object:
Additionally, dojo.stopEvent(event) will prevent both default behavior any any propagation (bubbling) of an event. Example Code for Reference<head>
<title>Dojo Events are Great</title> <script type="text/javascript" src="http://o.aolcdn.com/dojo/1.0.0/dojo/dojo.xd.js"></script> <script type="text/javascript"> function echo(event) { key = event.charCode; console.debug(event.charCode); } function foo(event) { dojo.stopEvent(event); console.debug("The link was clicked"); } dojo.addOnLoad(function() { interactiveNode = dojo.byId("interactive"); linkNode = dojo.byId("link"); dojo.connect(interactiveNode, 'onkeypress', echo); dojo.connect(linkNode, 'onclick', foo); }); </script> <body> <a href="http://dojotoolkit.org" id="link">Dojo</a> is great. <form> <label for="infield"> Type some text: </label> <input id="interactive" type="text" name="infield"> </form> </body> Using a Dojo Event ObjectIn the example code, we have two functions that are connected to two different events. Echo sends the key code of any key typed in the text input field to the console. It does so by using the charCode property of the normalized event object. Foo is connected to the #link and cause it to send "The link was clicked" to the console instead of changing the browser's location; by using the preventDefault method of the normalized event object, connections to change the default behavior of DOM objects. Now, imagine that you want to detect for the down arrow key in the text box. To do this, we just need to attach a new event listener to the text box and check to see if each keycode is the keycode for the down arrow. And how do you know what the keycode for the down arrow is, you may ask? Well, Dojo provides constants for every non-alpha-numeric key [[link to sub page to come]]. In our case, we are interested in dojo.keys.DOWN_ARROW. So, assuming that you want to just log when the down arrow is pressed, the following code should do the job: dojo.connect(interactiveNode, 'onkeypress', function (evt) { key = evt.keyCode; if(key == dojo.keys.DOWN_ARROW) { console.debug("The user pressed the down arrow!"); } }); dojo.addOnLoad starts your scripts after the DOM has loaded but before all of the page elements have loaded. Acting in parallel to dojo.addOnLoad is dojo.addOnUnload , which runs functions when the page is being "unloaded" (e.g., when the user clicks a link off of the current page). This gives you the opportunity to send notifications to your web application or clean up unavoidable memory leaks. DOJO Programming 4 - Events - Call a Function DOJO AJAX
Many programming tutorials contain a "Hello, World!" example, so it seems appropriate to have one for Dojo XHR. In this example, your web page will fetch a snippet of content via XHR and attach it directly to your page. To setup the example:
Example 1. Hello, Ajax world! <html>
Passing Data with JSONSubmitted by dante on Mon, 04/30/2007 - 23:39.
JSON, or Javascript Object Notation, is a lightweight data interchange standard. It can, in theory, be used to pass data between any two programming languages, but it has special advantages when used with Javascript. JSON is fundementally just the Javascript array and object initializer syntax on its own. So this array of objects in a Javascript program: var cobblers = [
{"filling": "peach", "timeToBake": 30 }, {"filling": "cherry", "timeToBake": 35 }, {"filling": "blueberry", "timeToBake": 30} ]; Roughly everything after the "=" is JSON. Here's what the JSON packet would look like coming back from a web service: { "cobblers": [
{"filling": "peach", "timeToBake": 30 }, {"filling": "cherry", "timeToBake": 35 }, {"filling": "blueberry", "timeToBake": 30} ] } "Excuse me," you might say, "but we already have a data interchange format. You might have heard of it ... it's called XML." So why not just pass it as: <cobblers>
<cobbler filling="peach" timeToBake="30" /> </cobblers> The answer is performance, performance, performance! JSON data is parsed up to 100 times faster than XML. That makes sense because the parser is just eval(). For small portions of data, this doesn't mean much, but for large ones it's indispensible. XML expressed in Javascript must carry the full weight of XML - including namespaces, DTD's and schemas. Furthermore, the DOM representation of XML is much more memory-intensive than native Javascript. Add to that the fact that XML is interpreted a little differently in each browser, and JSON is the preferred method for data interchange in dojo. XML is supported, but you might not want to use it in simple scenarios. Where it really begins to make sense, however, is when large scale transformations are needed on the client side. Almost every modern browser today provides a client-side XSLT transform facility which can often outstrip JSON for speed in transforming large data sets from one structure to another since that transformation is handled in C or C++ and not in JavaScript. Whether your app chooses to use JSON or XML is often a foregone conclusion, but be aware that there are tradeoffs for each. Accepting JSON Data in dojo.xhrGetProvided your web service sends JSON (as the above example shows) Dojo pretty much handles the rest for you, including parsing the JSON into a JavaScript object. All you have to do is specify a JSON content handler: dojo.xhrGet( { // The following URL must match that used to test the server. url: "http://server/ajax.txt", handleAs: "json", load: function(responseObject, ioArgs) { // Now you can just use the object console.dir(responseObject); // Dump it to the console console.dir(responseObject.cobblers[0].filling); // Prints "peach" return responseObject; } // More properties for xhrGet... }); Errors and TimeoutsSubmitted by jchimene on Tue, 06/05/2007 - 18:44.
Regular web requests and Ajax requests with dojo.xhrGet/Post are much alike. Both use URL's and both use the HTTP protocol. But with browser requests, it is always clear to user when something goes wrong. You may get a 404 - Page Not Found, or a Server Unavailable, or at least something that says "Error". Ajax requests happen in the background, so when they error out the user won't know. Even worse, if the response never comes the browser may appear to lock up. That's why it's extremely important to provide an error handler and a timeout handler with any dojo.xhrGet/Post calls. You should consider these as critical as URL or the load function At the very least, you should alert the user that something went wrong. Here's an example: dojo.xhrGet({
url: "/cgi-bin/timeout.cgi", load: function(data){ document.myForm.myBox.value = data; dojo.byId("boxLoadTime").innerHTML = new Date(); }, error: function(err){ console.debug("Holy Bomb Box, Batman! An error occurred: ", err); }, timeout: 2000 }); The error() function takes the same arguments that load() does. But unlike load(), the only useful parameter is data, which contains the error message. You can also find out what kind of error was generated by looking at the error object's "dojoType" property. It will usually be "timeout" or "cancel", but other error types are possible. The timeout, given in milliseconds, defaults to 0, which means "wait forever". Even if you expect the request will take a long time, you should set a high value here (e.g. 15000 = 15 seconds), not 0. DOJO AJAX Tutorial - Cenni su Json DOJO LOG
Method 1: LoggingThe first method is logging, and if you've used modern logging tools like log4j you'll find it familiar. The idea is to write trace messages to a log which you can then use to find variable values or the last executed bit of code. Why not just use alert() ? The trusty JavaScript alert() is a favorite debugging tool, but it suffers from the following problems:
Clearly alert's just not powerful enough. In Dojo logging, you can associate messages with severity, just like in log4j. The following code illustrates the five severity levels: console.log("Nothing happening");
console.debug("Checking to make sure nothing happened"); console.info("Something might happen."); console.warn("Something happened, but it's no big deal."); console.error("Cough cough!"); In the Firebug console, the messages will appear like this:
In IE, they will appear like this:
Another useful method, console.dir() dumps variable contents to the screen. While console.log works fine for strings and integers, console.dir prints more complex variables - objects, arrays, arrays of objects, or whatever. For example: console.dir([
{attribute: "last_name", sortDescending: true}, {attribute: "last_name", sortDescending: true} ]); produces:
So in our example above, we write: console.debug("dojo.newWidth is" + dojo.newWidth);
this.domNode.style.width = dojo.newWidth; Running this, we quickly find that dojo.newWidth is undefined. Maybe we spelled it wrong? To quickly find out, we change the debugging statement to: console.dir("dojo is" + dojo);
this.domNode.style.width = dojo.newWidth; Nope, there's no property in dojo that looks like newWidth. Finally, we spot our error and change the right hand side to "newWidth." Case closed. Method 2: The "debugger" StatementAlternatively you can set a "poor person's breakpoint" in the code. Just insert the debugger; statement, which is a legal JavaScript reserved word. debugger;
this.domNode.style.width = dojo.newWidth; This statement stops the code and brings you to a Firebug command prompt. It appears the code has stopped at ... huh?
That's a side effect of running dojo/event code. The breakpoints don't seem correct at all. But just click the Console tab and now you can examine variables or execute just about any JavaScript you want. In this case, we look at the dojo.newWidth property, which has nothing in it. But "dojo" does and we examine it by console.dir(dojo). Basically all the logging features of method 1 are available to type here.
To Follow The dojo.require Trail, Use Dojo LocallySince that code is now running, we try a minor variant which sets the button to blue: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <title>Fix me!</title> <style type="text/css"> @import "http://o.aolcdn.com/dojo/1.0.0/dijit/themes/tundra/tundra.css"; @import "http://o.aolcdn.com/dojo/1.0.0/dojo/resources/dojo.css" </style> <script type="text/javascript" src="http://o.aolcdn.com/dojo/1.0.0/dojo/dojo.xd.js" djConfig="parseOnLoad: true"></script> <script type="text/javascript"> dojo.require("dojo.parser"); dojo.require("dijit.form.Button"); </script> </head> <body class="tundra"> <div dojoType="dijit.form.Button"> Click to break! <script type="dojo/event" event="onClick"> this.domNode.style.backgroundColor = dojo.Color.named.aliceblue; </script> </div> </html> You check the console ... no errors there. But that dojo.Color.named.aliceblue is a little questionable. You know that dojo.colors needs to be included, but you thought dijit.form.Button already did that. You can find out for sure by using a local copy of Dojo. CDN Dojo is very quiet about the modules it loads. Local Dojo is very noisy. So, assuming our local copy of Dojo is installed on the web server underneath /dojoroot, the following change: <style type="text/css">
@import "http://o.aolcdn.com/dojo/1.0.0/dijit/themes/tundra/tundra.css"; @import "http://o.aolcdn.com/dojo/1.0.0/dojo/resources/dojo.css" </style> <script type="text/javascript" src="http://o.aolcdn.com/dojo/1.0.0/dojo/dojo.xd.js" djConfig="parseOnLoad: true"></script> Yields the following on the console
You see every Dojo Core and Dijit Component loaded. Sure enough, dojo.colors is not in the list, so we add a dojo.require statement That Doesn't Look Right ... DOM InspectionUnfortunately, that doesn't fix the problem either. When styling errors occur, it's a good time to use Firebug's DOM Inspector. You can think of it as View Source on steroids.
So we click Inspect and point at the screen button
The right-hand side of the console tells what styles and style rules are applied to this class. Crossed-off lines are styles that have been overriden. Very nice! Debugging External Classes With debugAtAllCostsdojo/method and dojo/event scripts are good for short, non-reusable snippets of code. But when you start building reusable components, you'll be storing your code into Dojo-declared classes instead. The good news is the more you make this switch, the easier your debugging task will be. So here's a piece of HTML code and a reusable Dojo-based widget: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <title>Goolica Tax Form</title> <style type="text/css"> @import "/dojoroot/dijit/themes/tundra/tundra.css"; @import "/dojoroot/dojo/resources/dojo.css" </style> <script type="text/javascript" src="/dojoroot/dojo/dojo.js" djConfig="parseOnLoad: true"></script> <script type="text/javascript"> dojo.require("dojo.parser"); dojo.require("dojobook.online-book.debugging.BuggyWidget"); </script> </head> <body class="tundra"> <div dojoType="dojobook.online-book.debugging.BuggyWidget"></div> </body> </html> dojo.provide("dojobook.online-book.debugging.BuggyWidget");
dojo.require("dijit._Widget"); dojo.declare( "dojobook.online-book.debugging.BuggyWidget", [dijit._Widget], { postCreate: function() { dojo.nonExistentMethod(); } }); Running this code, you will see an error appear, but it's nowhere near the right location: But by simply setting the debugAtAllCosts flag to true: <script type="text/javascript" src="/dojoroot/dojo/dojo.js"
djConfig="parseOnLoad: true, debugAtAllCosts: true"></script> the displayed error location will now be correct:
Important! you should always remove debugAtAllCosts from production code. It slows down the client unnecessarily. Rather than manually inserting and removing them, I like to delegate that job to a server side language like PHP: <?php $djConfig = $inProduction ? "parseOnLoad: true" : "parseOnLoad: true, debugAtAllCosts: true"; $loadLocation = $inProduction ? "http://o.aolcdn.com/dojo/1.0.0" : "/dojoroot"; $useXd = $inProduction ? ".xd" : ""; ?> <style type="text/css"> @import "<?= $loadLocation ?>/dijit/themes/tundra/tundra.css"; @import "<?= $loadLocation ?>/dojo/resources/dojo.css" </style> <script type="text/javascript" src="<?= $loadLocation ?>/dojo/dojo<?= $useXd ?>.js" djConfig="<?= $djConfig ?>"></script> DOJO sistema di log simile log4j DOJO Callback
In Java you can define classes anonymously, on-the-fly, right in the middle of a method call. You can do that in Javascript too. Simply define the function in the parameter list and omit the name. For example, instead of defining and passing a new function: function myTwoParameterFn(a, b) { return max(a, -b); } console.debug(myTwoParameterFn(1, 2, Math.max)); We can shorten it to: console.debug(myTwoParameterFn( 1, 2, function(a,b){ return max(a, -b) } )); This makes from some pretty strange syntax, especially if the anonymous function is large. But callbacks are often specified this way when calling dojo functions. in Dojo le callback sono strutturate come funzioni innestate in altre funzioni Snippet
<!--A HEAD snippet which loads the style sheet and Dojo libraries, then calls functions to load individual dijit types.-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <head> <title>Events</title> <script type="text/javascript" src="dojoroot/dojo/dojo.js"></script> <script type="text/javascript"> function echo(event) { key = event.charCode;//object Event console.debug(event.charCode);//object event } function foo(event) { dojo.stopEvent(event); console.debug("The link was clicked"); } dojo.addOnLoad(function() { interactiveNode = dojo.byId("interactive"); linkNode = dojo.byId("link"); dojo.connect(interactiveNode, 'onkeypress', echo); dojo.connect(linkNode, 'onclick', foo); }); </script> <body> <a href="http://dojotoolkit.org" id="link">Dojo</a> is great. <form> <label for="infield"> Type some text: </label> <input id="interactive" type="text" name="infield"> </form> </body> </html> DOJO Eventi e utilizzo di event object DOJO - Simple Ajax
<!--A HEAD snippet which loads the style sheet and Dojo libraries, then calls functions to load individual dijit types.--> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <head> <title>Prova di chiamata a server</title> <style type="text/css"> @import "dojoroot/dijit/themes/tundra/tundra.css"; @import "dojoroot/dojo/resources/dojo.css" </style> <script type="text/javascript" src="dojoroot/dojo/dojo.js" djConfig="parseOnLoad: true"> </script> <script type="text/javascript"> dojo.require("dijit.form.Button"); </script> <!--The two arguments to the functions (data, and ioArgs) are important --> <!-- don't leave any of them out! The first argument (data) contains the --> <!-- data sent back from the server, whilst the second argument --> <!-- contains a Dojo I/O Bind object.--> <script> function helloCallback(data,ioArgs) { alert(data); } function helloError(data, ioArgs) { alert('Error when retrieving data from the server!'); } </script> </head> <body class="tundra"> <button dojoType="dijit.form.Button" id="servletButton">Hello Servlet! <script type="dojo/method" event="onClick"> dojo.xhrGet({ url: 'Start', load: helloCallback, error: helloError }); </script> </button> <!--This property - content - allows the programmer --> <!--to send arbitary values to the server as parameters.--> <!--In this case, since we are using the default method --> <!--of dojo.io.bind which is GET, the server side script --> <!--will have the value of the textbox available --> <!--to it as a the GET parameter 'name'--> <!--va bene anche post basta che cambio la funzione dojo.xhrPost--> <button dojoType="dijit.form.Button" id="helloJSP">Hello JSP! <script type="dojo/method" event="onClick"> dojo.xhrGet({ url: 'HelloWorldResponseGET.jsp', load: helloCallback, error: helloError, content: {name: dojo.byId('name').value } }); </script> </button> Please enter your name: <input type="text" id="name"> </body> </html> DOJO Esempio Base di una chiamata Ajax DOJO
<!--A HEAD snippet which loads the style sheet and Dojo libraries, then calls functions to load individual dijit types.--> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <head> <title>Taxes, The Surest Thing Next to Death!</title> <style type="text/css"> @import "dojoroot/dijit/themes/tundra/tundra.css"; @import "dojoroot/dojo/resources/dojo.css" </style> <script type="text/javascript" src="dojoroot/dojo/dojo.js" djConfig="parseOnLoad: true"></script> <script type="text/javascript"> dojo.require("dijit.form.Button"); dojo.require("dijit.form.DateTextBox"); dojo.require("dijit.form.TextBox"); dojo.require("dijit.form.ComboBox"); dojo.require("dijit.form.CheckBox"); dojo.require("dijit.TitlePane"); dojo.require("dijit.form.CurrencyTextBox"); </script> </head> <!--A class to the BODY tag specifying the name of your theme. In our examples, we'll use the "Tundra" theme.--> <body class="tundra"> <!--<body class="a11y"> per visione ad alto contrasto--> <button dojoType="dijit.form.Button" id="helloButton">Hello World! <!-- metodi Dojo all'interno del bottone, posso gestire anche eventi come pressione tasti. I metodi vanno bene per tutti i Browser--> <script type="dojo/method" event="onClick"> alert('You pressed the button'); </script> </button> <br> <img src="symbol_help.gif" id="helpIncome"/> <div dojoType="dijit.Tooltip" style="display:none" connectId="helpIncome"> Agente <b>Bauer</b>: c'è un emergenza in corso! </div> <!--Dijit introduces a new attribute "dojoType". You simply add that to the tag you wish to "dijit-ize".--> <!--We use the dojoTypes dijit.form.TextBox and dijit.form.Checkbox.--> <form> First Name: <input type="text" size="20" name="first" dojoType="dijit.form.TextBox" trim="true" propercase="true" / > <br> Last Name: <input type="text" size="20" name="last" dojoType="dijit.form.TextBox" trim="true" propercase="true" /> <br> Email Address: <input type="text" length="20" name="email" dojoType="dijit.form.TextBox" lowercase="true" /> <br> Filing Date: <input type="text" length="10" name="filingDate" dojoType="dijit.form.DateTextBox" /><br> <select name="plop.combo" dojoType="dijit.form.ComboBox"> <option value="one">one</option> <option value="two">two</option> <option value="three">three</option> </select><br> <hr> <ol> <li>Please Enter Your 2007 Gross Income <!--<input type="text" length="10" name="grossIncome" dojoType="dijit.form.TextBox"/></li>--> <input type="text" maxlength="12" class="fillwidth currency" id="grossincome" name="grossincome" value="0.00" dojoType="dijit.form.CurrencyTextBox" required="true" onChange="updateTotals()" currency="USD"/> <li>Please enter the value from line 1. This is your <em>2007 tax</em> <input type="text" length="10" name="tax" dojoType="dijit.form.TextBox" /></li> <li>Would you like to contribute an extra $3 to the Presidential Campaign Fund? <input type="checkbox" name="campaign" value="Y" dojoType="dijit.form.CheckBox" /></li> </ol> <div dojoType="dijit.TitlePane" open="false" title="Directions (click to Expand)" style="width:300px;height:170px"> Proin risus. Nullam rhoncus purus id turpis. Praesent aliquam adipiscing ligula. Aenean lorem ante, accumsan quis, elementum id, cursus eu, lorem. Fusce viverra. Ut tempor nisi at ipsum. Etiam sed nibh. </div> </body> </html> File di esempio con configurazione base e semplici widgets |