211 2 3MB
English Pages 316 [336] Year 2008
Dojo
This page intentionally left blank
Dojo Using the Dojo JavaScript Library to Build Ajax Applications
James E. Harmon
Upper Saddle River, NJ • Boston • Indianapolis • San Francisco New York • Toronto • Montreal • London • Munich • Paris • Madrid Cape Town • Sydney • Tokyo • Singapore • Mexico City
Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Where those designations appear in this book, and the publisher was aware of a trademark claim, the designations have been printed with initial capital letters or in all capitals. The author and publisher have taken care in the preparation of this book, but make no expressed or implied warranty of any kind and assume no responsibility for errors or omissions. No liability is assumed for incidental or consequential damages in connection with or arising out of the use of the information or programs contained herein. The publisher offers excellent discounts on this book when ordered in quantity for bulk purchases or special sales, which may include electronic versions and/or custom covers and content particular to your business, training goals, marketing focus, and branding interests. For more information, please contact: U.S. Corporate and Government Sales (800) 382-3419 [email protected] For sales outside the United States please contact: International Sales [email protected] Visit us on the Web: www.informit.com/aw Library of Congress Cataloging-in-Publication Data Harmon, James Earl. Using the Dojo Javascript library to build Ajax applications / James Earl Harmon. p. cm. Includes index. ISBN 0-13-235804-2 (pbk. : alk. paper) 1. Ajax (Web site development technology) 2. Java (Computer program language) I. Title. TK5105.8885.A52H37 2008 006.7’8—dc22 2008021544 Copyright © 2009 Pearson Education, Inc. All rights reserved. Printed in the United States of America. This publication is protected by copyright, and permission must be obtained from the publisher prior to any prohibited reproduction, storage in a retrieval system, or transmission in any form or by any means, electronic, mechanical, photocopying, recording, or likewise. For information regarding permissions, write to: Pearson Education, Inc Rights and Contracts Department 501 Boylston Street, Suite 900 Boston, MA 02116 Fax (617) 671 3447 ISBN-13: 978-0-132-35804-0 ISBN-10: 0-132-35804-2 Text printed in the United States on recycled paper at R.R. Donnelley in Crawfordsville, Indiana. First printing June 2008
Associate Publisher Mark Taub Acquisitions Editor Debra Williams Cauley Development Editor Michael Thurston Managing Editor Kristy Hart Project Editor Chelsey Marti Copy Editor Language Logistics Indexer Lisa Stumpf Proofreader Kathy Ruiz Technical Reviewer Eric Foster-Johnson Publishing Coordinator Kim Boedigheimer Cover Designer Gary Adair Senior Compositor Gloria Schurick
This Book Is Safari Enabled The Safari®Enabled icon on the cover of your favorite technology book means the book is available through Safari Bookshelf. When you buy this book, you get free access to the online edition for 45 days. Safari Bookshelf is an electronic reference library that lets you easily search thousands of technical books, find code samples, download chapters, and access technical information whenever and wherever you need it. To gain 45-day Safari Enabled access to this book: n Go to http://www.informit.com/onlineedition n Complete the brief registration form n Enter the coupon code JBKT-NKCJ-BJ2U-RSIN-7TC8 If you have difficulty registering on Safari Bookshelf or accessing the online edition, please e-mail [email protected].
❖
With Love to My Family: Sonia, Phoebe, and Nathan ❖
Contents at a Glance Foreword
xiii
Acknowledgments About the Author
xv xvi
I: A Dojo Tutorial 1 Understanding Dojo: A Tutorial
3
2 Using Dojo for Client-side Validation 3 Using Dojo to Work with the Server 4 Using Dojo Widgets
25 35
51
5 Processing Forms with Dojo
59
II: Dojo Widgets 6 Introduction to Dojo Widgets 7 Dojo Form Widgets
67
91
8 Dojo Layout Widgets
137
9 Other Specialized Dojo Widgets
155
III: Dojo in Detail 10 What Is Dojo?
189
11 Technical Description of Dojo 12 Objects and Classes 13 Strings and JSON
223
239
14 Events and Event Handling 15 Ajax Remoting
259
16 Working with the DOM
277
17 Testing and Debugging
293
Index
303
199
249
Table of Contents Foreword
xiii
Acknowledgments
xv
About the Author
xvi
I: A Dojo Tutorial 1 Understanding Dojo: A Tutorial
3
1.1 Introduction to the Tutorial
3
1.1.1 Goals for this Tutorial
4
1.1.2 Goals for Using Dojo
4
1.2 A Standard HTML Data Entry Form 1.2.1 First and Last Name 1.2.2 User Name
1.2.5 State 1.2.6 City
6
7
1.2.3 Email Address 1.2.4 Address
5
8
8 8
10
1.2.7 Zip Code
10
1.2.8 Service Date 1.2.9 Comments
11 11
1.3 The Plan for Enhancing the Form 1.3.1 Including Dojo in the Form
12 12
1.3.2 Adding Client-side Validation
13
1.3.3 Adding Server-side Features
13
1.3.4 Using Additional Specialized Dojo Widgets 1.3.5 Processing the Form
14
1.4 Getting and Running the Source Code 1.5 Tutorial Step 1—Including Dojo
14
15
1.5.1 Download or Create the Source Files
15
1.5.2 Include the Code for the Dojo Toolkit
19
1.5.3 Include Dojo Style Sheets
20
1.5.4 Review All the Code Changes 1.5.5 Run the New Page
22
21
13
viii
Contents
2 Using Dojo for Client-side Validation 2.1 Validating Form Fields
25
25
2.2 Tutorial Step 2—Adding Client-side Validation 2.2.1 Validate the First Name Field
27
2.2.2 Validating the Last Name Field
30
2.2.3 Validating the User Name Field
31
2.2.4 Validating the Email Address Field 2.2.5 Validating the Address Field 2.2.6 Validating the City Field
26
31
32
33
2.2.7 Validating the Zip Code Field
33
3 Using Dojo to Work with the Server 3.1 Adding Server-side Features
35
35
3.2 Tutorial Step 3a—Adding Server-side Validation 3.2.1 Assign Event Handler Function 3.2.2 Make a Call to the Server
36
36
38
3.3 Tutorial Step 3b—Retrieving Data from the Server 43 3.3.1 Select Appropriate Widget for the City Field 43 3.3.2 Get the Value of State and Send to the Server 45
4 Using Dojo Widgets
51
4.1 Adding Dojo Widgets to the Page
51
4.1.1 Dijit—The Dojo Widget Module
52
4.2 Tutorial Step 4—Using Dojo Widgets
52
4.2.1 Use the Dojo DateTextBox Widget
53
4.2.2 Use the Dojo Rich Text Editor Widget
5 Processing Forms with Dojo
55
59
5.1 Using Dojo to Process Forms
59
5.2 Tutorial Step 5—Processing the Form 5.2.1 Creating a Dojo Form Widget 5.2.2 Intercept Form Submission
60
60 61
5.2.3 Check That All Form Elements Are Valid 5.2.4 Submitting the Form to the Server
63
62
Contents
II: Dojo Widgets 6 Introduction to Dojo Widgets 6.1 What Are Widgets?
67
67
6.2 What Are Dojo Widgets?
68
6.3 Components of a Dojo Widget 6.3.1 Widget HTML
70
6.3.2 Widget Styles
74
70
6.3.3 JavaScript Component of a Widget 6.3.4 Dojo Widget Hierarchy
78
6.3.5 Visual Overview of Dojo Widgets 6.3.6 Building Your Own Widgets
7 Dojo Form Widgets
76 83
90
91
7.1 Standard Forms and Dojo Form Widgets 7.1.1 The dijit.form._FormWidget Class 7.2 The Dojo Form Widget Explained
8 Dojo Layout Widgets
91 92
94
137
8.1 Understanding Page Layout
137
8.1.1 The dijit.layout._LayoutWidget Class 8.2 Explanation of Dojo Layout Widgets
9 Other Specialized Dojo Widgets 9.1 What Are Specialized Widgets? 9.2 Menu Widget
155 155
156
9.2.1 dijit.Menu
157
9.2.2 dijit.MenuItem
157
9.2.3 dijit.MenuSeparator 9.2.4 dijit.PopupMenuItem
157 158
III: Dojo in Detail 10 What Is Dojo?
189
10.1 History of JavaScript and AJAX 10.2 History of Dojo 10.3 Purpose of Dojo
191 191
189
138 139
ix
x
Contents
10.4 Description of Dojo
192
10.5 What Problems Does Dojo Solve? 10.6 Who Should Use Dojo? 10.7 Licensing
193
194
195
10.8 Competitors and Alternatives 10.9 The Future of Dojo
195
197
11 Technical Description of Dojo
199
11.1 What You Get in the Dojo Download 11.2 Organization of Dojo Source Code 11.2.1 First-level Directories
199 201
201
11.2.2 Digging Deeper into the Dojo Directory 11.3 Dojo Modules and Features
11.3.1 Naming Conventions and Name Space 11.3.2 Dojo Base Module
205
11.3.3 Dojo Core Modules
217
12 Objects and Classes
223
12.1.1 Creating Objects 12.1.2 Encapsulation
224 224
12.1.3 Object Templates
225
12.1.4 JavaScript Prototypes
227
12.2 Using Dojo to Work with Objects
228
12.2.1 Dojo Function: dojo.declare
229
229
12.3.1 Superclasses and Inheritance 12.3.2 API for dojo.declare 12.3.3 Other Dojo Functions
231
231 233
12.3.4 Object Graphs and Dot Notation
13 Strings and JSON 13.1 Text Strings
204
223
12.1 Objects Explained
12.3 Defining a Class
202
203
234
239 239
13.1.1 Dojo Function: dojo.string.pad
240
13.1.2 Usage Example for dojo.string.pad 13.1.3 Dojo Function: dojo.string.substitute
241 241
13.1.4 Usage Example for dojo.string.substitute
243
Contents
13.2 JSON
244
13.2.1 Dojo Function: dojo.toJson
246
13.2.2 Usage Example for dojo.toJson 13.2.3 Dojo Function: dojo.fromJson
14 Events and Event Handling
249
14.1 Description of the Event Model 14.1.1 What Are Events?
246 247
249
250
14.1.2 Additional Dojo Events
251
14.2 Defining and Assigning Event Handlers
252
14.2.1 Using dojo.connect to Assign Event Handlers 252 14.2.2 Usage Example for Assigning Event Handlers 253 14.3 Representing an Event as an Object
254
14.4 Using Aspect Oriented Programming in Dojo
15 Ajax Remoting 15.1 Remoting
259 259
15.2 Review of XMLHttpRequest (or XHR for Short) 15.2 The dojo.xhrGet Function 15.3.1 Parameters in Detail 15.4 dojo.xhrPost
261 264
264
15.4.1 Usage Example—Error Handling 15.5 Working with Forms
268
269
15.5.1 Dojo Function dojo.formToObject 15.5.2 Dojo Function dojo.objectToQuery 15.5.3 Dojo Function dojo.formToQuery
271 274
15.5.5 Dojo Function dojo.queryToObject
16 Working with the DOM
270 272
15.5.4 Dojo Function dojo.formToJson
274
277
16.1 Finding Needles in the DOM Haystack 16.2 Dojo Query
256
277
278
16.2.1 CSS Selectors
279
16.2.2 Using Selectors in dojo.query 16.2.3 Using DOM Elements Found by dojo.query 283
282
260
xi
xii
Contents
16.3 Animation
283
16.3.1 Understanding Animation 16.3.2 Dojo Animation Function
283 285
16.3.3 Standard Animation Effects
17 Testing and Debugging 17.1 Testing
286
293
293
17.1.1 Unit Testing
294
17.1.2 DOH—The Dojo Unit Testing Framework 17.1.3 Other Types of Testing 17.2 Logging
298
17.2.1 Basic Logging
299
17.2.2 Advanced Logging
Index
303
300
298
294
Foreword
If there is one lesson to be learned from the Dojo Toolkit, it is “Be careful what you wish for!”When we first started Dojo, we had the modest goal of creating a JavaScript toolkit that would be useful and would prevent expert JavaScript developers from having to reinvent the wheel.With the buzz and excitement that would soon follow with the emergence of the term Ajax, we quickly found ourselves as the creators of a toolkit used by thousands and thousands of developers and millions of users in a very short time. In the case of any project or company that grows much faster than expected, there are growing pains along the way. It has taken Dojo nearly 18 months to address and solve most of the issues caused by its rapid success: performance, comprehension, ease of use, and documentation. Open source projects are notoriously bad at both marketing and documentation, and Dojo was initially no exception to the rule.With each release from Dojo 0.9 to 1.1 and beyond, documentation and API viewing tools have improved significantly and are now something we’re proud to have rather than being a blemish to the project. Above and beyond source code documentation, demos, and great examples is the need for great books.When learning something new, the most difficult things to learn are usually the questions you don’t know how to ask.The vernacular and philosophy of Dojo is very powerful and efficient but often leaves developers new to Dojo not knowing where to get started. Dojo in particular and Ajax in general also have the learning curve of basically needing to understand a wide range of technologies, from server-side programming languages to JavaScript, CSS, HTML, and the DOM, plus the browser quirks and inconsistencies across each.Toolkits such as Dojo go to great lengths to rescue developers from the most common and egregious of these issues, but developers creating something new will inevitably run into trouble along the way. There are numerous opportunities for developers and users of Dojo to solve their problems and get up to speed, from reading this book to online community support, and the commercial support provided by companies such as SitePen. Dojo has thrived and succeeded because of its transparent and open development process. All code is licensed under the AFL and BSD, licenses which are focused on adoption rather than control. Contributions have been received from hundreds of individuals and from companies such as AOL, Google, IBM, Nexaweb, Renkoo, SitePen, Sun,WaveMaker, and many more.We have a strict but low-barrier contribution policy that requires all source code contributions to be made through a Contributor License Agreement, ensuring that usage of Dojo will not cause legal or IP headaches now or in the future.
And we innovate and experiment more than any other toolkit, introducing features in DojoX that are far ahead of other toolkits. I first met James Harmon at a conference when he was giving a talk about Dojo.The great thing about James’ approach was that he did an amazing job of simplifying the message. Alex Russell and I have a tendency to beat people over the head with every feature and every possibility, whereas James was able to distill complex topics down to easy-to-follow concepts that help people quickly get up to speed with Dojo. This book takes the same simple approach of clearly explaining how to create web applications and web sites with Dojo in a manner that should make it easy, even for developers who are not JavaScript experts, to quickly get up to speed and become effective with the Dojo Toolkit. Dylan Schiemann CEO, SitePen Cofounder, Dojo Toolkit
Acknowledgments
It seems like a ridiculous conceit to put only my name on the cover of the book. I've learned that “it takes a village” to write a book and I'd like to acknowledge some of the members of my village who have been so helpful with their time and encouragement. First, thanks to my editor, Debra Williams Cauley, who began by not taking “no” for an answer (in the nicest way, of course) and continued by expertly guiding me through the process. Also, thanks to Debra's team at Prentice-Hall, including those I worked with directly, Chelsey Marti, Chrissy White, Michael Thurston, and all those who toiled behind the scenes to get this book into the reader's hands. Eric Foster-Johnson also provided invaluable suggestions to the text. No book on Dojo would have been possible without the Dojo Framework itself. Thanks to all who've contributed to the project and provided me with help and support along the way, including Dylan Schiemann, Alex Russell, Karl Tiedt, Adam Peller, Becky Gibson, Sam Foster, Ben Lowery, and James Burke. And to all the other contributors too numerous to mention that have made Dojo the great framework it is. Also thanks to my personal network who gave lots of great advice: Ed Lance,Ted Rafacz, Max Rahder, Steve Meshner, Bob Phifer, and Will Provost.Thanks to my technical idols, Douglas Crockford, Jesse James Garret, and the guys at Ajaxian.com who got me interested in Ajax and JavaScript in the first place. And special thanks to my wonderful wife, Sonia, who helped me carve out the time to write this book. I couldn't have done it without you.Your constant support is always an inspiration to me. I love you.
About the Author
James E. Harmon is the President and Senior Instructor at Object Training Group in Chicago. He is an experienced developer who spent a majority of his career building large scale online applications at Accenture and for several other Web-centric consulting firms. He now specializes in training Java Developers to be more productive by using the latest technologies and frameworks. The book’s web site is http://www.ObjectTrainingGroup.com/dojobook.
I A Dojo Tutorial
1
Understanding Dojo: A Tutorial
2
Using Dojo for Client-Side Validation
3
Using Dojo to Work with the Server
4
Using Dojo Widgets
5
Processing Forms with Dojo
This page intentionally left blank
1 Understanding Dojo: A Tutorial
If you tell me, I’ll soon forget. If you show me, I’ll remember forever. —Chinese Proverb
I
n the spirit of the quote that opens this chapter, I believe that a simple demonstration is one of the best ways to introduce a new technology. So I’m opening this book by providing a tutorial that will use the Dojo Toolkit to enhance a basic HTML form.This chapter introduces the tutorial, which continues through Chapter 5, “Processing Forms with Dojo,” and comprises Part I, “A Dojo Tutorial.”
1.1 Introduction to the Tutorial Imagine that you are a web developer (which is probably not a stretch if you are reading this book) and you are being encouraged to add some Ajax features to a site you’re working on. Maybe the originator of this request is your boss or your boss’s boss, who is not even sure what Ajax is, let alone what kinds of features might be useful. And maybe you’re not sure yourself. Imagine that your prior experience has mostly been on the server-side, developing in Java or some other server-side technology, and your experience with HTML and JavaScript has been fairly limited.This is the scenario we will explore over the next several chapters as you are introduced to the Dojo Toolkit. To further flesh out the scenario, imagine that you’ve heard lots of things about how powerful the JavaScript programming language can be and that there are a number of JavaScript libraries and frameworks that can help you take advantage of that power. You’ve decided to use the Dojo Toolkit because some of the web sites and forums that you frequent to keep up with the ever-changing IT industry have recommended it. And you’ve already selected one of the most frequently used pages in your application to be the first candidate for being “Ajaxified.”
4
Chapter 1
Understanding Dojo: A Tutorial
This tutorial walks you through a number of steps to update the page with Ajax features.We will enhance the page in a number of small ways that each address a specific type of issue. Along the way, we’ll see the kinds of features that Ajax allows us to add to web pages, and we’ll see exactly how to implement those features using the Dojo Toolkit.
1.1.1 Goals for this Tutorial The primary goal of this tutorial is to show you how to use the Dojo Toolkit to introduce some common Ajax features into your web pages.The tutorial provides instructions for picking the low hanging fruit. In other words, it focuses on the features that are fairly easy to implement and yet provide a substantial return in increased usability.This tutorial is not meant to demonstrate every feature of Dojo, nor is it intended to exhaustively cover the features that we implement together.You can think of this tutorial as addressing the first phase of web site enhancement. Another main goal of this tutorial is to implement features in the plainest way. Although most Dojo features can be implemented either declaratively (in HTML markup) or programmatically (using JavaScript), we’ll first focus on the declarative technique given that most web server-side developers are more familiar with HTML markup than with JavaScript. Of course, we will also use some JavaScript as the glue to tie things together.
1.1.2 Goals for Using Dojo What do we hope to achieve by using Dojo? First and foremost, we expect that our pages will be more usable.This might manifest itself in a variety of ways.The page should be faster. It should be better looking. It should be easier to operate by the user. It should help the user enter the required information properly, and the page should be easier to navigate.Yet at the same time, we should not violate any of the user-interface conventions that users have come to expect when accessing web pages.We should make significant usability gains without sacrificing anything that the user already depends on. How do we make these gains in usability? Dojo provides enhancements to the existing HTML form elements that provide additional functionality.These enhancements should make the current form elements behave in more useful ways. Performance can be improved either by making things run faster or by making things appear to run faster.The ideal way to make a process appear faster is to have the process run while the user is doing something else rather than just having him wait for the process to complete. Ajax provides the ideal mechanism to support this technique.We’ll use Dojo to allow a page to make data requests of the server asynchronously while the user is continuing to work.The page will appear to the user to be faster and more responsive. Data validation can be improved by bringing the validation of data closer to the entry of data. Dojo supports the ability to send small validation requests to the server without requiring an entire form to be submitted.When appropriate, we might even want to adopt the desktop application paradigm of validating data on a keystroke by keystroke basis. We also expect our features to be easy to implement.We want to be able to leverage what we know about HTML, and when we use JavaScript, the programming model should
1.2 A Standard HTML Data Entry Form
be consistent and powerful.We expect to write a lot less code than if we were developing the functionality by writing it all ourselves. Less code means less opportunity for error.As you learn Dojo, you can expect that what you learn will continue to be useful as you dig further into Dojo.And when things do become more complex, you will have tools to aid in debugging. In short, you can expect Dojo to provide a great programming environment. Finally, we hope to be constantly surprised by the benefits we derive from using Dojo, obtained without any extra work on our part. For example, we expect that any features we add will work the same regardless of what browser our users are using. And we expect our visual elements to support Web Accessibility and Internationalization standards. We’ve set quite a high bar for Dojo to cross over.We’re asking for a lot and not expecting to sacrifice much to obtain it. Can Dojo really deliver? Let’s find out.We start at the beginning by reviewing the page that will be the basis for our enhancements and identifying the kinds of problems we hope to solve.
1.2 A Standard HTML Data Entry Form We begin by selecting a page from our application that will be the target for our Dojo enhancements (see Figure 1.1).This page comes from a hypothetical Customer Service application for a nation-wide cable company and allows a customer to create an account and to request service.The tutorial is going to be pretty vague about the operations of our “business” because, as you probably guessed, this form is being used to highlight some specific types of functions that many business applications possess. So, if you can suspend your disbelief for a little while, let’s review the form.
Figure 1.1
Standard HTML customer entry form
5
6
Chapter 1
Understanding Dojo: A Tutorial
This page has a very basic design—almost no design at all. It uses only a small bit of styling and is about as plain as you can get.Your pages probably look much better than this, but we start with this minimal design to keep the examples as simple as possible. Let’s walk through each of the fields on this form and discuss the usability problems. A discussion of how Dojo can solve these problems then follows.
1.2.1 First and Last Name The first data entry field is used to hold the customer’s first name. Straightforward enough, yet we already have a problem.The label for the field says “First / Last Name:” and is followed by two text fields for input. Although the user can probably figure out what the page is asking for, it may be more difficult to understand for screen readers, which are used by those with visual impairment.
You could argue that from a usability perspective, this is already a bit confusing. All the other labels on the page refer to a single text box only, while this label refers to two text boxes.When a name is separated into two parts, should the last name be entered before the first name, or the other way round? These are good questions, but we’ll have to wait for the answers. Remember, we’re just identifying the problems now.We look at solutions later in the chapter. Now let’s examine the HTML markup for these fields. First / Last Name:
You might not have used the tag before, but it can be helpful for improving your site’s accessibility for the disabled.The tag is useful to screen readers when the label does not immediately precede the input field, such as when the label is in a different table cell. It also makes it easier to style all the labels with a single style when using Cascading Style Sheets (CSS). Another problem is that only one of the fields has a tag. Both the first name and last name fields are required. However, in our standard form, no JavaScript is being used, so how do we make the fields required? There is no HTML tag or attribute for this, so we’ll depend on the server to do the validation.That means the user won’t know the fields are required until after submitting the form and receiving an error message back from the server. How will the error messages be displayed? Let’s say that the user has entered some data in the form and pressed the “Submit” button.The browser will make a request to the server that will then validate the data and return the form back to the browser along with some error messages. Hopefully the server will also send back the data that the user
1.2 A Standard HTML Data Entry Form
entered so they don’t have to re-enter it. Oftentimes, the error page will display all the error messages near the top of the page.The page with error messages might appear as shown in Figure 1.2.
Figure 1.2
Typical error messages for a form
1.2.2 User Name Our application will allow the user to sign in and manage his or her account, so we’re asking the user to create a user name that will be used for that purpose.We ought to provide him with some guidance for creating a proper name, but that would require us to add quite a bit of text to the page, so we’ve decided not to.The form simply asks for a user name and provides a text field.
The HTML markup for this is quite similar to the “First / Last Name:” fields, just a and tag as shown here. User Name:
We’ve added a little client-side validation by specifying the size=”20” attribute to ensure that the user can’t enter a name longer than 20 characters. A problem with this field involves validation. A user would like to create a short user name that is easy to remember, but because this is also the goal of every other user, it is possible that the name might have already been selected. How is the user notified of this? Again, validation can’t be done until the user submits the page.The server will check the user name to see if it has already been assigned and, if so, will return a page that redisplays the form and shows the error message (along with any additional error messages associated with other fields). It might be helpful also to suggest some alternatives to the user so that he doesn’t keep entering names that have already been taken. These suggestions should be based on the user’s desired user name.
7
8
Chapter 1
Understanding Dojo: A Tutorial
1.2.3 Email Address We’d like to communicate with the user through email, so we’ll ask for an address. A simple text box will be used to let the user enter the email address.
The HTML markup is shown here and is very similar to the other text fields on the page. Email:
Again, we’ve enabled some client-side validation by specifying the size of the field. But is there a way to tell if the email address is valid? There are two types of validation we could try. First, is the email address in the correct format? For instance, does it contain the “@” symbol? Does it end with a TLD such as “.com”? Second, is it an actual working email address? Unfortunately, there is no way to determine the latter without actually creating and sending an email.Though this might be useful for sending the user a password and letting her validate the user name, it is beyond the scope of what we want this page to do. So we’ll just focus on confirming that the email address at least appears to be formatted correctly.
1.2.4 Address We’ll ask for the first line of the user’s home address and use a regular text box to capture it.
The HTML is similar to the previous fields. Address:
This field should contain the first line of the customer’s billing address, so we need to make sure it is entered. It is a required field, but again we’ll have to depend on the server to perform that validation.
1.2.5 State We need the user’s state as part of the billing address. Because there are only a limited number of states, we can use a to provide a pull-down list of states, one of which can be chosen. A typical example of a pull-down list of states is shown in Figure 1.3.
1.2 A Standard HTML Data Entry Form
Figure 1.3
Pull-down list of states
HTML provides the form element, which can be used to supply a list of values. A snippet of the markup necessary to create the field is shown here.
Alabama Alaska American Samoa Arizona ... additional state values not shown ...
Because there is only a small set of values for state, they can all be shown. For this field, validation is not a problem, but behavior is. I live in Illinois, and I make frequent purchases on the Web, so I’m often faced with entering my billing address.When I come to the state selection field on a form, I first type an “i”, and “Idaho” pops up on the list because it is the first state that begins with an “i.” Fair enough—even though I don’t live in Idaho. Next I type an “l” (a lowercase “L”), and “Louisiana” pops up. Now, many fine people live in Louisiana, but I am not one of them.The problem is that the tag interprets my typing as two distinct cases of typing the first letter of a word instead of just one case of typing the first two characters of a single word.When I type “il” I want to see all the states that begin with the letters “il”, and only Illinois makes that cut. Unfortunately, this just isn’t how a tag works—it displays “Louisiana” when I type the “l,” assuming that I’m typing the first letter of the state again. This isn’t always a problem. Some browser versions do work as we’d like them to (interpreting the entire string “il” as the first characters of the state), but we need to have consistent behavior on our page regardless of what browser the page happens to be running in.
9
10
Chapter 1
Understanding Dojo: A Tutorial
1.2.6 City This is another required field.We’ll use a text box to capture the value from the user.
The HTML will be the same as we’ve already seen for the other text fields. City:
The basic HTML form will not provide any type of validation for this field. However, couldn’t we have presented the user with a pull-down list of valid cities like we did for the state selection? There are only a finite number of cities for each state, but the number isn’t small. Across the entire United States there are somewhere around 30,000 cities. So simply listing all of the values in our page would have increased the size of the page, making it slower to load. It is also not correct to list all the cities; we must list only the cities for the state selected by the user.We would need to create some JavaScript logic to do that, and we’re trying to avoid JavaScript in our simple form. The usability of the pull-down list would also be problematic. Because there are so many cities, many of them would start with the same letter.Typing the first letter of the city would only get the user to the beginning of a long list.The user would have to scroll down for quite a while to reach certain values—something that would get pretty tiresome.
1.2.7 Zip Code Zip code is the final required field for the billing address.We’ll use a text box to capture the data from the user.
The HTML is the same as for the other text fields. Zip Code:
Validation is required. Again, we’ll depend on the server for making sure the field has been entered.The server will return a page containing the form, any data entered by the user, and any validation error messages that are created. Aside from making the field required, what other validations might be performed? Just like for the email address, there are two types of validation. Is the data in the right form? And is the data a valid value? Zip codes take two forms in the United States.They can be five numeric digits long or five digits followed by a dash and then four more digits.This means that the entered
1.2 A Standard HTML Data Entry Form
data can either be five characters long or ten characters long. HTML does provide us with a technique for enforcing a maximum length by using the size attribute. However, there is no way in HTML to specify a minimum length. Nor is there a way to specify that a dash is required to separate the two parts of the long style of zip code.The server can perform all these checks but only after the user has submitted the form. We could go even further. Like states and cities, the U.S. has a certain finite set of zip codes.Would we be able to list them in a list? And since we already know the state and city, could we list just the zip codes that apply? That logic is actually more complicated than you might think—some cities have multiple zip codes while some zip codes cross over city boundaries. Also if we expand our geographic reach beyond the boundaries of the U.S., we’ll discover additional complexities. However, we’ll stay within the U.S. borders for the sake of keeping our tutorial fairly simple. We’ve introduced lots of problems with this field. Remember, solutions are suggested later in the tutorial.
1.2.8 Service Date Our customers would also like to schedule the start of their cable service, so we provide a text box where they can enter the starting service date.
The HTML is the same as we have seen before for the other text fields. Service Date:
What kinds of validation are required for the service date? Of course, it must be a valid date, but what format should the date be entered in? We’re not giving the user guidance.This is clearly a problem. Beyond that, the date should be in the future and not the past.There might even be dates that should be blocked out such as non-business days. Another usability problem with this field is that people can’t easily calculate future dates.What is the date of the day two weeks from now? Do we just add 14 to the current date? Not if the current month ends before we reach that date. And what is the date of the first Monday three weeks from now? It can be very difficult for the user to calculate dates without having a calendar available.
1.2.9 Comments Finally we come to the last field on the form—Comments.The user can enter freeform comments describing how she found out about our service and what kinds of shows she likes—or anything else she might want to tell us.
11
12
Chapter 1
Understanding Dojo: A Tutorial
This is a multi-line text box that allows the use to enter as much or as little text as she would like.The HTML is shown here. Comments:
This is not a required field, so no validation is necessary.The HTML form element provides some basic text editing capability. It will automatically wrap words
when the user comes to the end of each line. Once the user enters more text than can fit in the visible portion of the box, a scroll bar automatically appears on the right-hand edge of the box to allow up and down scrolling. But that’s the extent of its features. There are no formatting capabilities. This completes our review of the original HTML form. Now that we’ve cataloged the many problems with this form, we can plan our strategy for addressing them with Dojo.
1.3 The Plan for Enhancing the Form There is a lot of work to do to address all the problems we’ve identified.We need to create a plan of attack, and the first task is be to organize our problems into some broad categories.We’ll start with the simplest changes first and gradually move up to more complicated ones.The categories are listed here. Each category will be a step of the tutorial. 1. Including Dojo in the form 2. Adding client-side validation 3. Adding server-side features 4. Using additional specialized Dojo widgets 5. Processing the form Each topic is described in more detail in the following sections.
1.3.1 Including Dojo in the Form The first step of the tutorial shows you how to add Dojo to a web page and is contained here in Chapter 1. Dojo is a library of functions that we can access either programmatically or declaratively.We use it programmatically by writing JavaScript, which makes calls to Dojo functions, or declaratively by calling Dojo using HTML markup. But before we can make
1.3 The Plan for Enhancing the Form
any calls to Dojo, we must make it available to our page. In other words, we must include Dojo in our web page.This step alone won’t implement any of the many features available to us, but without it, we can’t use Dojo at all.
1.3.2 Adding Client-side Validation The second step of the tutorial focuses on client-side validation and is contained in Chapter 2, “Using Dojo for Client-side Validation.” Many of the usability problems we identified were things that could be solved by providing some validation in the browser. In this step we only address the validation that doesn’t require communication with the server. Some developers might not even consider these features to be Ajax because there is no server request created. But that would not be quite accurate. After all, Ajax is a two-sided coin. One side is certainly asynchronous server communication without a page refresh, but the other side of the coin is all the interactivity and eye candy available by using JavaScript to manipulate the display. One of the problems we solve in this step is the validation of required data. Rather than submit the form and asking the server to check that a required field has been entered, we use JavaScript to test for data before submitting the form.This will make the application seem faster because the user won’t have to wait for a server response to find out about bad data.
1.3.3 Adding Server-side Features The third step of the tutorial focuses on the classic definition Ajax—making calls to the server without refreshing the page that the user is working on.This topic is covered in Chapter 3, “Using Dojo to Work with the Server.” Some of the other problems with our form were caused by forcing a page submit to validate certain kinds of data. For example, the user name needs to be validated against existing user names on the server.There is no way to avoid checking the server—that’s where the data is. But we don’t have to request a whole new page.We can create an Ajax request just to check the user name, and the server will return just the validation information, not an entire new page.This will be quicker and won’t interrupt the user’s flow. We’ll also make requests to the server to get data based on values entered by the user. For instance, we can go get a list of cities from the server based on the state selected from the pull-down list.This step will require some additional scripts on the server to allow it to respond to these Ajax requests. I’ve created some simple JavaServer Page (JSP) scripts on the server to allow the examples to work.The scripts are over-simplified but serve the purpose of demonstrating the features that are discussed in the tutorial.
1.3.4 Using Additional Specialized Dojo Widgets The fourth step of the tutorial demonstrates some of Dojo’s powerful widgets and is contained in Chapter 4, “Using Dojo Widgets.”
13
14
Chapter 1
Understanding Dojo: A Tutorial
Eye candy is the term some designers use to describe cool visual effects. Drag–anddrop in Google Maps is at least partly an eye candy feature. Not only does Dojo allow us to enhance existing HTML form elements, but it also provides entire new visual elements called widgets, which provide new form elements not available in HTML. For example, one of the problems with service date was that the user really needs to see a calendar to pick the date.We can add the Dojo Date Picker widget, which causes a calendar to display right on the page.We can also replace the simple element with a full-blown rich text editor widget.
1.3.5 Processing the Form The fifth and final step of the tutorial demonstrates form processing and submission and is discussed in Chapter 5. The final step of the tutorial deals with treating the form elements as an integrated whole.We look at how to verify that all the client-side validations have been performed before the form is submitted, and we see how to submit the form. I hate to ruin the end of the movie, but here goes (spoiler alert): Dojo will submit the form data as through it were a regular HTML form. In other words, we won’t have to modify the component on the server that processes the form data.The server won’t even know that the form has been “Dojo-ized.”That will save us some work on the server.
1.4 Getting and Running the Source Code Each step in the tutorial is fully described in this book. However, you might want to play along at home. All the source code required for the tutorial is available at the web site for the book, which includes starting code for each step along with the final code for each step.You can download the starting code and make the changes yourself—or just download the final code for each step and run it. You can use whatever editor you like to modify the code. For some of the steps, you do not even need a web server. However, this is a web application, so some of the features do require a server. I’ve created some server components using Java Server Pages (JSPs).These server components are sufficient only to run the examples and are not suggested or recommended for production systems use. To run the server code you need a web server that provides a JSP container. I’d recommend Tomcat, available at the Apache Software Foundation web site.1 Tomcat is free. However, any web server which supports JSPs will do.The web site for the book also provides support for running the code along with corrections to the book’s text. Please check out the website and feel free to contact me.2
1 2
You can download the Tomcat web server from the following address: http://tomcat.apache.org/. The web site for this book can be found at the following URL: http://www.objecttraininggroup.com/dojobook.
1.5 Tutorial Step 1—Including Dojo
1.5 Tutorial Step 1—Including Dojo The purpose of the first step of this tutorial is to make the Dojo Toolkit functions available to our web page. For now, we can think of Dojo as a JavaScript file that must be included on our page (and on each page that will use Dojo).This is a simplification. The Dojo Toolkit actually consists of many files organized in a directory structure.We explore that in later chapters, but for now we can pretend that Dojo is just a single JavaScript file. We include Dojo in our page using the same technique that we would use to include any JavaScript source file.We will use the
There are a few caveats.The link provided in the code was for the current version of Dojo at the time this book was published. A more recent version may be available for you. If you choose to use a later version, check this book’s web site to see if the source code has changed. You don’t have to use the AOL CDN.You can download Dojo to your own server. This might be a preferable approach, especially during development. It allows you to look at the Dojo source code and to work offline in case you don’t have an Internet connection. Downloading Dojo is easy.You simply point your browser to Dojo’s web site, http://www.dojotoolkit.org, and look for the download link.The download page contains links to the current version and to older versions.While new versions might provide you with additional features, they might not necessarily work with the source code for this tutorial. Just check this book’s web site for updates. If you choose to download Dojo, the
The attribute djConfig=”parseOnLoad: true” tells Dojo to search the HTML on your page for any Dojo widgets you may have added. For this to work, we need to include the Dojo parser.This is accomplished by adding some JavaScript code to our page. Include the following code in the tag after the
NOTE This is important—the preceding code containing “dojo.require” must follow the link to Dojo, not precede it.
1.5.3 Include Dojo Style Sheets Throughout the tutorial, we add various Dojo widgets to our page.The “look” of the Dojo widgets is defined through styles specified on a few style sheets that must be added to our page.The Dojo team has separated the “look” of the widgets into separate style sheets.This is an outstanding feature of Dojo widgets. It means that you can easily style the widgets to match the look of your website by overriding the default styles.You’re not limited to whatever out-of-the-box style that the widgets come with. The first style sheet, “dojo.css,” overrides some of the styles of standard HTML page elements such as , , and .There are just a few styles, and they’re meant to set the style to a plain vanilla look. The next file, “tundra.css,” defines the style for components of many of the standard Dojo widgets.The “tundra” theme is one of the three built-in themes available in Dojo. Why the name tundra? A tundra is the cold, treeless area just below the icecap of the arctic regions. It consists of the permanently frozen subsoil populated with mosses and small shrubs. Dojo’s “tundra” theme is meant to be reminiscent of that barren landscape and provides a minimal palette for the widgets.The “noir” theme is darker (“noir” is a genre of film that emphasizes starkness and often is filmed in black and white). And the “soria” theme is brighter (Soria is a city in the sunny north-central region of Spain). Add the following code to the section of the page to style our widgets and provide the Dojo tundra theme. Order is not important.
1.5 Tutorial Step 1—Including Dojo
The code just given only makes the styles available to the page. Now we must actually apply the theme to the page by adding a class attribute to the tag as the code that follows demonstrates.
1.5.4 Review All the Code Changes We’ve made quite a number of changes to the page, and it might be a little confusing as to exactly what the page should now look like. Following is a new listing of the top part of the page so that you can see all the changes.
Customer Entry Form
Once all these changes are made, we can run the new page to see what it looks like.
1.5.5 Run the New Page The new page appears as shown in Figure 1.4.
Figure 1.4 HTML Customer Entry Form with link to Dojo
Hopefully you’re not too disappointed—the page appears to look almost the same as the original form.There are some subtle style changes, though, such as the font for the labels and form title—but nothing dramatic.That is ok.We really haven’t started using Dojo yet.We’ve just made it available to our page. In the next chapter, we continue on with step 2 of the tutorial where we implement the client-side validations, which is when we start to see some exciting stuff.
1.5 Tutorial Step 1—Including Dojo
Summary We explored Dojo by starting a tutorial that will demonstrate some of its basic features. The tutorial consists of five steps: Step 1—Including Dojo (Chapter 1) Step 2—Adding client-side validation (Chapter 2) Step 3—Adding server-side features (Chapter 3) Step 4—Using additional specialized Dojo widgets (Chapter 4) Step 5—Processing the form (Chapter 5)
We started out by implementing step 1 of the tutorial in this chapter by placing references to Dojo within our HTML page.
The next chapter continues the tutorial. Now that we’ve made Dojo available to our page, we can start to use it to do some client-side validation on our text fields.
23
This page intentionally left blank
2 Using Dojo for Client-side Validation
To err is human… —Alexander Pope (1688–1744)
W e all make mistakes, so input forms must anticipate that users will inadvertently enter bad data. Identifying and correcting these mistakes is an important job of an HTML form, and this chapter describes Dojo features that allow you to easily add validation.
2.1 Validating Form Fields Validating input data on web pages is usually a function performed by the server.The web page allows the user to enter data, and when the Submit button is pressed, the browser wraps up the data into an HTTP request and sends it to the server.The server checks each data field to make sure it is valid, and if any problems are found, a new form along with error messages is sent back to the browser.Wouldn’t it be much more useful if problems could be detected in the browser before a server request is made? This approach would provide two primary advantages. It would lighten the load on the server, and, more importantly, it would notify the user of a problem with a data field almost immediately after he or she entered the bad data.This supports the truism that errors are cheapest to fix the closer the detection is to the original creation of the error. For example, if there is a problem with a zip code field and the user is notified just after he enters the bad zip code, then he is still thinking about zip code and can easily make the correction. If the user isn’t notified until the server response comes back, he’s already stopped
26
Chapter 2
Using Dojo for Client-side Validation
thinking about zip code—his mind has moved on to other concerns.This problem of context switching is especially difficult when the server returns errors for many different fields. How can we drive validation closer to the entry of the data? There are two primary techniques available.The first technique involves trying to prevent the error from being entered at all. For example, if the form requires the user to enter a field that must contain a numeric value of a certain length, we can use the size attribute available in HTML to specify the maximum amount of characters the user can enter. So the user is prevented by the browser from entering more characters than are allowed. Following is an example from our form for the zip code field. Zip Code:
This initial validation markup gives us more optimism than is deserved.We might be hoping for many other attributes to provide some kind of client-side validation. Unfortunately, the size attribute is basically the extent of HTML-based validation techniques.There are no markup tags or attributes for minimum size or for data type. Nor is there a way in HTML to designate that a field is required. That brings us to the second type of validation available to us in the browser.We can use JavaScript. Given the power of JavaScript, the sky is the limit in terms of types of validations we can perform.We can trigger a JavaScript function to run after the user enters a field, and that function can check to see if data is entered, check for a minimum or maximum length, or even perform sophisticated pattern matching using regular expressions. Problem solved, correct? Not quite.The problem with depending on JavaScript as our validation technique is that we have to write lots of code to implement the checks. JavaScript code is required to perform the validation. Other JavaScript code tells the validation when to run. And even more JavaScript code is needed to display the error messages back to the user. Code, code, and more code. Suddenly, this approach doesn’t seem as desirable anymore. But this is where Dojo can come to the rescue. In this part of the tutorial, we explore how Dojo can help us with validation by combining the two techniques we’ve discussed. In other words, we’ll be able to turn on validation by using simple HTML markup, but we’ll let Dojo provide the complex JavaScript code automatically. Let’s get started.
2.2 Tutorial Step 2—Adding Client-side Validation In this step of the tutorial, we use Dojo to provide basic client-side validations.We look at a number of useful techniques within the context of making real enhancements to our form. One by one, we examine the fields that these techniques are appropriate for.
2.2 Tutorial Step 2—Adding Client-side Validation
2.2.1 Validate the First Name Field Let’s look at the “First Name” field first.What are the validations that we need to apply? The data on this form feeds into our billing system, so the customer’s name is very important—the field must be required. Are there any other validations? Not only do we want to get the data, but also we’d like it to be in a consistent format. Possibly the data should be stored in all capital letters. Or maybe we want to ensure that the data is not in all capitals. Let’s choose the latter—but we’ll still want to make sure that at least the first letter is capitalized. As in many of the issues related to validation, things are more complicated then they might first appear. For example, are we allowing enough room to enter long names? Will single-word names such as “Bono” be allowed? For our purposes, we’ll keep it simple. We turn on validation by using special attribute values in the HTML markup for these fields.The following code will add validation to the fields. First Name:
The code is formatted to be more readable by using line breaks.To summarize what has happened: All we’ve done is add some new attributes to the tag for the field. Each of the new attributes affects the validation in some way. Notice the following line of code from the preceding example: dojoType="dijit.form.ValidationTextBox"
This attribute is not a standard HTML tag attribute. Depending on which editor you are using to modify the file, it may even be highlighted as an error.The dojoType attribute is only meaningful to the Dojo parser, which was referenced in step 1. Remember the code we needed to include the parser? It is shown here: dojo.require("dojo.parser");
The parser reads through the HTML and looks for any tag that contains dojoType as one of its attributes.Then the magic happens.The parser replaces the element with the Dojo widget specified by dojoType. In this case, the widget dijit.form.ValidationTextBox is substituted for the Document Object Model (DOM) element created from the tag.
27
28
Chapter 2
Using Dojo for Client-side Validation
How does Dojo know what to replace the tag with? That is determined by the specific widget. Each widget behaves a little differently. HTML markup and JavaScript code is associated with the widget in its definition, and that is how Dojo knows what to replace the original element with—which brings us to the missing piece of the puzzle. We need to tell Dojo to include the code for the widget by specifying the widget in JavaScript.To do that, we include the following JavaScript code after the link to Dojo and after the reference to the Dojo parser. dojo.require("dijit.form.ValidationTextBox");
Notice that the name of the widget specified as the value for the dojoType attribute is the same as the argument for the dojo.require call.This is the linkage that allows Dojo to associate the HTML markup with the JavaScript code for that widget. To emphasize this process, let’s review the HTML markup specified in the original page and then compare it to the HTML markup after the parser runs.To see the original markup, we merely have to view the source of the file form.html. Seeing the new markup is a bit harder.The browser converts the original HTML into a DOM tree representing the various tags.The Dojo parser modifies the DOM elements using JavaScript, but the original source for the page is untouched.We need some tool that will convert the DOM (the browser’s internal representation of the page) back into HTML for our review.The Firefox browser provides a DOM Inspector to do just that. An excellent add-on to Firefox, called Firebug, also allows the DOM to be inspected. Firebug also provides a number of excellent tools for developing web pages such as its DOM inspection capabilities we can use to inspect the DOM after the Dojo parser has run—so we can see exactly what it does. But before we see how the DOM changes, let’s first review the original tag for the first name field.
The code has been reformatted to make it more readable by adding some line breaks. The attributes from dojoType through trim are not valid HTML attributes.They are meaningful only to the Dojo parser and drive some features of the Dojo widget they pertain to. Now let’s see what the HTML looks like after the parser runs.
2.2 Tutorial Step 2—Adding Client-side Validation
The preceding code has also been reformatted for readability, adding line breaks and changing the order of the attributes a little. Notice that a number of valid HTML attributes have been added to the DOM element such as tabindex, class, autocomplete, and disabled. And additionally, a number of Dojo-only attributes have been added such as widgetid, dojoattachevent, dojoattachpoint, invalid, and valuenow.We look at these in more detail in Part II, “Dojo Widgets,” but for now it’s enough just to point out that the parser is rewriting our HTML.The parser is doing even more work that we can see here. It is associating various event handler functions to events that might occur on this DOM element. For instance, when the user enters or changes the value in the field, Dojo functions get called, which perform validation. And Dojo even creates objects that correspond to the HTML tags.We can’t tell that this is happening just from seeing the HTML markup, but behind the scenes, that is exactly what Dojo is doing. Let’s review the other special Dojo attributes. Each Dojo widget has a set of properties that control its behavior.These properties are set by various Dojo widget attribute values. n n
The required=”true” attribute setting tells Dojo that this field must be entered. The propercase=”true” attribute setting tells Dojo to reformat the field value entered by the user. In this case, the setting for propercase tells Dojo to make sure that the first letter is capitalized and subsequent letters are in lowercase. In other words, Dojo will put the entered value into the format for a typical proper noun.
29
30
Chapter 2
n
n
n
Using Dojo for Client-side Validation
The promptMessage=”Enter first name.” attribute setting tells Dojo to display a message next to the field to instruct the user on what kind of data can be entered into the field.The prompt message displays while the field is in focus. The invalidMessage=”First name is required.” attribute setting causes Dojo to display a message next to the field if it fails the validation. In our case, if the user does not enter a value, then a message will appear. The trim=”true” attribute setting tells Dojo to remove any leading or trailing spaces from the entered value before sending it to the server.
Now let’s run the page and see how it behaves. Because this is the first field on the page, the field gets focus, and the cursor immediately is placed on the input area for the “First Name” field.
Notice that we get a message box that says “Enter first name.” Dojo calls this a Tool Tip, and it has dynamic behavior. It is only displayed when the field has focus (the cursor is in the field), and once the field loses focus, the message disappears.The message appears on top of any visible element below it, so there is no need to leave room for it when designing your page. Try entering different values in the field and then press to leave the field. For example, enter “ joe “ and watch it be transformed into “Joe” with leading and trailing spaces removed and the first letter of the name capitalized. NOTE: You might not agree with the various validations I have chosen. For example, one early review of this text pointed out that “LaToya” would be a hard name to validate. You could probably make a case for different validations, and I could probably agree with you. But I’ve chosen the ones I have not only to represent my example application, but also to highlight certain Dojo features—so I’m sticking to them!
2.2.2 Validating the Last Name Field The last name field has the same validations as the first name field does.There is nothing extra to do for this field and nothing new to learn. Just replace the tag for Last Name with the following code.
2.2.3 Validating the User Name Field We are going to allow the user to manage his or her own account information in our application.To provide some security we need the user to make up a user name that he or she can use later to sign on to the system.This field will be required, and we’d like it to always be entered in lowercase.To validate this field, we’ll use the same Dojo widget that we’ve already used, dijit.form.ValidationTextBox, but we’ll use a new attribute called lowercase to force the transformation of the entered data into all lowercase letters. There are some additional validations we’d like to do on this field. For instance, is this user name already assigned to someone else? We could check the server for existing values. However, because this validation requires interaction with the server, we’ll save it for step 3 of the tutorial and focus on only the client-side validation right now. The following HTML markup is needed to enable validation for this field.
2.2.4 Validating the Email Address Field We need to communicate with our customers so we’ll get their email addresses.This will be a required field.We’ll also make it all lowercase for consistency. In addition, we’d like to make sure that the value entered in this field is also in the correct format for an email address.There is no way to know if it is a working email until we actually try to send something to it, but at least we can make sure that it contains a “@” character and appears to reference a valid domain. How can we specify the desired format? By using a specialized pattern matching language known as regular expressions, we can specify a pattern of characters to check the value against.We need to build a regular expression to validate for email addresses. At this point in our discussions, let’s not go on a long detour to discuss the building of these expressions. NOTE: Some great information on building regular expressions can be found at the Mozilla Developer Center at http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference: Global_Objects:RegExp.
31
32
Chapter 2
Using Dojo for Client-side Validation
The following is regular expression that can be used to validate most formats of email addresses—most because it is surprisingly difficult to validate for all possible email addresses.This is because of some of the unusual variations such as domains longer than four characters such as “.museum” or addresses consisting of a sub-domain. But the following regular expression will work for most. [\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b]+
NOTE: For more information on validating email addresses, the following link will get you to a Dojo Forum article describing a regular expression for email: http://dojotoolkit.org/forum/dijitdijit-0-9/dijit-support/text-validation.
The ValidationTextBox contains a special property for validating against regular expressions.The attribute to use is regExp—just specify the regular expression as its value. Replace the tag for email with the following code in “form.html” to specify validation for the email address field.
Validating email addresses is a really interesting subject.There are quite a few variants to the simple [email protected] format that we often see. For a really thorough discussion of email, you should review the RFC rules.The following link will get you to the Wikipedia page that describes email, from which you can link to the official RFC documents: http://en.wikipedia.org/wiki/E-mail_address.
2.2.5 Validating the Address Field The address field will contain the first line of the user’s mailing address.We’ll make it required.We will use the ValidationTextBox, and we have seen all of the attributes already. Replace the tag for address with the following code.
2.2 Tutorial Step 2—Adding Client-side Validation
There are many additional validations that can be performed on address data, the most important being to ensure that the address is an actual address. Standard abbreviations such as “St” for “Street” could also be allowed.These additional validations could be done by a number of web services available from the U.S. Postal Service, but that is really outside the scope of this tutorial.
2.2.6 Validating the City Field The city field will contain the value for the city in the user’s mailing address.We’ll make it required.We will use the ValidationTextBox. Replace the tag for address with the following code.
2.2.7 Validating the Zip Code Field The zip code field is part of the mailing address and is required.There are some additional validations we can apply. Our hypothetical company is a U.S. corporation and only provides service to U.S. customers, so we’ll limit our address to valid U.S. addresses, which means that the zip code must be in one of two forms. Either it is a 5-digit number, or it is a 5-digit number followed by a dash and then followed by a 4-digit number. If we can come up with a regular expression to test for either format, then we’re golden! Replace the tag for zip code with the following to enable Dojo validation for this field.
An interesting feature of the preceding code is that we’ve got two overlapping validations.The maxlength attribute prevents the value from being over 10 digits, but so does that regular expression.What are the implications of this? One could argue that it is inefficient because both validations will be executed. But they each operate differently on the page, which might justify using both. If the user tries to enter a zip code that is 12
33
34
Chapter 2
Using Dojo for Client-side Validation
digits long, he will be notified as he tries to type the eleventh digit, rather than after typing all 12 digits and pressing tab to leave the field. By using both techniques, the error is detected sooner. NOTE: This chapter has stopped short of describing validations for the “Start Service” and “Comments” fields. This is because we will use more advanced Dojo widgets to validate these fields, which are described in Chapter 4, “Using Dojo Widgets.”
Summary The Dojo widget dijit.form.ValidationTextBox provides many common client-side validations. Include the ValidationTextBox by referencing it in the tag for the field that needs the validation. dojoType="dijit.form.ValidationTextBox" Remember to tell the page that it needs the JavaScript code for the widget by coding a call to the require method somewhere after the call to the Dojo parser. dojo.require("widget dijit.form.ValidationTextBox"); Additional attributes in the tag specify behavior for the ValidationTextBox. A few are listed here: require="true" makes the field required. trim="true" removes leading blanks. lowercase="true" converts field to all lower case letters. We’ve now completed step 2 of the tutorial. The changes we’ve implemented have added client-side validation to our form. We were able to add validation almost exclusively through modifying the HTML—only a small amount of JavaScript was necessary to include the Dojo validation code. Client-side validation is an extremely powerful capability and makes our page much more usable. Yet by using Dojo, we obtain this power without the corresponding cost of writing a lot of JavaScript.
In this chapter we’ve focused on functionality that doesn’t require a call to the server. In the next chapter the server will play a role.We’ll make calls to the server using the XMLHttpRequest to get data and perform validations. Now that’s Ajax!
3 Using Dojo to Work with the Server
You’re gonna have to serve somebody. —Bob Dylan
T
his chapter describes how we can use Dojo to communicate with a server.Two of the primary purposes that the server can fill are to run processes and provide data. Examples of both of these are provided in this part of the tutorial.
3.1 Adding Server-side Features Although Dojo calls itself a JavaScript library, it is often categorized as an Ajax library instead.Though the characterization might not be accurate, it is understandable. Because there is no “International Organization For the Definition of Ajax,” the term has been used in a variety of ways. In general, it’s used to refer to web pages that access the server without benefit of a full page refresh and that perform some snazzy manipulation of the DOM to make the site more interactive than stodgy old HTML alone can. But still, for some, we’re only using real Ajax when we’re making server requests. This chapter deals with making Ajax requests of the server.We examine two kinds of requests.The first type of request is to ask the server to perform some processing. In this case, we’ll ask the server to validate user name.The second type of request is to ask the server to provide some data, which we will then add to the DOM so it is visible to the user. Our data request will be for a list of cities in a given state.
36
Chapter 3
Using Dojo to Work with the Server
NOTE There are two primary reasons for communicating with the server: (1) to perform validation and (2) to get data. This part of the tutorial is split into two steps to correspond to each of these reasons for using the server. The first step, 3a, describes server-side validation. The second step, 3b, describes getting data from the server.
3.2 Tutorial Step 3a—Adding Server-side Validation In this step of the tutorial we use the server to validate some data entered by the user. A number of interesting questions are addressed. How do we capture the data? At which point should the server request be made? What should the application do while waiting for the server to return? How should the server response be handled? As simple as this scenario might appear, it does introduce a few complexities. Dojo provides flexibility in coding for these issues, and some common patterns and best practices will emerge. We can validate that a user name entered by the user is not already assigned to another customer. Many applications allow a user to specify a name by which they are known to the application.This user name allows the user to login to the application to do things like edit his or her account or see transaction history.The user name must be unique for each user across the entire system; therefore, it requires server-side validation to ensure that it hasn’t been assigned to another user.The use case for this scenario might seem rather simple, but still it introduces some interesting complexities.
3.2.1 Assign Event Handler Function The process begins with the user entering a desired user name.The user types the characters and at some point is finished. But how do we really know that the user is done entering data? Is it when the individual stops typing? If so, how long does the application wait before deciding that the user is done? We could even perform the validation after each keystroke. However, this approach has a number of drawbacks.The load on the server would be needlessly increased. And the user might be subjected to a flurry of messages describing the intermediate validations. It would be more useful to perform the validation just once, when the user has completed entry of the data. A better approach might be to wait until the user exits the field by pressing the Tab key or even the Enter key.The problem with pressing Enter is that the browser might interpret this as a form submission (the default behavior for a standard HTML form). By pressing the Tab key or using the mouse to place the cursor into another field, the user would be signaling that he is done entering the user name field and wishes to enter data for a new field.We’ll use this condition as the right time for the validation to be performed. Now we need to translate the logical event we wish to capture (the user exiting the field) into an actual event monitored by the browser. JavaScript provides us with two possible candidate events, onblur and onchange.The onblur event is triggered when
3.2 Tutorial Step 3a—Adding Server-side Validation
the focus leaves the field, which normally means that the user has pressed the tab key to move to the next field or used the mouse to click on another field.The onchange event does almost the same thing.The difference is that if the data did not change, onblur would still be called anyway, but onchange would not.The first time the user enters this field, the difference is moot. But if the cursor passes through the field again without the user changing the data, then the event will be triggered again, and an unnecessary call will be made to the server. So the most efficient event to use would be onchange.We need to create a function that will handle the onChange event and we need to call that function when the event occurs. At this point we need to discuss the difference between regular JavaScript events and Dojo events. JavaScript provides a way to assign an event handler (function) to an event on a DOM element.The code that follows presents an example of this by setting the onChange attribute to a value of userNameOnChange().This will cause the userNameOnChange function to execute when the browser detects that the value of the field has been changed.
The same technique using Dojo appears in the following code.
Notice that we are not using the standard function calling syntax in the second example. In other words, Dojo uses a reference to the function, not a call to the function. We can tell this because the first example uses double parentheses at the end of the function name, while the second example does not. Another difference is that the attribute has a different case—although the spelling is the same, the “C” in the second example is capitalized. As you might guess, Dojo is intercepting the browser events and calling its own events.We go into more detail on exactly what Dojo is doing in Part II, “Dojo Widgets.” But for now, we only have to recognize that Dojo has a slightly different syntax than regular JavaScript for specifying event handler functions.
37
38
Chapter 3
Using Dojo to Work with the Server
Let’s put the handler function into a completely separate JavaScript file.This isn’t necessary but will allow us to keep our JavaScript separate from the original HTML file and will make our code easier to read. Create a new JavaScript file called “userNameValidation.js” with a function called userNameOnChange.The following code contains the contents of our new JavaScript file.We enhance it as we progress through this step of the tutorial. // define function to be called when username is entered function userNameOnChange() { return; }
We also need to reference the JavaScript file in our page, so we’ll have to add a new
The first thing you might notice is that the onChange function is called when the form is first displayed, even before the user has entered any data in the field.The field doesn’t even have focus yet.This is because the default behavior for a form widget (of which our widget is a subclass) calls the onChange function when it first sets the value of the element. So we’ll want to remember to skip our validation if there is no data in the form yet, as is shown in the following code.The additional code has been bolded for emphasis. // define function to be called when username is entered function userNameOnChange() { var userName = document.getElementById("userName").value; if (userName == "") { console.log("userName is empty"); return; } return; }
Notice that we are using the console.log function to display messages in a special browser console that is separate from the web page. Logging is a useful technique during development so that we can see what the program is doing without having to use JavaScript alert boxes or write to the web page itself.We dig deeper into debugging in Dojo in Chapter 17, “Testing and Debugging.”
3.2.2 Make a Call to the Server We’ve placed the hook into the page so that when the user enters or changes the value of the user name, our handler function will run. But our function is merely a stub—it
3.2 Tutorial Step 3a—Adding Server-side Validation
doesn’t really do anything. Now, let’s flesh out the function and do the work that needs to be done.We need to perform the following steps: 1. Get the data entered by the user. 2. Send the data to the server along with a request for the server to validate it. 3. Handle the response from the server. Additionally, we’ll need to handle the response on the server and then process the results that come back from the server but that can wait a bit. Let’s concern ourselves with that at a later stage and start with getting the data. 3.2.2.1 Get the Data Entered by the User Dojo provides a number of techniques for getting the value of entered data from a widget. But to understand them, it might be helpful to remind ourselves of how we can get data from form fields without Dojo, just using plain old JavaScript and the DOM. The DOM automatically builds references to form elements, and we can use that to get a value. var userName = document.form.custForm.userName.value
Another technique is to use the id property of the DOM elements to find the correct form element. Of course, this will only work if we’ve assigned id properties to the elements (as we have in our form). var username = document.getElementById("userName").value
Dojo provides some additional techniques.The DOM gives us a single object to get data from—the object corresponding to the DOM element for the field. But when using Dojo, there are two possible objects we could use to get the value.The first object is the DOM element, as with plain old JavaScript, but Dojo provides a shortcut for referencing that object. Notice the dojo.byId function in the following code. var username = dojo.byId("username").value
The second object that Dojo provides is one that is not part of the DOM. It is a separate object that contains additional properties and functions that don’t exist in the DOM element—the Dojo widget object. Every Dojo widget object corresponds to a set of DOM elements that describe that widget.We need a different Dojo function to access the widget object. var userName = dijit.byId("userName").getValue()
Notice in the preceding code that we are referencing a different namespace (that is, dijit.byId, not dojo.byId).The function dojo.byId returns a reference to a DOM element.The function dijit.byId returns a reference to the “shadow” object corresponding to each Dojo widget. Alright already! We’ve got lots of ways to get the data.Which one should we use? “In for a penny, in for a pound,” as Ben Franklin use to say. Because we’re using Dojo, let’s really use it.We’ll write our code against the Dojo object whenever possible so we’ll use
39
40
Chapter 3
Using Dojo to Work with the Server
the last version discussed—getting the value from the Dojo widget object using the dijit.byId function. Let’s add the new code to our userNameOnChange function.We’ll replace the existing code that assigns userName.The new code is bolded. // define function to be called when username is entered function userNameOnChange() { var userName = dijit.byId("userName").getValue(); if (userName == "") { console.log("userName is empty"); return; } return; }
3.2.2.2 Send the Data to the Server Now we’ll send the data to the server.We need to use the XmlHttpRequest (XHR) object. But rather than use it directly, we’ll take advantage of the function wrapper provided by Dojo. By using the dojo.getXhr function, we’ll be using the XHR object indirectly and letting Dojo handle the housekeeping for us. Our code will be simpler that way. // define function to be called when username is entered function userNameOnChange() { var userName = dijit.byId("userName").getValue(); if (userName == "") { console.log("userName is empty"); return; } dojo.xhrGet( { url: "validateUserName.jsp?userName=" + userName, handleAs: "json", handle: userNameValidationHandler }); }
The dojo.xhrGet function has a very interesting signature. It takes a single object as an argument, but that object might have a number of properties. And it is specifically which properties we set and their assigned values that determine how the XHR call is made.We go into much greater detail in Chapter 15, “Ajax Remoting,” but let’s take a cursory look at the function now. It might be helpful at this juncture to remind ourselves of how we would use the XHR directly using JavaScript. var xhr = new XMLHttpRequest(); xhr.open("GET","validateUserName.jsp?userName=" + userName); xhr.onreadystatechange = function() {userNameValidationHandler;}
3.2 Tutorial Step 3a—Adding Server-side Validation
How does our call to dojo.xhrGet differ from the standard usage for XHR? First, and most obviously, we aren’t creating a new XHR object.The new object does get created eventually—somewhere deep in the internals of Dojo (actually not that deep but more on that later). But we have a simpler syntax using an existing Dojo function. Second, rather that pass the HTTP message type as a parameter, it is built into the name of the function.To do an HTTP GET, we use dojo.xhrGet, while to do a POST we use dojo.xhrPost instead. Third, and finally, we pass the callback function, userNameValidationHandler, as a property of our argument object, not by setting an XHR property.There are some benefits that aren’t obvious from viewing this code.When using XHR directly, our callback method has to test the state and status properties of the XHR object before it can safely execute the handler code.When using dojo.xhrGet, Dojo will perform the checks before calling our handler, allowing us to write simple handler code.The less code we write, the less the potential for error.That’s a good thing, as Martha Stewart might say. 3.2.2.3 Handle the Response from the Server The server receives our request, processes it, and returns the response back to the browser.The browser executes a callback function internal to Dojo. Dojo, in turn, calls the function that we specified as the callback, userNameValidationHandler, in the dojo.xhrGet function call. All we have to do is code that function.What must this function do? At a minimum, it should display an error message stating that someone else has already taken the user name.The following code will display an error message. function userNameValidationHandler(response) { // Clear any error messages that may have been displayed dijit.byId("userName").displayMessage(); if (!response.valid) { var errorMessage = "User name already taken"; // Display error message as tooltip next to field dijit.byId("userName").displayMessage(errorMessage); } }
Note that we’re making sure to clear the error message first.This is necessary to get rid of the error message if the user is entering this field a second time after having failed to enter a valid user name the first time. There is at least one thorny issue left.What if the call to the server to validate user name takes a long time—maybe 20 seconds or more? The user might already be entering the next field.We don’t want to interrupt what the person is doing by switching focus back to the user name field. But what will they think when an error message suddenly appears next to a field they aren’t even working on? We could block the user from working while the validation is being done by making the XHR call synchronous, but
41
42
Chapter 3
Using Dojo to Work with the Server
that could also be frustrating for the user.We’ll discuss this issue further in Part II when we explore Dojo widgets in more detail. Our example rests on the assumption that the server can validate the user name.To do that we’re traveling past the boundaries of Dojo.We assume that there is some resource on the server called “validateUserName.jsp.”This resource takes the user name as a parameter and returns a JavaScript Object Notation (JSON) string, defining an object with a property called valid that might either be true or false. Dojo doesn’t care how you write this resource or what kind of server it is running on, just so long as the server can talk HTTP. Following is a simple JSP page that would validate the user name with a hard coded check to see if the value is “olduser.” As long as it isn’t, then the user name would be considered valid.This will allow our example to work, but obviously the server program should be more sophisticated.
The code will return the following JSON string for invalid user names. {valid: false}
And for valid user names, the following JSON string will be returned instead. {valid: true}
You might be wondering how our page can receive JSON and yet never have to convert it to an object. In our callback function we are able to use the object by referencing response.valid.We’re taking advantage of some Dojo magic. By specifying the handleAs property and giving it a value of json, we are telling Dojo to expect to receive a JSON string from the server and to create the object from the JSON string and pass it to our callback method. Now that really saves us some coding!
3.3 Tutorial Step 3b—Retrieving Data from the Server
3.3 Tutorial Step 3b—Retrieving Data from the Server In this step of the tutorial we use the server to return some data back to the browser.We need to send a state value to the server so that it can determine the cities within that state.The server will send back the cities, and then we’ll populate the city select list.The user will be able to select a city from the newly populated pull-down select list.This approach will work most of the time, but there is a small problem.There are a lot of cities in the U.S., and it is just possible that we’ve missed one or that a new one has been incorporated.Therefore, it would be useful to allow the user to type the value of a city just in case it isn’t in our list.The regular HTML doesn’t allow for this but, fortunately, the Dojo version does. Let’s summarize the steps. 1. Select the appropriate Dojo widget to replace the HTML for city. 2. Get the value of state and send it to the server. 3. Process the response from the server Now let’s drill into the details for each of these steps.
3.3.1 Select Appropriate Widget for the City Field In the original HTML form for entering customer information, the “City” field is a textbox in which the user can enter the city by typing it in. Some city names can be rather long and require a lot of typing, making the entry time consuming and prone to spelling errors.We could improve the user interface by providing an auto suggest facility that would list the cities corresponding to the letters typed by the user. For example, if the user typed “ch,” they would be presented with a list of cities beginning with those two letters as shown in the following example.
Figure 3.1
Proposed City Section
An additional refinement would be to list only the cities of the state the user selected from the “State” field. Shall we congratulate ourselves on such a wonderful solution? Well, let’s not throw a party quite yet. After all, there is no standard HTML widget that provides the features we so ardently seek. Luckily, we are using Dojo, which just happens to have a widget called the ComboBox that contains just the features we are looking for. Let’s replace the standard textbox for city with the Dojo ComboBox.We must make sure that the code for the widget is included by using the dojo.require statement. Add the following code to the
Now we must create the new file and define the handler function. function populateCity() { // Get the new value of state var selectedState = dijit.byId("state").getValue(); // Build URL to make XHR call to server var url = "getCities.jsp?state=" + selectedState; // Build new data store cityStore = new dojo.data.ItemFileReadStore({url: url}); return; }
3.3 Tutorial Step 3b—Retrieving Data from the Server
The data store is now created but does not make an XHR request yet.That will only occur after we bind the data store with the widget. 3.3.2.3 Bind the Data Store to the Widget To actually cause the data store to get the data from the server, we need to associate it with the widget that will use the data. All we have to do is assign the value of the store property of the widget to the data store, and Dojo does all the rest. We need to add additional code to our event handler to get a reference to the widget and to assign the new property value. Add the following code that is in bold to your handler function. function populateCity() { // Get the new value of state var selectedState = dijit.byId("state").getValue(); // Build URL to make XHR call to server var url = "getCities.jsp?state=" + selectedState; // Build new data store cityStore = new dojo.data.ItemFileReadStore({url: url}); // Create a reference to the city widget var city = dijit.byId("city"); // Clear out any existing values in the widget city.setDisplayedValue(""); // Assign new data store which will force a new XHR request city.store = cityStore; return; }
This is all that is necessary. By building a new data store to ask for the selected state and then assigning that data store to the widget, Dojo automatically creates an XHR object to get data from the server and then populates the widget with that data.With just a few lines of code we’ve implemented a powerful server lookup feature in our form. Summary Dojo can be used to call server resources, which can perform processes or retrieve data. The Dojo xhrGet and xhrPost functions can be used to provide a wrapper around the XMLHttpRequest (XHR) object, which can perform a call to the server. Data stores provide a wrapper around external data retrieved from the server. Some Dojo widgets can bind with a Dojo data store to automatically retrieve data from the server and populate the widget.
49
50
Chapter 3
Using Dojo to Work with the Server
This chapter provided insight into a few of the standard Dojo widgets and showed how to use them to call server processes and to get data. The client-side functionality of the Dojo widgets was much more powerful than the standard HTML widgets, but we can go even further. Although communicating with the server is an important Ajax feature, the flip-side of the Ajax coin is the ability to create impressive visual elements in the browser. The next chapter focuses on a few very powerful and visually impressive widgets available in Dojo.
4 Using Dojo Widgets
There is nothing worse than a sharp image of a fuzzy concept. —Ansel Adams
Fvisualor better or worse, the Web is a strong visual medium. A web page is a collection of elements that allow the user to view and manipulate information whose best presentation fits the right widget to the right data. In other words, the information cries out to be displayed in the correct form. Unfortunately, standard HTML only provides a small set of options for displaying data. Dojo expands our possibilities by providing a robust set of visual elements, called widgets, which offers us a much richer palette to choose from for bringing the data and features of our applications to life.
4.1 Adding Dojo Widgets to the Page Web developers are looking for ways to apply Ajax techniques to their web pages. But what exactly is Ajax? The original acronym was capitalized as AJAX and stood for Asynchronous JavaScript and XML. But the meaning has evolved over time. Let me give you a more current meaning. Ajax can be described as a two-sided coin. One side of the coin is the ability to communicate with the server asynchronously without refreshing the page—also known as the XHR object.This, in many ways, is the essential feature of an Ajax web site because this is the new paradigm on which many Web 2.0 interfaces are built.The other side of the Ajax coin is the rich user interface that most Ajax applications provide.To many, this is the real hallmark of an Ajax application, regardless of how server requests are made under the hood. A JavaScript library might address either side of this coin, but Dojo addresses both.We’ve already covered the XHR object, so in this part of the tutorial we focus on the ability of Dojo to provide the rich user interface through its set of advanced widgets.
52
Chapter 4
Using Dojo Widgets
4.1.1 Dijit—The Dojo Widget Module Dojo uses the term dijit to describe its features related to creating and using widgets. Not only is this a conceptual term, but Dojo also physically organizes these features into a subdirectory called digit, which is at the root of the dojo directory. Also dijit is the namespace used to reference widget-related functions.We’ve seen some examples of the use of the dijit features already, but now we can explore them in a little more detail. The Dojo team had a number of goals in creating the widget features: n
n
n n n
Create a set of visual widgets that provide useful features beyond the standard HTML elements. Expose the technique for creating Dojo widgets so that developers can extend existing Dojo widgets or create entirely new widgets based on the same techniques. Make the widgets look the same in all the different browsers. Ensure that the widgets can support accessibility features for impaired users. Provide internationalization support for all the widgets so they can support multiple languages.
As you work with the Dojo widgets, you will discover that Dojo has achieved these goals and given developers a powerful toolbox for creating visually sophisticated web sites. Part II, “Dojo Widgets” explores individual Dojo widgets in greater detail. For now, let’s explore how to use a couple of the most powerful Dojo widgets by adding them to our web page.
4.2 Tutorial Step 4—Using Dojo Widgets In this step of the tutorial, we use Dojo widgets to replace some of the standard HTML widgets on our page.We’ve already done this in prior steps of the tutorial, so the technique should be familiar. Our approach will be to add a special attribute, dojoType, to the standard HTML tag that will be read by the Dojo parser and will cause the Document Object Model (DOM) element to be enhanced with additional features.That was a mouthful. More simply, we are just telling Dojo to replace the single DOM element representing the standard HTML widget with a more complex set of elements. This new group of elements, when acting together, provides the functionality for our Dojo widget. Additionally, Dojo will create a JavaScript object that is not part of the DOM that will be associated with the new widget.This “shadow” object will contain properties and methods not available in the DOM elements. NOTE: Because Dojo widgets can consist of multiple DOM elements, you’ll want to be sure to access them using dijit.byId() instead of document.getElementById().
4.2 Tutorial Step 4—Using Dojo Widgets
4.2.1 Use the Dojo DateTextBox Widget Let’s start with the “Service Date” field.This is the date on which the user wishes service to start.We haven’t seen this field since step 1 of the tutorial, so you might want to take a look at the original form in Figure 1.1 to refresh your memory. In the original form the user is presented with a text box containing no validation. As we discussed earlier, a number of problems exist with this approach, the most obvious of which being that the user does not know what format in which to enter the date. Beyond that, it is difficult for people to determine dates without access to a calendar. So it seems obvious that this widget, the standard HTML textbox, does not fit the function of the data the user needs to enter. A more appropriate graphical user interface (GUI) element would provide the user with a calendar from which he or she could select a date.That would address the format problem because the user wouldn’t need to enter the date as text. And it would allow the user see the data in the form most useful for them: a calendar. Let’s see how we can quickly add this widget to the page.Then we can discuss it in more detail. We simply need to add the dojoType attribute to the tag for the element. We’ll also add a few additional attributes that aren’t required but will provide some useful functionality.The following code shows the attributes to add to the tag. New attributes are bolded.
The new attributes tell the Dojo parser to replace the standard HTML tag with the Dojo DateTextBox widget. However, Dojo needs to know where to get the code for the new widget, so an additional step is necessary.We tell Dojo where to get the code by including a dojo.require function call passing the widget name as a parameter. Add the following code to the top of the “form.html” file to the existing group of require function calls. dojo.require("dijit.form.DateTextBox");
Notice that the value of the dojoType attribute dijit.form.DateTextBox is the same as the parameter passed to the dojo.require function.This is the link that allows Dojo to associate the widget in the tag with the code and additional HTML associated with the widget. When we first run the form after making our code changes, it appears that nothing has changed. Next to the “Service Date” label, what looks like a simple text box is still displayed.
53
54
Chapter 4
Using Dojo Widgets
However, as soon as we place the cursor in the field, a calendar is automatically displayed from which we can select a date.
Figure 4.1
Service Date Field With DateTextBox WidgetNot only does a calendar appear, but also the current date is highlighted. In the preceding example, October 24 is selected, as shown by the dark background behind that date on the calendar.The user can flip through the calendar by clicking the back and forward arrows in the upper left and right of the calendar.When the desired date is visible on the calendar, the user can select it simply by clicking on the desired day, and the calendar widget automatically fills the text field with the correct text value for the date.
We’ve now added an extremely useful widget to our page with very little effort. But let’s get a little greedy.What other useful features can take advantage of in this widget? Let’s consider some additional business rules. For example, the user should not be able to schedule a date in the past. How can we accomplish this? It turns out that there is an attribute called constraints that can be used to define valid values for the date. By setting a minimum constraint to the current day, we are excluding prior dates.This can be done using the constraint attribute as shown in the following code.The new code is bolded.
4.2 Tutorial Step 4—Using Dojo Widgets
Even through the value of '2007-10-24' appears to be hard-code, you could generate this dynamically when creating the page on the server so that the current date is always supplied. Now when the widget appears on the page, prior dates are crossed out as shown here.
We could go even further. For example, we could exclude weekends. However, we must be careful. Even if we include business rules for service date in the browser, they must be re-validated on the server.The server should never trust data from the browser. A better approach might be to create an XHR request to validate the selected date once the user enters it.This would allow us to keep the business logic on the server and yet still give the user the benefit of instant validation without having to submit the entire form. A number of other useful attributes to control the behavior of the calendar exist and will be explored in more detail in Part II.
4.2.2 Use the Dojo Rich Text Editor Widget Now let’s turn our attention to the comment field.This field allows the user to enter multi-line text comments using the HTML tag.This standard HTML tag provides some simple features such as automatic word wrapping at the end of each line. But that is about all it offers. If we want to do anything fancy such as changing the font of the entered characters, making them bold, or putting them in a bulleted list, then we are out of luck.The standard widget just doesn’t allow for it.Wouldn’t it be nice to have a powerful text editor that we could insert right into the page? Yes, it would. And Dojo provides one. It is called dojo.editor, and it provides quite a robust set of default features. Before exploring the details, let’s just put the default widget onto our page by replacing the existing tag. As with the prior widgets, all we really need to do is add the dojoType attribute in the existing HTML tag.Then we need to make sure the widget code is included in the page by referencing the widget using dojo.require. First let’s change the current HTML tag so that the Dojo Rich Text Editor Widget will be used in its place.
55
56
Chapter 4
Using Dojo Widgets
Notice that the widget name is a little different than for the other Dojo widgets we have used.The Editor is not part of the form package, so we don’t include form in the widget name. Now we need to make sure that the code for the widget is available to the Dojo parser for substitution into the DOM. Add the following code to the top of the “form.html file” to the existing group of require function calls. dojo.require("dijit.Editor");
Now when we run the page, we see the new widget. By clicking just below the widget toolbar, we can enter some instructions regarding service. Figure 4.2 shows the widget along with some user-entered text concerning the types of service that the person wishes to purchase.
Figure 4.2
Text editor widget
As you might have noticed in using the widget, it is hard to figure out exactly where the text area for the widget begins and ends.To improve the look of the widget, we’ll enclose it within a div and assign a style to it.We’ll add a solid border around the widget and make the text area have a light background, as shown here.The new markup code is in bold.
Comments:
Now we get a clearer idea of where text can be entered, as shown in the following screen shot.
4.2 Tutorial Step 4—Using Dojo Widgets
Notice how it is now much easier to see where the text area of the widget is. The toolbar at the top of the widget displays a number of icons that can be used to provide formatting features. In the given example, the items “HBO” and “Showtime” were converted into an unordered list by selecting them and then clicking the unordered list icon.The various icons are explained in Table 4.1. The default Editor widget provides a number of formatting tools represented by the icons on the toolbar. But you might not want to make all of the editing features available to the users of the page. It is possible to specify which tools you would like the editor to make available by setting the plugins property of the widget, which contains a list of editing features that should be displayed in the toolbar. Also you might notice that a vertical bar separates some features.This allows related icons to appear together as a group. The “|” character is used as a separator by default, but any character is allowed. Following is the definition for an Editor widget that only allows three editing features (bold, italics, and ordered list/unordered list) with a separator after italics.
Notice that the widget now has a different toolbar and is showing only the features that we have specified.
Each of the editing features has an icon and a name that can be used in the value for the plugins attribute.The following table lists the available editing features along with their corresponding icons. Table 4.1 Icon
Rich Text Editor Icons Attribute Value
Description
undo
Undo last edit.
redo
Redo last edit.
cut
Cut selected text.
copy
Copy selected text.
paste
Paste text at cursor.
bold
Make selected text bold.
italic
Make selected text italicized.
underline
Underline selected text.
strikethrough
Strike through selected text.
insertOrderedList
Turn selected text into an ordered list.
57
58
Chapter 4
Using Dojo Widgets
Table 4.1
Continued
Icon
Attribute Value
Description
insertUnorderedList
Turn selected text into a numbered list.
indent
Indent selected text.
outdent
Outdent selected text.
justifyLeft
Left justify selected text.
justifyRight
Right justify selected text.
justifyCenter
Center justify selected text.
justifyFull
Justify selected text on right and left.
We can specify any combination of editing features in any order. Summary Dojo provides a rich set of graphical widgets that can be added to web pages. Dojo widgets can be placed on a page by adding the dojoType attribute to the HTML tag for the DOM element to contain the widget. dojoType="dojo.form.ValidationTextBox" The Dojo parser reads through the HTML and replaces the DOM element with the specified Dojo widget everywhere that it finds a dojoType attribute. The Dojo parser is included in the page by including the following JavaScript code: dojo.require("dojo.parser") The Dojo parser needs to know where the code is for every widget it needs to place on the page. A call to the dojo.require function is required for each type of widget on the page. dojo.require("dojo.form.ValidationTextBox") In this step of the tutorial we added two very powerful widgets to our page. Dojo contains many more widgets then we’ve seen so far. And although each widget has certain unique features, all widgets follow a similar structure. The techniques provided here to manipulate and work with widgets apply to the other Dojo widgets as well. We explore more Dojo widgets in Part II.
In the next chapter we put the finishing touches on our form and see how we can submit the form to the server.
5 Processing Forms with Dojo
The job’s not done until the paperwork is complete. —Anonymous
T
his chapter finishes up the tutorial.We’ve already added validation, server-side processing, and widgets, but there are a few finishing touches required before we can call our work complete.This chapter describes the remaining problems with the form and shows us how we can use Dojo to fix them.
5.1 Using Dojo to Process Forms We are almost done upgrading our form to use Dojo.To some extent, we are done—we could declare victory and go home or at least submit our changes to production so that the users could benefit from our wonderful changes.We’ve addressed most of the problems identified in our analysis of the original HTML page. However, there are a few remaining issues that are still in need of remediation. For example, what happens if the user tries to submit the form before entering information into all the fields? The way we’ve coded our validations so far requires that the user actually visit each field.We now need to consider the fields as a whole by making sure all the validations have been applied before we allow the entire form to be submitted to the server. A plain vanilla HTML form would make a server request once the user clicks the submit button without regard to the additional validations that could be performed.We’ll use Dojo to intercede in the processing so that it can perform those useful client-side validations before making an unnecessary request to the server. A slightly subtler problem involves exactly how the page makes the server request and also what resource on the server is necessary to respond to that request. A standard HTML form is submitted to the server when the user clicks the submit button.The browser knows which server resource to call based on the action attribute of the form
60
Chapter 5
Processing Forms with Dojo
element. In our example, our form calls the submit.jsp resource on the server as designated in the code snippet here taken from the form.
The browser not only needs to call the correct server process, but it also needs to wrap up the data entered in the form and send it also. Fortunately, the browser can do that automatically.The browser iterates through each of the form elements and creates a name/value pair containing the element’s name and its value at the time the form was submitted. If the form method is “POST,” then these name/value pairs are hidden in the body of the HTTP request, and if the form method is “GET,” then the name/value pairs are appended onto the end of the URL request made to the server.The data will be URL encoded—the spaces and other special characters have been replaced with their decimal equivalent.The field name is first and then separated from the value by the “=” character. Also name/value pairs are separated from each other by the “&” character. What else do we have left to worry about? For instance, once we upgrade the page with Dojo, will there be an effect on the data being sent to the server? Will we have to rewrite some server code to deal with the new data? The short answer is, “No!” In other words, the same program on the server that currently handles the request can continue to handle the request once we add Dojo to the page.That will minimize the impact on adding Dojo to our application. However, suppose we are willing to do some work on the server by rewriting our response processes. Could we achieve any benefit by this? We could submit an XHR request to the server and receive back the response from the server without doing a page refresh.This might be useful but would require that we create a server process that simply sends back the error messages instead of trying to replace the entire screen along with error messages embedded in it.This technique might not be as useful when the form submission succeeds because we would likely be moving onto an entirely new page anyway. But as a general technique, this could be very useful.We could submit the form as an XHR object and process the response without a full page refresh. For the purposes of this tutorial, we will not rewrite any server processes, so we’ll leave XHR form submission for a later chapter when we study Remoting in Chapter 15.
5.2 Tutorial Step 5—Processing the Form In this step of the tutorial we deal with the issues related to the entire form and not just to individual fields.The first thing to do is convert the standard HTML form into a Dojo Form widget.
5.2.1 Creating a Dojo Form Widget We’ve already defined a form on the HTML page. Now we need to convert it to a Dojo Form widget. It is easy enough for us to do now that we’re familiar with the general technique for creating Dojo widgets.We simply add the dojoType attribute to the form element as the following code illustrates (with our required changes in bold).
5.2 Tutorial Step 5—Processing the Form
Of course, we also need to make sure that the Dojo code for the widget is available to the parser.We’ll add another require statement to our list. dojo.require("dijit.form.Form");
That’s all there is to it.We’ve now converted the standard HTML form into a Dojo Form widget.
5.2.2 Intercept Form Submission The form is now a Dojo widget and possesses some new super powers. It gives us the ability to intercept the request when a user clicks the Send button so that we can perform our own processing. By specifying a special attribute, we can cause the browser to pass control to a function instead of submitting the request to the server.We’ll set the value of the execute attribute to the name of a function that we will use to handle the form submission.
We need to create a new function called processForm, and we need a place to put it. So we’ll create a new file called “processForm.js,” and we’ll include it in our page by using the
For now, let’s just create the stub for the form handler function. Create a file called “processForm.js” and place it in the same directory as our form. Following is the code for the stub function. // Process form function processForm { // Re-validate form fields // Place focus on first invalid field // If all fields are valid then submit form }
We’re now ready to implement the function.
61
62
Chapter 5
Processing Forms with Dojo
5.2.3 Check That All Form Elements Are Valid What should we do in our form handler? We need to validate the fields in the form and notify the user by performing the following actions. 1. Re-validate each of the fields in the form. 2. If an invalid field is found, then display an error message and place the cursor in the field. First we need to identify a technique for iterating through the form fields. On each field, we’ll check to see if the field is valid.This can be easily accomplished by calling the isValid() method on the form element.This method will return a true if the field is valid or a false otherwise. Iteration should stop on the first field that is not valid, and we should display an error message and place focus on that field. Displaying an error message turns out to be something that happens automatically. Simply by calling the isValid() method on the element, the message text specified in the invalidMessage message attribute in the elements tag will appear. Placing the field in focus is accomplished by executing the focus() method on the element. We’ve now walked through the necessary code for implementing the form validation. Let’s see what it looks like altogether in the following code snippet. Our changes to the function are shown in bold. // Process form function processForm { // Re-validate form fields var custForm = dijit.byId(“custForm”); var firstInvalidWidget = null; dojo.every(custForm.getDescendants(), function(widget){ firstInvalidWidget = widget; return !widget.isValid || widget.isValid(); }); if (firstInvalidWidget != null) { // set focus to first field with an error firstInvalidWidget.focus(); } }
Now all that is left is to submit the form in the case where all the fields are valid.
5.2 Tutorial Step 5—Processing the Form
NOTE The example provided introduces a new function, dojo.every. This is a special Dojo function that takes an array of objects as its first parameter and a function as its second parameter. The function is then run once for every object in the array with the object being passed as the argument to the function.
5.2.4 Submitting the Form to the Server The next step is to submit the form to the server. Our risk here is to be too smart for our own good.What I mean is that we should not over-think things. Based on what we now know about Dojo, our intuition might suggest that we need to iterate through the field elements, collect the element values, convert them to JSON, and use xhrGet() to create an XHR request to the server.While that is certainly an elegant and workable approach, it is much more complex than is really needed.We can take advantage of the fact that the browser does all those tasks already when a form is submitted. So all we have to do is let the browser continue with its normal process of form submission that we so rudely interrupted. JavaScript provides us with a direct method for submitting a form. In the DOM, form objects have a submit() method, which can be used to cause the browser to perform its normal form submission process.The following code would work. document.forms.custForm.submit()
However, we can do a little better. Because we are using Dojo, we should use a Dojo method when one is available. Although not required in this particular case, the Dojo object that acts as a companion object to the DOM object for this form also contains a submit method. In general, we should use the Dojo method when available because it might be providing some extra functionality or performing some cross-browser incompatibility checking. So we’ll use the following code instead. custForm.submit();
And now we’ve submitted the form. But just for completeness, let’s see the processForm method in its entirety with the final piece of required code in bold. // Process form function processForm { // Re-validate form fields var custForm = dijit.byId("custForm"); var firstInvalidWidget = null; dojo.every(custForm.getDescendants(), function(widget){ firstInvalidWidget = widget; return !widget.isValid || widget.isValid();
63
64
Chapter 5
Processing Forms with Dojo
}); if (firstInvalidWidget != null) { // set focus to first field with an error firstInvalidWidget.focus(); } else { custForm.submit(); } }
The browser will package up the form element values and create an HTTP request to be sent to the server.This request will not be an XHR request, so we’re expecting that the server will be sending an entire new page back to the browser. Because we are using the browser to submit the request, the format of the data is exactly the same as it would have been before we “Dojo-ized” the form. So we don’t have to modify the server process in any way, which minimizes the code changes necessary to implement our new features. As the page works now, the server forwards the user to a completely new page if the form submission is successful. Eventually, we may decide that we would like to evolve the server process to return the error messages or submission status only instead of an entire new page. At that point, we would need to change our form to submit an XHR request instead and to handle the response on the page. But for now let’s leave that effort for another day and declare victory on our new form! Summary The dojo.form.Form object can be used to replace the standard HTML form object by adding dojoType=” dojo.form.Form” to the form tag. We can interrupt the normal form submission performed by the browser by using the execute attribute of the Dojo form to name a method to be called when the user submits the form. To have the browser submit the form, use the submit() method of the Dojo form object.
Now that we’ve seen the general techniques for adding some neat widgets to our web page, it would be interesting to see all of the kinds of widgets that Dojo provides. Part II, “Dojo Widgets,” describes many of the widgets available to us right out of the box with Dojo.We also explore how we can modify and extend the widgets and even create brand new widgets of our own.
II Dojo Widgets
6
Introduction to Dojo Widgets
7
Dojo Form Widgets
8
Dojo Layout Widgets
9
Other Specialized Dojo Widgets
This page intentionally left blank
6 Introduction to Dojo Widgets
Pay no attention to that man behind the curtain! —The Wizard of Oz
W e aren’t going to follow the advice of this quote. In this chapter we pull back the curtain on Dojo widgets and reveal their secret inner life. It is a life of purpose and utility achieved with simplicity and yet, like a duck furiously paddling just beneath the water line, there is lots going on under the surface.We explore the internal workings of Dojo widgets and acquire a foundation of knowledge for using them effectively.
6.1 What Are Widgets? Describing exactly what a widget is (and isn’t) turned out to be harder to do than I thought it would be at first. As I did a little research I came across a wonderful definition in, of all places, some Red Hat Linux documentation.The definition describes a widget as “a standardized onscreen representation of a control that may be manipulated by the user. Scroll bars, buttons, and text boxes are all examples of widgets.”1 What a great description. Note Another interesting fact is that “widget” is short for “window gadget”—who knew?
1. Red Hat Linux 6.2: The Official Red Hat Linux Getting Started Guide: http://www.redhat.com/docs/ manuals/linux/RHL-6.2-Manual/getting-started-guide/ch-glossary.html.
68
Chapter 6
Introduction to Dojo Widgets
Let’s tease out each of the elements of the definition and see what it means for us. n
A widget is an onscreen control—Widgets are visual elements on the page that provide a way for the user to manipulate some data or functionality of the application. One of the simplest widgets is an HTML check box. It appears on the page, and by checking it, the user is setting some data values that will eventually be sent to the server. And though a widget must be on the page, it doesn’t necessarily have to be visible. It may sometimes be temporarily hidden.
n
A widget is standardized—The widget should work the same way everywhere and should have some intuitive or obvious behavior. Also the widget should follow generally accepted patterns of usage and behavior.Within the Ajax world, this criteria is not always met. Some widgets are used in such a limited role or are so new that standardized behavior hasn’t been defined yet. A widget can be manipulated by the user—The purpose of a widget is to allow the user to set some data or control the functionality of the system in some way. So just because there is a visual element on the page doesn’t mean that it is a widget. A widget contains data—Although this isn’t in the definition, it is also a crucial fact in understanding widgets. A widget contains some state that can be manipulated. For instance, an image isn’t a widget even though it is an element on the page. However, a slide show of images is a widget because not only can the user manipulate it, but it also contains state information (the current image in focus, for example).
n
n
Are the existing standard HTML controls such as check boxes and radio buttons also widgets? I would argue that they certainly are. However, the small number of widgets provided by HTML don’t give us enough variety. A really good widget matches itself to the functionality the user expects for a given feature of an application. An excellent example of this is the “crop” widget in Photoshop.The icon shows a picture of an actual physical cropping tool used in film-based photography.The icon also allows the user to set the crop area in a fashion similar to the real tool. However, there is no “cropping” widget in HTML. Nor are there widgets to match much of the functionality we’d like to provide in current browser-based applications.There are too many missing widgets in HTML. Dojo provides some of these “missing widgets” that HTML should have given us.
6.2 What Are Dojo Widgets? We just discussed a general definition for widgets, but we can further ask exactly what Dojo widgets are. First a short definition: A Dojo widget is a collection of DOM elements and JavaScript objects that work together to provide a single control for manipulating the application.They are combinations of DOM elements on the web page that
6.2 What Are Dojo Widgets?
act together to provide a visual component that provides the widget characteristics that we’ve already discussed.The great thing is that you don’t have to write code for them. Dojo has provided everything you need to add your widget to a web page and start using it. Although you probably understand what a widget is now and probably already knew before we defined it, we discuss one of Dojo’s most popular and most complicated widgets here, the Rich Text Editor. Here’s a picture—which is not only worth a thousand words but will let you edit a thousand words as well!
Figure 6.1
Dojo Rich Text Editor widget
This editor is really an HTML widget on steroids. It allows you to create multi-line text and apply various styles to it. It’s like having a word processor built right into your web page. So Dojo widgets are simple to use, are they? We just “add” them to a page? Exactly how do we do that? Following is an example of HTML markup that places a Dojo widget on a web page.
See, it was simple! The only “magic” (if you can even call it that given how simple it is) is to include the dojoType attribute and name the desired widget.There is one other small step, and that is to include the code for the widget by putting a dojo.require("dijit.form.TextBox") statement somewhere in the JavaScript. And of course, this example doesn’t take full advantage of customizing the widget. It is also possible to set properties of the widget by using additional attributes in the tag. Note Notice how the code is referring to “dijit”? This is the module, known as Dijit, that contains the code and other artifacts for creating Dojo widgets.
There is also a technique for creating Dojo widgets using JavaScript that is quite simple also.We just create an object using the desired constructor and then add it to the DOM for the page. Following is an example of how to add a Dojo TextBox to a web page (this example assumes there is a DOM element named placeHolder to which we can attach the widget). new dijit.form.TextBox({}, dojo.byId("placeHolder"));
69
70
Chapter 6
Introduction to Dojo Widgets
The first parameter is an object containing properties of the widget to be created. Although we’re not setting any in the example, there certainly are many possible properties that can be used to customize the widget. Also the second parameter is a DOM element to which we can attach the new widget.Without a reference to an existing DOM node, the new widget would be created but wouldn’t be part of the page.This is a common mistake to make when you’re first learning to work with widgets. Now that we’ve described Dojo widgets in a top-down fashion, if you’re like me, let’s dive into and explore the technical details.We’ll drill down to the atomic level and see what elementary substances make up a widget.
6.3 Components of a Dojo Widget Every Dojo widget consists of three elements, as follows.
n
The structure defined in HTML tags The look defined in CSS styles
n
The behavior defined with events and event handlers in a JavaScript object
n
Let’s walk through each of these elements in more detail using an actual widget from Dojo as an example to clarify these areas further.
6.3.1 Widget HTML A Dojo widget is a collection of DOM elements created from the HTML tags that describes its structure.The HTML for each widget is contained is a separate file and saved in a special directory.The following example will describe one HTML file and identify its location.The example will explain the general technique that all widgets use to define their structure in HTML. Let’s start with one of the simplest widgets, a text box.This widget replaces the standard HTML text field. Following is an example of a simple text field that would allow the user to type in an address. Address:
This field in this example is preceded by a label that describes the field on the web page. Figure 6.2 shows how this field would display on a page (in the absence of additional styling).
Figure 6.2
Standard HTML text box
6.3 Components of a Dojo Widget
We’re going to replace this standard HTML widget with the Dojo equivalent, using the declarative method.This means we’ll use HTML markup within the body of the page to define the widget.The alternative is to use the programmatic method that uses JavaScript.The following HTML markup would build the Dojo widget.
(Plain HTML ) Address:
(Dojo Widget) Address:
I also added some additional HTML to include the regular widget, the Dojo widget, and just a bit of formatting. Figure 6.3 shows how the original HTML text box and the Dojo text box would appear.
Figure 6.3
Dojo text box compared with standard HTML text box
Remember, for the example to work, we’ve got to make sure we’ve included Dojo, started the parser, and included the widget code.We’ll repeat the code for this here, but for more detail, see the tutorial in Part I, “A Dojo Tutorial.”
There are some obvious differences between the plain HTML widget and the Dojo widget. For instance, the background color for the Dojo widget is yellow.Why do these differences exist? To answer that question we need to examine the actual DOM elements that have been created.We’ll use the Firebug plug-in for Firefox to see the DOM elements represented as HTML.
(Plain HTML ) Address:
(Dojo Widget) Address:
Firebug looks at the DOM after it is modified by the JavaScript on the web page and converts the DOM back to the equivalent HTML.You might expect that the HTML displayed from Firebug should be the same as the HTML we created in the original source for the page. And in the case of the HTML for the plain text widget, it is. However, the Dojo parser looks for Dojo widgets defined in HTML and replaces them with additional DOM elements and attributes.That is why the HTML we see from Firebug for the Dojo widget seems so much different from the HTML we typed into the source page. Why are the differences there? The obvious answer is that Dojo put them there. But how? Dojo does it by replacing the entered HTML with alternate HTML, which it calls a template.The template contains most of the replacement HTML with a few hooks where Dojo can add some additional information. Let’s review the HTML template for this widget. First we have to find it.The HTML markup containing the structure of a widget (its template) can be found by looking for its “template” directory in the path corresponding to its package name. Our widget is in the package “dijit.form,” so we should look for the template subdirectory at “dijit/form/template” as shown in Figure 6.4.The figure shows only the relevant directories and files, and your directory structure may be slightly different depending on the version of Dojo you are using.
6.3 Components of a Dojo Widget
Figure 6.4
Location of templates directory in dijit.form package
Below is the code in the “TextBox.html” file. It’s been reformatted by adding some line breaks to make it more readable. Otherwise, the code shown is exactly as what is in the file.
Now we can see why the HTML from Firebug looks different than what we entered in the source file. It has simply been replaced by the preceding template file. However, there are a few differences—a few places where Dojo has changed the value in the template.The first difference is in the following line from the template file. name="${name}"
Compare this to the same line from Firebug: name="address"
73
74
Chapter 6
Introduction to Dojo Widgets
How did “${name}” from the template get replaced with “address” in the final HTML? This was done by the Dojo parser, which looks for values in the template and replaces them with attributes from the actual HTML.The “$” character is a special symbol used to name a variable in the template file that will be replaced with an attribute value from the HTML markup with the same name. In other words, the name attribute from the HTML markup in the source was used. Remember, the name attribute was in the original HTML as shown as follows in bold.
(Plain HTML ) Address:
(Dojo Widget) Address:
This value replacement is a general purpose process that can be used to substitute any attribute value into the template. It is a way of passing data from the HTML markup to the template.The same mechanism is used to pass type="text" into the template as well for the assignment of the type="${type}" line. The id and widgetid attributes in the template are created automatically by Dojo. They can be assigned by setting the value of these attributes in the markup. In this case, Dojo made up some values based on a simple naming scheme. There are also some new attributes that don’t seem to come from the template.These are autocomplete, tabindex, and value.They have also been added automatically by Dojo for this widget type. Different widget types also have some unique properties added.We explore these in later chapters when we examine individual widgets. We now have a much better idea how Dojo is updating the DOM for this widget. However, there are still some open issues. For example, why does the text area for the Dojo widget appear longer and with a slightly different border? We need to examine how Dojo applies styles to widgets.
6.3.2 Widget Styles You may have noticed that the Dojo TextBox widget does not look the same as the standard HTML text box.This is because Dojo has applied some special styling to the widget. One of the three primary elements of every Dojo widget is the set of styles associated with it. How does the style get applied? We can answer that by examining one of the attributes in the DOM element for the widget we’ve been discussing.The following code comes from the HTML defined in the template file for the TextBox Dojo widget. class="dojoTextBox"
The class attribute is used to associate various styles to the DOM element.The specific styles are unique to each widget.The TextBox widget uses only a single style, but many Dojo widgets use multiple styles.The various Dojo widget styles are defined in CSS files, which can be found in the Dojo directory structure.
6.3 Components of a Dojo Widget
Inside the subdirectory “dijit/themes” we can find the file “dijit.css.”This file contains the styles for most of the Dojo widgets. Additionally, Dojo also provides a number of alternative themes that can be used to apply additional styling beyond the default. Figure 6.5 shows a screen shot of the directory structure used to hold the various style sheets including images used by the styles.
Figure 6.5
Location of Dojo widget styles files
We’ll look inside the “dijit.css” file and see if we can find the style information related to this widget.With just a bit of searching, we can find the following style definitions. .dijitTextBox, .dijitComboBox, .dijitSpinner { border: solid black 1px; width: 15em; }
This code assigns a solid black border to any DOM element whose class is either dijitTextBox, dijitComboBox, or dijitSpinner. It also assigns these elements a
default width of 15em.The “em” is a unit of measure roughly equivalent to a character at the current font size.2 You can customize the style of a Dojo widget by adding properties to the appropriate style. For instance, if we wanted the background color of all TextBox widgets to be yellow, we could simply add the background property to the dijitTextBox style. 2. For a more detailed explanation of “em,” you can read the Wikipedia explanation at http://en.wikipedia.org/wiki/Em_%28typography%29.
75
76
Chapter 6
Introduction to Dojo Widgets
Of course, you’ll probably want to include this in a separate CSS file so that you can use it from all your pages.This would allow you to create your own style on top of the Dojo default style. Dojo has done some of this work for us already.They’ve provided an additional style called Tundra that you can use as a base or as a model for your own themes. We’re heading toward a complete understanding of Dojo widgets. Are we there yet? Not quite.There is one more element we need to review to complete our understanding of Dojo widgets. Now we’ll look at the JavaScript code associated with each widget we create.
6.3.3 JavaScript Component of a Widget A widget is a control that possesses behavior. But where does all that behavior reside? The functionality of a widget is provided by a JavaScript object associated with the widget that contains properties and methods not contained in the DOM element. The JavaScript object is created from a constructor function defined for each widget. In the example we’ve been following for dijit.form.TextBox, we can find that constructor function in a file within the “dijit/form” subdirectory. Notice how the widget package name corresponds to a subdirectory in the Dojo directory structure. Figure 6.6 is a screenshot of the directory structure for TextBox showing only the files relevant for our example.
Figure 6.6
Location of Dojo widget JavaScript file
6.3 Components of a Dojo Widget
When we open up the “TextBox.js” file we will find the following code near the top of the file. dojo.declare( "dijit.form.TextBox", dijit.form._FormWidget,
The dojo.declare function will be described in more detail in Chapter 12, “Objects and Classes,” when we discuss Object Orientation, but here’s a brief description of it now.The dojo.declare function creates a constructor function that can be used to build new objects.The first parameter is the name of that constructor function.The next parameter defines the super class for the object being created.The new object will inherit all the properties and methods from the super class. Additional code (not shown) describes properties and methods in the object created by the constructor.To create a new object after dojo.declare has been defined, you just use the standard JavaScript technique for object creation using the new keyword. newWidget = new dijit.form.TextBox();
The variable newWidget will now reference a JavaScript object.This object is not the DOM element itself, but a separate object associated with the Dojo widget. Like the wave/particle duality of light, Dojo widgets also have a dual nature existing as both a DOM element and a JavaScript object. As we’ve already discussed, there are two ways to create a Dojo widget—declaratively by including HTML markup or programmatically by using the new keyword as the preceding example shows.When we’re creating the widget using HTML markup, the Dojo parser automatically creates the widget object for us. So in both cases, the widget object is built from the constructor, but when using HTML markup, we don’t have to write the code ourselves. What kinds of properties and methods are included in the constructor code? It all depends on the specific functionality of the widget. Each widget constructor is different, but there are some common characteristics.They all contain the following types of properties and methods: n
Attributes—An attribute is a property of the object that is used to specify some behavior or characteristic of the widget. It can be set by passing a parameter when calling the constructor function or by setting an attribute value in the HTML markup when declaratively creating the widget. In general, it is set only when the object is created. However, some widgets allow these properties to be modified by using special methods following the setter/getter naming convention. For example, an attribute called value could be set by calling a method named setValue and passing the new value of the property.This technique is familiar to Java programmers who use JavaBeans.You should use these methods when they exist and avoid setting properties directly in the widget objects.
77
78
Chapter 6
n
n
Introduction to Dojo Widgets
Behavioral Methods—These are the functions that define the specific behavior of the widget.These are different for each widget depending on what the widget does. Extension Points—These are really just methods, but they have a special role. They are meant to be overridden by developers to change the default behavior of the widget.This is a very powerful feature of Dojo widgets.You don’t have to just take what you get. Dojo widgets are built with the expectation that you can modify and extend them.These methods are not called directly but instead are called by other methods at a certain point in the lifecycle of the object—for example, when a widget object is created or deleted.The default implementation of the methods (the code inside them) usually does nothing.They just provide the developer with a place to add functionality to the object.
We talk about the specific properties and methods for Dojo widgets when we review each widget in subsequent chapters. But there are some specific examples of these components that all widgets share, which we can discuss now.
6.3.4 Dojo Widget Hierarchy There are many different kinds of Dojo widgets available to us. And although each type of widget is unique, they share many common features.To understand how a widget acquires these shared features, we need to understand a little about an object-oriented programming concept called inheritance.This is the idea that we can build new objects by inheriting the capabilities of existing objects. All Dojo widgets have some similarities. One of the most important ways they are similar is that they all descend from a few classes from which they inherit a number of special properties and methods. In objectoriented programming languages, these special ancestor objects are knows as abstract objects because they can’t be built into usable objects themselves. They are not standalone widgets but act as placeholders for inheritable properties and methods. Let’s review Figure 6.7, which allows us to visualize the various widget classes and their relationships.
6.3 Components of a Dojo Widget
Interfaces (Mix-Ins) dijit._Templated
dijit._Container
dijit._Widget
dijit. form_FormWidget
dijit. layout_LayoutWidget
Button DropDownButton ComboButton ToggleButton CheckBox RadioButton TextBox ValidationTextBox MappedTextBox RangeBoundTextBox NumberTextBox CurrencyTextBox TimeTextBox DateTextBox ComboBox FilteringSelect Form
LayoutContainer SplitContainer StackContainer AccordianContainer ContentPane TabContainer
Figure 6.7
Other Specialized Widgets
Menu Toolbar ProgressBar Tooltip TooltipDialog Dialog ColorPalette Tree Slider Number Spinner InlineEditBox Textarea Editor
Dojo widget hierarchy
The diagram shows the overall relationship between the major widget classes.The diagram only shows a highly selective and abbreviated description of the class hierarchy for widgets.We’ll drill down more into these in later chapters. But I think it would be helpful now to at least get a brief description of some of the classes shown in the diagram. n
dijit._Widget—This is the root class for the hierarchy. Every widget is a sub-
class of this class. n
dijit._Templated—This class provides methods for subclasses that can be built
from templates of HTML code. Java programmers are accustomed to single inheritance, but Dojo provides a type of multiple inheritance by allowing an object to inherit from more than one class. Another way to think of this class is as an interface.
79
80
Chapter 6
Introduction to Dojo Widgets
n
dijit._Container—This class provides methods for objects that can contain
n
other widgets as children.This class can also be thought of as an interface. dijit.form._FormWidget—This is the root class for widgets that will appear on a form.
n
dijit.layout._Layout—This is the root class for widgets that provide some
n
Specialized Widgets—This isn’t an actual Dijit class, but I’m using it as a place-
kind of a layout mechanism that can contain other widgets. holder for all the Dojo widgets that are not part of the Form or Layout package. Figure 6.7 contains many other widget classes besides those just described.We discuss these in detail in Chapters 7, 8, and 9, but we should describe some of them now.We’ll start with the most important class, dijit._Widget. 6.3.4.1 dijit._Widget The abstract class dijit._Widget is the root class from which all widget objects descend. Notice a few characteristics of the class name that give us hints about its purpose. One is the use of the underscore character in the name.This tells us that this is a class to be used internally by Dojo—we won’t create instances of this class ourselves as Dojo users.The other hint is that there is no subpackage name, which tells us that this class applies to all widgets. So this class is the “mother” of all widgets. It has properties and methods that are shared by every Dojo widget object that we will create.Table 6.1 shows some of the important ones. Table 6.1
Key Properties of dijit._Widget Object
Property
Description
id
This is a unique identifier for the widget that can be assigned by Dojo or by the developer.
class
HTML class attribute.
style
HTML style attribute.
title
HTML title attribute.
srcNodeRef
Reference to the DOM element in the page associated with this widget prior to processing by the Dojo parser.
domNode
This is the root-level DOM element representing this widget. This is the node that is added to the DOM. This node may exist without actually yet being associated with the DOM.
Table 6.2 shows some of the methods in dijit._Widget.
6.3 Components of a Dojo Widget
Table 6.2
Key Methods of dijit._Widget Object
Method
Description
create
This function creates the widget.
postCreate
This is a stub function that you can override to modify take actions after the widget has been placed in the DOM. There is no requirement to call this function.
startup
This is a life-cycle function that can be called after the all the widget’s children have been created but not yet displayed. This is a stub function containing no code. There is no requirement to call this function.
postMixInProperties
This is a life-cycle function that can be used to override properties in the widget. It is a stub function containing no code. There is no requirement to call this function.
buildRendering
This function actually creates a DOM element for the widget. This function can also be overridden by code in the dijit._Templated object, which builds the DOM element from a template of HTML code. This function does not add the element to the DOM for the page.
destroyRecursive
Destroy this widget and its descendants.
getDescendants
This function returns all the children of this widget.
connect
This function is used to associate an event handler with a function within the widget.
disconnect
This function is used to remove an event handler from the widget. It is the reverse of connect.
It isn’t enough just to know what methods are available in dijit._Widget.We also need to know when they are called and how. In other words, what are the lifecycle methods for each and every widget? Fortunately for us, it is pretty easy to create a good idea of the important methods by looking at the create method for Widget.This is the method that is called when a widget is created, either by the parser as it works through the HTML or by the constructor function of the widget we are building programmatically. Following is the main code from the create method.The code has been reformatted and some additional comments added to further explain the comments you have read in these sections. //mixin our passed parameters if(this.srcNodeRef && (typeof this.srcNodeRef.id == "string")){ this.id = this.srcNodeRef.id; }
81
82
Chapter 6
Introduction to Dojo Widgets
if(params){ dojo.mixin(this,params); } this.postMixInProperties(); if(!this.id){ this.id=dijit.getUniqueId(this.declaredClass.replace(/\./g,"_")); } dijit.registry.add(this); this.buildRendering(); // Copy attributes listed in attributeMap into // the [newly created] DOM for the widget. . . . if(this.domNode){ this.domNode.setAttribute("widgetId", this.id); } this.postCreate(); // If srcNodeRef has been processed and removed // from the DOM (e.g. TemplatedWidget) then delete it to allow GC. if(this.srcNodeRef && !this.srcNodeRef.parentNode){ delete this.srcNodeRef; }
Let’s walk through each section and describe the key processing steps.
Table 6.3
Key Methods Called as Processing Steps During Widget Creation
postMixInProperties:
A stub function that you can override to modify variables that may have been naively assigned by the mixInProperties# widget is added to the manager object here.
buildRendering
Method which performs UI initialization including attachment of additional DOM nodes to the root DOM element for the widget.
postCreate
A stub function that you can override to modify take actions after the widget has been placed in the UI.
6.3 Components of a Dojo Widget
6.3.4.2 dijit._Templated This is an interesting class from which many widgets descend. I think of it like an interface in Java.This provides special properties and methods that allow a widget to be created from a template (a string of HTML) rather than instantiated programmatically.
6.3.5 Visual Overview of Dojo Widgets At this point it would be useful to see some of the widgets.This will give you a good idea of the breadth of the Dojo widget set.The widgets are divided into general categories that correspond to the way the widgets are packaged. Most of these widgets have numerous properties that can be set to enable additional functionality.We only show the simplest version of each widget just to give you an idea of what they do.We drill down into each widget in subsequent chapters and see their full power. Many of these examples are modified versions of test pages available in the Dojo distribution directory at “dijit/tests.” 6.3.5.1 Form and Data Widgets These widgets appear in the form package.Their basic purpose is to display some data and provide the user with a way of modifying that data that is appropriate for the data type. Table 6.4
Examples of Form Widgets
Description Button This replaces the standard HTML button. It looks nicer and has a slightly better effect on rollover. DropDownButton When this button widget is clicked, it will display whatever widget is defined as its child. In the example, the leftmost widget is the widget before it is clicked. The rightmost example shows the same widget after it has been clicked. It displays its child widget, which in this case is a ColorPalette but could be any valid widget (menus are very typical).
Example
83
84
Chapter 6
Introduction to Dojo Widgets
Table 6.4
Continued
Description ComboButton This widget combines a regular Button widget with a DropDownButton widget, hence the name ComboButton. The leftmost example shows the widget before the down arrow is selected. The rightmost example shows the widget after the down arrow icon has been checked. The user can click either on the down arrow icon or on the button itself. ToggleButton This button looks the same as a regular Button but behaves differently. When the button is clicked, the button CSS as well as the icon CSS can change. CheckBox This replaces the standard HTML checkbox. It looks nicer and has a better check icon.
RadioButton This replaces the standard HTML checkbox. The advantages are a nicer look and a better checked icon. FilteringSelect This widget is an enhanced version of the HTML tag. One improvement is that when text is typed in the field it will be used to “filter” possible values from the full list of data. In this example, typing i causes the widget to only display states that begin with “I.” The data list could be static (provided in the HTML page) or could be acquired from the server using Ajax.
Example
6.3 Components of a Dojo Widget
Table 6.4
Continued
Description NumberSpinner This is really just a text box for entering numbers but with a special feature: Up and down arrow keys can be used to increase or decrease the value instead of the person having to type it directly. Slider This widget is also a replacement for a simple numeric text value, but instead of entering the number directly you drag an icon (the slider) across a bar of values. The value for the widget is determined by the position of the slider on the bar. Textarea This widget is a replacement for the standard HTML tag. The primary additional feature of this widget is that it “grows” vertically instead of “scrolls” vertically. As you type, the size of the box expands to hold the text rather than displaying scroll bars to the side. TextBox This widget is a replacement for the HTML tag.
ValidationTextBox This widget extends TextBox and adds various kinds of validations including those for dates, times, and numbers. Messages and prompts are automatically displayed.
Example
85
86
Chapter 6
Introduction to Dojo Widgets
Table 6.4
Continued
Description
Example
DateTextBox This widget extends TextBox by providing the user with a calendar metaphor for selecting a date. The widget looks like a TextBox on the page, but when the field is in focus, a pop-up calendar appears. This is a complex widget possessing a number of controls that allow the user to sequence through days, weeks, or years. And, of course, the look is easily customized by the developer.
6.3.5.2 Layout Widgets These widgets appear in the layout package. Table 6.5
Examples of Layout Widgets
Description LayoutContainer This widget provides a technique for dividing the page into separate areas for placing content. The areas can be aligned to the “top,” “bottom,” “right,” or “left.” Think of this widget as a replacement for using a table to provide layout.
SplitContainer This widget allows the user to define different areas, either vertically or horizontally, that can contain content. Between the areas is a border dragged to change the relative sizes of the panes. Any content within a pane can be automatically reformatted. The callout is not part of the widget.
Example
6.3 Components of a Dojo Widget
Table 6.5
Continued
Description StackContainer This is a container that has multiple children but only displays a single child at a time. It usually depends on some external control (like the prior page and next page buttons in this example) to allow the user to trigger the display of a different child. Otherwise, it looks like a typical ContentPane. AccordianContainer This widget acts as a container for its children. Only one child at a time is displayed (as with the StackContainer). However, the controls are built into this widget and display as pane titles with an arrow icon that can be used to collapse the displayed content and expand the hidden content. ContentPane This widget that acts as a container for other widgets and includes the capability for dynamically loading content using Ajax. TabContainer This widget acts as a container for its children and only displays a single child at a time. However, just like the AccordianContainer, its controls are built in and appear as tabs. By selecting a particular tab, the content associated with that tab is displayed.
Example
87
88
Chapter 6
Introduction to Dojo Widgets
6.3.5.3 Other Specialized Widgets These are other widgets. Table 6.6
Examples of Other Specialized Dojo Widgets
Description InlineEditBox This widget displays text that will be highlighted when the user places the mouse over it. Clicking the highlighted text causes it to be replaced with a different widget that can be used for editing. In this example, the user clicks the word “running” in the first line, which is then replaced with a TextBox that the user can enter a new value in. Menu This widget displays a popup menu that can be nested as deeply as the developer wants. Menu items can be separated with a line icon or disabled.
Toolbar A toolbar presents a series of options or icons that can display additional content (including submenus) or trigger some process to occur.
ProgressBar This widget is used to represent the completion state of a process. In this example, the current state of the widget is shown as a number (i.e., 10%), and the bar is partially filled in at the left.
Example
6.3 Components of a Dojo Widget
Table 6.6
Continued
Description Tooltip This widget displays a popup.
TooltipDialog Pops up a dialog that appears like a Tooltip. It may contain any content including a form. The page behind the widget is still active.
Dialog This widget provides a pop-up dialog containing content that may include a form (as shown in the example). When the dialog appears, the original page is disabled. This is sometimes known as a modal dialog. The page does not become active until the dialog is dismissed.
ColorPalette This widget displays color swatches that can be selected by the user. The widget will automatically convert the selected color into its RGB value for use inside the page.
Tree This widget displays data in a hierarchical tree with nodes that can be expanded or collapsed. You can specify an icon for each node. One of the major features of the tree widget is the ability to build itself from data on the server by making Ajax requests when either the tree is first built or when nodes are expanded.
Example
89
90
Chapter 6
Introduction to Dojo Widgets
The visual guide provides a quick introduction to many of the widgets available to you in Dojo. However, there are some we didn’t cover, which we review in subsequent chapters. Also remember that Dojo is constantly being improved, and new widgets are becoming available all the time.
6.3.6 Building Your Own Widgets Dojo widgets are highly customizable.You can change the way they look by changing their style properties.You can control their behavior by setting properties and by providing overrides to the various life-cycle methods. However, sometimes you may just want to build your own widget.The various base classes such as dijit._Widget, dijit.form._FormWidget, and dijit.layout._LayoutWidget are perfect starting points for creating new widget classes of your own. Summary The dijit module in Dojo provides a toolbox of widgets that can be easily added to a web page. Dojo widgets can be created declaratively by using HTML tags with the dojoType attribute. For example
Dojo widgets can be created programmatically by using JavaScript by creating new objects with the Dojo widget constructors (don’t forget to add the object to the DOM). For example new dijit.form.TextBox({}, dojo.byId("placeHolder"));
Be sure to include the dojo.require statement so that the Dojo parser knows how to get the code for the widgets you are using on the page. For example dojo.require("dijit.form.TextBox");
Widgets have three primary components that make them very easy to customize: n
HTML for their structure
n
CSS for their styling
n
JavaScript for their behavior
Dojo provides many useful widgets right out of the box. See the visual guide in section 6.4 for a quick walkthrough. Dojo widgets are highly customizable, but you can also build your own using the existing Dijit base classes such as dijit._Widget, dijit.form._FormWidget, and dijit.layout._LayoutWidget as a starting point.
Now that we’ve seen how Dojo widgets work in general (and we’ve seen some examples of specific widgets), we can begin a detailed study of the various widgets available in Dojo.The next chapter explores each of the Form widgets in detail.
7 Dojo Form Widgets
…and the world was without Form… —Genesis
A s with creation, there was a point when the World Wide Web itself was also without form, tags that is. But we certainly have them now, and they are the primary
technique for gathering data from the user. Standard HTML provides a number of useful form widgets such as text boxes, radio buttons, check boxes, and select lists. However, these widgets are limited and a bit primitive especially considering that users today are clamoring for Rich Internet Applications with user interfaces rivaling those of some desktop applications. Dojo provides replacements for these standard widgets along with many new widgets that can be used in forms to collect information from the user of our pages.This chapter drills down into the details of the Dojo form widgets.
7.1 Standard Forms and Dojo Form Widgets To begin our discussion of form widgets, let’s go back to first principles for a moment. Why do we need forms at all? We need them so that we can capture data from the user and send it to the server for processing. But we don’t really send forms to the server; we send the individual data elements. Remember what a query string looks like in a URL? Here’s an example of something you might see in the address bar of the browser: submit.jsp?name=Joe&id=123&type=new
In this example we have three data fields being sent from the browser (name, id, and type) along with their values (“Joe,” 123, “new”). But where is the form? The form is the aggregation of the data but doesn’t appear as a distinct component in the URL. However, within the HTML for the page, it certainly has a distinct identity and its own tag: . We need it so we can specify characteristics of the entire form such as the
92
Chapter 7
Dojo Form Widgets
action (server resource to be requested) and the method type (“GET” or “POST”). So we need a form widget, and Dojo provides one for us that allows us to treat the form as a Dojo object and gives us a few additional methods that make it easier to use. However, the real meat in this chapter is in the form element widgets.These are the components that capture the actual data and associate it with a logical name to be used on the server.To make this more concrete, let’s look at just one of the name/value pairs from the prior URL example. id=123
From this we can tell that there is a field (or variable) called “id,” which was given a value of “123” by the user.This doesn’t tell us anything about how the user entered the value. Did they do it by typing it in, selecting it from a pull-down list, or maybe even just checking a radio button that was associated with the value.The server doesn’t know, and it doesn’t care—and it shouldn’t.The server just cares about the data value. But for the user, the “how” is very important.They need a widget that makes it easy and intuitive for them to enter the right value. And that is why we need a number of form widgets—to present different metaphors to the user for entering and validating data. So for us, a form widget is simply a visual component of the page that captures a single data value but does it in a way that corresponds to the user’s understanding of the data. For example, the technique for selecting a data value for a date should be different than that of selecting an RGB value for color. Each should have its own unique visual metaphor, and Dojo provides snazzy widgets for both! Now let’s explore the technical details of the Dojo form widgets.
7.1.1 The dijit.form._FormWidget Class Form widgets are used to capture entered values from the user so that the data can be submitted to the server.The simplest examples of these widgets are the replacements for the standard HTML form elements such as text fields, multi-line text fields, radio buttons, check boxes, and select lists. Each acts as an individual data element on a form. Dojo provides us with souped-up versions of these HTML elements along with some new widgets that have no HTML counterparts. Although there are many different Dojo form widgets, they have many common features.The Dojo widgets are built using an object-oriented approach, which implies that a new widget should be able to inherit properties from more general widgets.The most general widget of all is dijit.form._FormWidget, which can be described as “the mother of all form widgets.” In other words, any Dojo widget we create in the form package inherits properties and methods from this class. Remember, inheritance is additive. A form widget will possesses all the properties and methods in its own class plus any from the dijit.form._FormWidget class. And also remember that in Chapter 6 we studied the base class for all widgets: dijit._Widget.The form widget dijit.form._FormWidget is a subclass of dijit._Widget, so any individual form widgets would also inherit all dijit._Widget methods and properties.
7.1 Standard Forms and Dojo Form Widgets
Let’s review the properties and methods that all widgets have in common by studying the members of the dijit.form._FormWidget class.We’ll review the key properties and methods.To see a full list of every property and method, you should review the source code for the widget. 7.1.1.1 Properties in dijit.form._FormWidget You may notice that many of the properties have a null value in FormWidget.This is because they are common properties of all form widgets, but each specific widget must assign its own value for the property.The reason that they don’t need values in FormWidget is that we will never build a FormWidget object directly.We’ll build one of its subclasses.That makes FormWidget an abstract class. Table 7.1
dijit.form._FormWidget Properties
Property
Default
Description
baseClass
null
CSS class for this widget used to associate styles.
alt
null
Used to assign the alt attribute of the HTML tag associated with the widget.
value
null
Used to assign the value attribute of the HTML tag associated with the widget. This is the most important property of the widget: its data value.
name
null
Used to assign the name attribute of the HTML tag associated with the widget.
tabIndex
"0"
Used to assign the tabIndex attribute of the HTML tag associated with the widget. This determines the order in which the cursor moves through the fields.
disabled
false
Determines whether the user can interact with this widget. A value of true turns the widget off, but it is still displayed (usually with a different style) while a value of true makes the widget usable.
We seem to be missing some important properties. For instance, where is the style property that defines styles for a DOM element? Remember, dijit.form._ FormWidget inherits from dijit._Widget, and it is dijit._Widget that contains the definition for the style property. 7.1.1.2 Methods in dijit.form._FormWidget Here are the key methods for dijit.form._FormWidget. Again, these aren’t all the methods, just the ones I felt were important.There are more in the source code.
93
94
Chapter 7
Dojo Form Widgets
Table 7.2
dijit.form._FormWidget Methods
Method
Description
setDisabled (disable)
Turns the widget on or off based on the argument disable. Both the DOM element and the widget object are disabled (or enabled). Following is the key line from the method: this.domNode.disabled = this.disabled = disabled;
Notice that both the DOM element and the Dojo widget have a disabled property that is set to the value of the argument to this method. isFocusable()
Returns true if focus can be placed on the widget (it is enabled and visible), otherwise returns false.
focus()
Places the widget in focus. This places the cursor on the widget.
onChange(newValue) This is the method that you would override to add your own behavior to the widget when the user enters some new data. If you look at the code for this method, you’ll notice that it doesn’t do anything. It is a stub method that can be replaced by your own code—although you don’t have to. setValue(newValue) Programmatically change the value of the widget to newValue. This is run automatically when the user enters data. getValue()
Returns the current value of the widget.
undo()
Resets the value of the widget to the last value passed to the onChange method. This method allows the developer to back out a change to setValue without having to write code to store the old value.
7.2 The Dojo Form Widget Explained This section provides a detailed write-up, usually two pages long, describing each of the form widgets in a standard format. But first, the following are some suggestions on how to use these write-ups, and a description of each of the categories in the write-ups. Table 7.3 Widget Name
Legend for Dojo Widget Documentation This is the full name of the widget including the package name. For example, dijit.form.TextBox is the TextBox widget in the package “dijit.form”. Sometimes you’ll see references to only the name of the widget, but that isn’t completely correct. However, in this version of Dojo, widget names are unique within a package but also across all the packages.
7.2 The Dojo Form Widget Explained
Table 7.3
Continued
Super Classes
Widgets inherit properties and methods from their super classes. This shows the class hierarchy for the widget. There are some missing pieces here. Some of the classes that act as interfaces aren’t shown, such as dijit._Templated and dijit._Container. Almost all widgets use these, so showing them would take more space without really adding any value. When you really need to be sure if these classes are used by a widget, check the source code.
File Location
This contains the location of the file containing the JavaScript source code for the widget. You don’t need to look at the source code, but here’s some advice: Don’t be afraid to look at the source code. It is very well written and very instructive. A wise developer once said that a programmer who doesn’t read the source code is really no better than one who can’t read the source code. Let’s not be that developer. This section also contains the JavaScript code necessary to include this widget in your page. Declaring the widget in the HTML is not enough.
Usage
This describes when you might use the widget and describes the behavior of the widget.
Display Examples
This shows you some examples of what the widget would look like on your page.
HTML Markup Examples
This shows the HTML that you would need to include in your page to create the widget. Remember, you can create the widget either in HTML or JavaScript. The HTML markup method is also known as the declarative method.
JavaScript Constructor Examples
This shows the JavaScript code you would need to create your widget. This is the programmatic method of creating the widget. When you create a widget this way, it is not automatically included in the DOM; you need to explicitly attach it; otherwise, it won’t be usable.
Key Properties
These are some of the important properties of the widget. I usually only show properties unique to the class and not the ones that are inherited from super classes. However, sometimes the really important properties are the inherited ones so they are listed.
Key Methods
These are some of the important methods of the widget.
Key Styles
Need explanation from Jim.
Key Events
These are some of the important events of the widget.
Notes
This contains additional items of interest about the widget.
One final note before we begin the form widget write-ups.The write-ups do not attempt to document every aspect of each widget.They provide a summary of each widget.These write-ups balance completeness versus succinctness.When you really need all the details you should go to the Dojo site to review documentation, the API, and the forums.You should also dive into the source code.
95
96
Chapter 7
Dojo Form Widgets
Also there are a few form widgets that are more complicated and specialized. I’ve chosen to put those in Chapter 8, “Dojo Layout Widgets.”These include the Slider, Number Spinner, InlineEditBox,Textarea, and Editor. Table 7.4
Explanation of Dojo Form Widgets
Widget Name Super Classes
dijit.form.Button dijit._Widget
dijit.form._FormWidget
File Location
dijit/form/Button.js Use dojo.require("dijit.form.Button");
Usage
This class will create a button icon that triggers some behavior when clicked. This button replaces the standard HTML and can be used for form submission or anywhere that some action needs to be initiated by the user.
Display Examples
HTML Markup Examples
Create a simple button.
Create a simple button with an icon:
Example CSS for icon .circleIcon { background-image: url(circleIcon.gif); background-repeat: no-repeat; width: 16px; height: 16px;}
Create a simple button with the label defined by placing text in the tag body:
Click here!
Note: This example also shows how to create behavior by assigning a function named handler to the onclick event. It assumes that there is a function named handler that will execute if the user clicks the button.
7.2 The Dojo Form Widget Explained
JavaScript Constructor Examples
Constructor for creating a new Button with a label of “Click me”: new dijit.form.Button({label: "Click me"}, dojo.byId("form1");
This code automatically adds the widget to an existing widget in the DOM whose id is “form1”. If you don’t specify a node for attaching the widget, it will not appear on the page. Key Properties
Key Methods
Key Styles
Property label
Default null
Description Button text
showlabel
true
Label text to be displayed on button
iconClass
null
CSS class containing icon for button
Method
Description
setLabel(label) Change the button label to new value label. This function must be used to change the label once the button has been created. Style Name
Description
dijitButtonText Style for button label text.
Key Events
Event Name
Description
onClick
Clicking the button will cause this event handler to run. Although this method is really part of dijit.form._FormWidget, it is included here on dijit.form.Button because it is the primary method you typically use for this widget.
Notes
You can also attach an onClick event to the widget using JavaScript so that there is a clear separation between the structure (HTML markup) of your widget and the behavior (JavaScript). This example assumes there is a function named handler, and the id of the button is btn1. dojo.connect( dojo.byId("btn1"), "onclick", handler);
97
98
Chapter 7
Dojo Form Widgets
Widget Name Super Classes
dijit.form.DropDownButton
dijit._Widget
dijit.form._FormWidget
dijit.form.Button
File Location
dijit/form/Button.js
Usage
This class creates a button icon that displays its child element when clicked. The child element can be any widget type. This widget is named as it is because it makes the creation of drop-down menus very simple. By default, the displayed content appears just below the button.
Use dojo.require("dijit.form.Button");
Display Examples
The examples here show what the widget looks like before it is clicked and then after. The rightmost image shows how the widget appears after it is clicked. HTML Markup Example
Create a DropDownButton with Menu:
Menu
Cut Copy Paste
In this example, the child widget is a dijit.Menu with dijit.MenuItem widgets attached. Each menu item gets an icon because of the iconClass property. This is a feature of the Menu widget, not of the DropDownButton specifically.
7.2 The Dojo Form Widget Explained
JavaScript Constructor Examples
Constructor for creating a new DropDownButton with a label of “Menu”: btn1 = new dijit.form.DropDownButton({label: "Menu"};
This code creates the widget, but it must be attached as a child of some DOM element to be visible on the page. For this widget to be useful you must also attach a child widget that will be displayed when the button is activated. Let’s say that you’ve already created a Menu widget with items on it (see the description for dijit.Menu for details on how to create menus), and the object name is menu. The DropDownButton provides a special property to attach the widget to the button. btn1.dropDown = menu;
This is necessary because a bit of processing needs to be done to make the widget hidden, so just adding the new widget as a child of the button using addChild() wouldn’t be sufficient. Key Properties
Property Default dropDown(child) null
Description Reference to child widget to be displayed when button is clicked. Don’t use addChild().
Key Methods
There are no additional public methods for this widget, just those that have been inherited from its super classes.
Key Styles
There are no additional public key styles for this widget, just those that have been inherited from its super classes.
Key Events
There are no additional public events for this widget, just those that have been inherited from its super classes.
Notes
The power of this widget comes from its ability to display any other widget on activation, but its most typical use is to display menus.
99
100
Chapter 7
Dojo Form Widgets
Widget Name
dijit.form.ComboButton
Super Classes
dijit._Widget
dijit.form._FormWidget
dijit.form.Button
dijit.form.DropDownButton
File Location
dijit/form/Button.js
Usage
This class creates a button combining the features of a dijit.form.Button and a dijit.form.DropDownButton. When the user clicks the down arrow icon on this widget, it acts as a DropDownButton and displays its child widget. When the user clicks the button outside the down arrow, this widget acts as a Button and runs its onclick event handler. This is useful when some default behavior can be tied to the button while the child widget asks for or applies some restrictions or further characteristics for the behavior. A classic example of this would be where the primary button does a “Save,” but the child widget performs a “Save” or “Save As…”
Use dojo.require("dijit.form.Button");
Display Examples
The rightmost widget shows what would display if the user clicks the down arrow icon on the widget. HTML Markup Examples
Create a ComboButton with a Menu.
Save
Save ➥ Save As
Remember to include dojo.require("dijit.Menu") in your page to use menus.
7.2 The Dojo Form Widget Explained
JavaScript Constructor Examples
Constructor for creating a new ComboButton with a label of “Click me”: new dijit.form.ComboButton({label: "Save"}, dojo.byId("form1");
This code automatically adds the widget to an existing widget in the DOM whose id is “form1”. If you don’t specify a node for attaching the widget, it will not appear on the page. Key Properties
There are no additional public properties for this widget, just those that have been inherited from its super classes.
Key Methods
There are no additional public methods for this widget, just those that have been inherited from its super classes.
Key Styles
Style Name
Description
dijitButtonText
Text for button label.
dijitDownArrowButton
Class for the down arrow icon.
Key Events
There are no additional public events for this widget, just those that have been inherited from its super classes.
Notes
None
101
102
Chapter 7
Dojo Form Widgets
Widget Name
dijit.form.ToggleButton
Super Classes
dijit._Widget
File Location
dijit/form/Button.js Use dojo.require("dijit.form.Button");
Usage
This class creates a button that can be in two states (checked or not). Use this widget to provide users with a means of flipping some internal state. It looks like a regular Button. However, it has a built-in feature to automatically change the button CSS and icon CSS when it is toggled.
dijit.form._FormWidget
dijit.form.Button
Display Examples
HTML Markup Examples
Create a simple ToggleButton:
JavaScript Constructor Examples
Constructor for creating a new ToggleButton with a label of “Click me”:
Toggle
new dijit.form.ToggleButton({label: "Toggle"}, dojo.byId("form1");
This code automatically adds the widget to an existing widget in the DOM whose id is “form1”. If you don’t specify a node for attaching the widget, it will not appear on the page. Key Properties
Property checked
Default false
Description Used to show the state of the widget. If checked is true the button has been clicked, and false if it has not. If the button is clicked again, checked will become false. Remember, this is a toggle.
iconClass
null
CSS style describing the icon shown when the button is clicked.
7.2 The Dojo Form Widget Explained
Key Methods
Method
Description
setChecked(checked)
This function sets the property checked to either true or false determined by the argument of the method.
Key Styles
Style Name
Description
dijitButtonText
Style for the button label text.
dijitToggleButton
Style for the button.
Style Name
Description
dijitButtonText
Style for the button label text.
dijitCheckBoxIcon
Style for the check box icon (a check).
Key Events
Notes
ToggleButton is a base class for checkboxes and radio buttons.
103
104
Chapter 7
Dojo Form Widgets
Widget Name Super Classes
dijit.form.CheckBox dijit._Widget
dijit.form._FormWidget
dijit.form.Button
dijit.form.ToggleButton
File Location Usage
dijit/form/CheckBox.js Use dojo.require("dijit.form.CheckBox"); This class creates a widget that can be in two states (checked or not). These widgets can be combined into a group. This is a replacement for the HTML tag. Although only a single widget is required, you would usually use multiple instances for each possible checkbox item. As with standard HTML, you can use the same value for the name attribute to link the individual checkboxes together into a group.
Display Examples
HTML Markup Examples
Create a simple CheckBox.
JavaScript Constructor Examples
Constructor for creating a new CheckBox:
Checked
Unchecked
Checked and Disabled
new dijit.form.CheckBox({name: "c1", checked: true});
This constructor only created the CheckBox not the label that usually goes along with it. You would also have to create the label and attach both it and the CheckBox to the DOM.
7.2 The Dojo Form Widget Explained
Key Properties
Key Methods
Key Styles
Property checked
Default false
Description Used to hold the state of the widget. If checked is true, the button has been clicked and false if it has not. If the button is clicked again, checked will become false. Remember, this is a toggle.
name
null
Assigns the name attribute in the tag associated with this widget. This is especially important in this widget because it is also used to assign multiple instances of this widget to a single group.
Method
Description
setChecked( Boolean) Set the property checked to either true or false based on the argument of the method. Style Name
Description
dijitButtonText
Style for the button label text.
dijitCheckBoxIcon
Style for the check box icon (a check).
Key Events
Style Name
Description
onClick
Checking the box will cause this event handler to run. Although this method is really part of dijit.form._FormWidget, it is included here because it is the primary method you typically use for this widget.
Notes
Use an tag rather than a tag for dijit.form.CheckBox.
105
106
Chapter 7
Widget Name Super Classes
Dojo Form Widgets
dijit.form.RadioButton
dijit._Widget
dijit.form._FormWidget
dijit.form.ToggleButton
dijit.form.Button
dijit.form.CheckBox
File Location
dijit/form/CheckBox.js Use dojo.require("dijit.form.CheckBox");
Usage
This class creates a widget that can be in two states (checked or not). These widgets can be combined into a group. This is a replacement for the HTML tag. Although only a single widget is required, you would usually use multiple instances for each possible checkbox item. As with standard HTML, you can use the same value for the name attribute to link the individual checkboxes together into a group. The difference between this widget and the CheckBox widget is that only one of the instances in a group of RadioButton widgets can be checked.
Display Examples
HTML Markup Examples
Create a simple set of RadioButton widgets.
Checked
Unchecked
Disabled
7.2 The Dojo Form Widget Explained
JavaScript Constructor Examples
Constructor for creating a new RadioButton: new dijit.form.Radiobutton({name: "c1", checked: true});
This constructor only created a single RadionButton widget, not the label that usually goes along with it. You would also have to create the label and attach both it and the RadioButton to the DOM. Key Properties
Property checked
Default false
Description Used to hold the state of the widget. If checked is true, the button has been clicked and false if it has not. If the button is clicked again, checked will become false. Remember, this is a toggle.
name
null
Assigns the name attribute in the tag associated with this widget. This is especially important in this widget because it is also used to assign multiple instances of this widget to a single group.
Key Methods
Method
Description
Key Styles
Style Name
Description
setChecked( Boolean) Set the property checked to either true or false based on the argument of the method.
dijitButtonText
Text for button label.
dijitRadioIcon
Style for the radio button icon (a radio button).
Key Events
Style Name
Description
onClick
Clicking the radio button icon will cause this event handler to run. Although this method is really part of dijit.form._FormWidget, it is included here because it is the primary method you typically use for this widget.
Notes
None
107
108
Chapter 7
Dojo Form Widgets
Widget Name Super Classes
dijit.form.TextBox
dijit._Widget
dijit.form._FormWidget
File Location
dijit/form/TextBox.js Use dojo.require("dijit.form.TextBox");
Usage
Creates a generic textbox field. This widget can be used as a replacement for the tag. By using the widget instead of the HTML tag you can get the benefits of consistent styling and a number of additional useful methods. This widget by itself does not provide any validation. However, Dojo does provide a number of subclasses of this widget that do provide lots of validation features. Details for each of these subclasses are provided on their own page, but they’re also summarized in the following table. TextBox Subclass
Purpose
ValidationTextBox
Text box providing validation
MappedTextBox
Like a ValidationTextBox but also provides a method to serialize the data value
RangeBoundTextBox
Text field with range validation (minimum and maximum values)
NumberTextBox
Text field requiring a numeric data type
CurrencyTextBox
Text field with currency validation
TimeTextBox
Field that allows for entry of time values
DateTextBox
Field that provides a calendar for selecting a date
Display Examples
A label would usually be associated with this field but is not part of the widget itself. HTML Markup Examples
Create a simple TextBox
7.2 The Dojo Form Widget Explained
JavaScript Constructor Examples
Constructor for creating a new TextBox new dijit.form.TextBox({}, dojo.byId("form1");
This code automatically adds the widget to an existing widget in the DOM whose id is “form1”. If you don’t specify a node for attaching the widget, it will not appear on the page. Key Properties
Key Methods
Property trim
Default false
Description If true will cause the widget to remove any whitespace characters such as spaces from the beginning and ending of the data.
uppercase
false
If true will cause the widget to convert all characters in the data to their upper case values.
lowercase
false
If true will cause the widget to convert all characters in the data to their lower case values.
propercase
false
If true will cause the widget to convert the first character of each word in the data to upper case like a proper name.
maxLength
null
Assigns the value of the maxLength HTML attribute for input tags, which limits the number of characters that the user can enter in the field (but doesn’t affect the size of the field—use CSS for that).
Method
Description
getDisplayedValue()
This function will return the value of the data being displayed to the user.
getValue()
This function will return the internal data value for the widget.
setValue(value)
This function will set the internal value of the data value for the widget.
setDisplayedValue(value)
This function will set the value of the data being displayed to the user.
format()
The internal data value for a widget may be different than the displayed value that the user sees. This function converts the internal value to the displayed value.
109
110
Chapter 7
Key Styles
Dojo Form Widgets
parse()
This function takes data entered by the user and removes the formatting so that it can be stored as an internal property of the widget.
filter()
A “filter” is the generic term for the various transformations that can be performed on the data value for the widget such as “trim” and “propercase”. This function applies to filters to the displayed data value.
Style Name
Description
dijitTextBox
Text for button label.
Key Events
Style Name
Description
OnChange
Entering data in the field and moving focus away from the field (i.e. pressing the tab key) causes this event handler to run. Although this method is really part of dijit.form._FormWidget, it is included here because it is the primary method you typically use for this widget.
Notes
Even though this class is used as a root class for other more useful validating textbox types, it can still be used by itself and often is when validation is not required. The autocomplete property is set to off. This prevents the browser from displaying suggestions for this field based on previously entered values. This widget allows the user to enter a single field. However, you can think of the data for the entry as being stored in two properties. The first property, displayedValue, contains the data as it is entered and seen by the user. The second property, value, contains the data as it is manipulated by the widget. The parse() method of the widget may transform the data in some way, and it is run whenever the displayedValue is changed. The format() method transforms the data in value back to the format required for display. The methods are intended to be the inverse of each other. The following diagram depicts this process visually. parse() displayedValue
value format()
The default behavior for these methods is to perform no transformation so that the internal value is the same as the externally displayed displayedValue.
7.2 The Dojo Form Widget Explained
Widget Name Super Classes
dijit.form.ValidationTextBox
dijit._Widget
dijit.form._FormWidget
dijit.form.TextBox
File Location
dijit/form/ValidationTextBox.js Use dojo.require("dijit.form.ValidationTextBox");
Usage
This widget can be used as a replacement for the tag, just like TextBox, with the additional benefit that validations can be automatically applied to the data when it is entered by the user. Validations can be defined by setting values for certain properties on the widget. Validation messages will appear as pop-ups next to the entered fields. Standard validation messages also exist but can be overridden. You can also define a helpful message that appears when the field is in focus and no data has been entered. This message can be defined in the promptMessage property of the widget.
Display Examples
This widget requires that a value be entered. The prompt message appears when the widget is in focus and no value has been entered. HTML Markup Examples
Create a simple ValidationTextBox
JavaScript Constructor Examples
Constructor for creating a new ValidationTextBox
new dijit.form.ValidationTextBox( { promptMessage: "Enter an age between 0 and 120", required: "true"}, dojo.byId("form1");
This code automatically adds the widget to an existing widget in the DOM whose id is “form1”. If you don’t specify a node for attaching the widget, it will not appear on the page.
111
112
Chapter 7
Dojo Form Widgets
Key Properties
Key Methods
Property required
Default false
Description Set to true to specify that data must be entered.
promptMessage
null
Message displayed as a tool tip when the field is in focus.
invalidMessage null
Message displayed when the data in the field is invalid.
constraints
null
Object to be passed to the validator method that contains properties that are meaningful for certain kinds of validations. These will be discussed in the various ValidationTextBox subclasses.
regExp
.*
A regular expression used to validate the entered data.
regExpGen
null
Meant to be overridden by a custom method that should dynamically generate a regular expression. This property should be set instead of regExp because it will generate a value for regExp.
Method
Description
validator()
This method performs the validations for the field using the constraints and regExp properties.
isValid()
Runs the validator method to determine if the data is valid. Returns true for yes and false for no. This method can be overridden to provide even more sophisticated custom validations.
getErrorMessage()
Returns an error message from the invalidMessage property.
getPromptMessage()
Returns the prompt message.
validate()
Shows missing or invalid messages if appropriate and highlights textbox fields.
displayMessage(msg)
Displays message msg as a tool tip.
7.2 The Dojo Form Widget Explained
Key Styles
Style Name
Description
dijitInputField
Style for data entry area.
dijitTooltip
Style for tool tip used for prompt messages and error messages.
Key Events
Style Name
Description
onChange
Entering data in the field and moving focus away from the field (i.e. pressing the tab key) causes this event handler to run. Although this method is really part of dijit.form._FormWidget, it is included here because it is the primary method you typically use for this widget.
Notes
The regular expression validation is extremely powerful. Regular expressions can be created for a huge variety of validations, although they can be somewhat difficult to work with at first. Regular expression syntax is beyond the scope of the book, but many good references exist.
113
114
Chapter 7
Dojo Form Widgets
Widget Name Super Classes
dijit.form.MappedTextBox dijit._Widget
dijit.form._FormWidget
dijit.form.TextBox
dijit.form.ValidationTextBox
File Location
dijit/form/ValidationTextBox.js Use dojo.require("dijit.form.ValidationTextBox");
Usage
This widget is the same as ValidationTextBox with a few differences. Additional methods are provided to allow the entered data to have special serialization performed and saved in a hidden field. The typical purpose of this is to allow you to transform the value for the widget before it is submitted to the server. In other words, this widget actually maps to two form elements, one of which is a hidden field whose value is passed to the server. The other element is the field actually entered by the user. Although it is possible to create widgets from this class it usually isn’t done. Instead, this is used as a base class for other validation widgets. You could think of this as an abstract class used to implement inheritance in the class hierarchy.
Display Examples
Not applicable.
HTML Markup Examples
Not applicable.
JavaScript Constructor Examples
Not applicable.
Key Properties Key Methods
Key Styles
None Method
Description
serialize
This function takes the value of the data that was entered by the user and converts it to another form that will be saved in a hidden field and set to the server. This conversion is called serialization here.
toString
String representation of the data value for the widget.
None
7.2 The Dojo Form Widget Explained
Key Events
Not applicable.
Notes
This widget is used as a base class for other validation wizards and would probably not be used directly. You might wonder what the purpose of the serialize method is given that Dojo form widgets get serialized automatically by the browser on form submission because they populate the value property of the DOM node. The serialize method in this widget can be overridden to provide specialized serialization, transforming the data before submission to the server. That is the difference.
115
116
Chapter 7
Dojo Form Widgets
Widget Name Super Classes
dijit.form.RangeBoundTextBox
dijit._Widget
dijit.form._FormWidget
dijit.form.ValidationTextBox
dijit.form.TextBox
dijit.form.MappedTextBox
File Location
dijit/form/ValidationTextBox.js Use dojo.require("dijit.form.ValidationTextBox");
Usage
This widget is a subclass of MappedTextBox that provides the ability to check for a minimum value, a maximum value, or both. Like MappedTextBox it tends to be used as an abstract class for inheritance to subclasses and not as a concrete class. In other words, you probably won’t create widgets from this class directly. You may use it as a super class to define your own custom widgets. Its two subclasses are NumberTextBox and TimeTextBox.
Display Examples
Not applicable.
HTML Markup Examples
Not applicable.
JavaScript Constructor Examples
Not applicable.
Key Properties
Property rangeMessage
Default null
Description Contains message to be displayed when the data value is outside the range of allowed values as determined by the rangeCheck method.
constraints
null
Object to be passed to the validator method that contains properties that are meaningful for certain subclasses. See the subclasses for details.
Key Methods
Method
Description
rangeCheck(number, constraints)
This function uses properties in the constraints object to validate the data value number. By default, the function looks for a min and max property and compares them to the value of the widget. This function can be overridden by the user for more sophisticated validation.
7.2 The Dojo Form Widget Explained
Key Methods
Method
Description
isInRange()
This function returns true if the value of the widget is in range and false otherwise. It runs the rangeCheck function.
compare(value1, value2)
This function returns one of three values depending on the relative values of value1 and value2. Returns 0 if value1 and value2 are equal. Returns a negative number if value2 is greater than value1. Returns a positive number if value1 is greater than value2.
Key Styles
None
Key Events
None
Notes
None
117
118
Chapter 7
Widget Name Super Classes
Dojo Form Widgets
dijit.form.NumberTextBox
dijit._Widget
dijit.form._FormWidget
dijit.form.ValidationTextBox
dijit.form.TextBox
dijit.form.MappedTextBox
dijit.form.RangeBoundTextBox
File Location
dijit/form/NumberTextBox.js Use dojo.require("dijit.form.NumberTextBox");
Usage
This class creates a widget that subclasses RangeBoundTextBox and allows only numeric values. By inheriting all of the functionality from its super classes, this widget provides a powerful set of features to provide for the entry of numeric data. It doesn’t possess any of its own new methods or properties but overrides a number of inherited methods to provide some useful numeric validations.
Display Examples
This figure shows the rangeMessage Tooltip when the entered data is outside the valid range. Notice also that the field is highlighted, and there is a special warning message icon at the far right of the field. HTML Markup Examples
Following is the HTML for creating a simple NumberTextBox with a range validation.
Notice that the constraints attribute specifies a value within braces: This is JSON notation for building an object.
7.2 The Dojo Form Widget Explained
JavaScript Constructor Examples
Create a NumberTextBox widget using JavaScript. var obj = { name: "temperature", value: 98.6, constraints: {min:90,max:110,places:1}, promptMessage: "Enter a value between 90 and 110", required: "true" , invalidMessage: "Invalid temperature." }; var f1 = new dijit.form.NumberTextBox(obj, "form1");
Notice that the places property has a value of 1 in the constraint attribute. This forces the user to type a one decimal digit in the value. Key Properties
Property constraints
Key Methods
None
Key Styles
None
Key Events
None
Notes
None
Default null
Description This is the object that contains properties used to validate the data for any widget that is a subclass of ValidationTextBox. This widget, NumberTextBox, allows the following properties: min—Minimum value of data max—Maximum value of data places—Number of decimal digits required All of the constraint properties are optional.
119
120
Chapter 7
Widget Name Super Classes
Dojo Form Widgets
dijit.form.CurrencyTextBox
dijit._Widget
dijit.form._FormWidget
dijit.form.TextBox
dijit.form.ValidationTextBox
dijit.form.MappedTextBox
dijit.form.RangeBoundTextBox
dijit.form.NumberTextBox
File Location
dijit/form/CurrencyTextBox.js Use dojo.require("dijit.form.CurrencyTextBox");
Usage
This class creates a widget that subclasses NumberTextBox. This class allows only numeric data but also puts a further limitation on the entered data by requiring that it follow the rules for currency formats. Each country has a particular format for writing its currency that follows rules for the number of decimal places, the decimal character, and the separator characters for thousands. Also a unique symbol can be used such as “€” for the Euro). The International Standard Organization (ISO) defines standard codes and formats for describing various currencies.1 Each country is assigned a unique three-character code to identify it (such as “JPY” for Japan).
Display Examples
This example displays an amount in Japanese, which is always formatted as a whole number without decimal digits. The bottom example shows what happens when you try to enter decimal digits in a field expecting an amount in yen. The symbol for yen is not entered by the user but is supplied automatically after the data is entered and focus leaves the field. HTML Markup Examples
The following HTML would create a widget for entering an amount in Japanese yen.
The following HTML would create a widget for entering an amount in U.S. dollars. The user would not be required to enter the decimal digits. 1. For a detailed explanation of currency codes, visit the following page on Wikipedia: http://en.wikipedia.og/siki/ISO_4217
7.2 The Dojo Form Widget Explained
JavaScript Constructor Examples
Create a NumberTextBox widget using JavaScript. var obj = { name: "cost", promptMessage="Enter the item cost." constraints="{fractional: true}" currency="USD" }; var f1 = new dijit.form.CurrencyTextBox(obj);
This widget must still be added to the DOM so it displays on the page. Key Properties
Property constraints
Default null
Description This is the object that contains properties used to validate the entered data. This widget, CurrencyTextBox, allows the following properties: fractional—requires entry of decimal digits If “fractional” is false or not entered at all, the user is not required to enter decimal digits (although they may), and the decimal digits will be added automatically.
currency
null
Contains the currency code to be used for formatting and validating the entered amount (i.e., “USD” for United States dollars).
Key Methods
None
Key Styles
None
Key Events
None
Notes
None
121
122
Chapter 7
Widget Name Super Classes
Dojo Form Widgets
dijit.form.TimeTextBox
dijit._Widget
dijit.form._FormWidget
dijit.form.ValidationTextBox
dijit.form.TextBox
dijit.form.MappedTextBox
dijit.form.RangeBoundTextBox
File Location
dijit/form/TimeTextBox.js Use dojo.require("dijit.form.TimeTextBox");
Usage
This class creates a widget that allows the user to enter data representing time. It also performs validation on the data to ensure that it is a time value and that it is in an appropriate format. The widget can be configured so that various time formats can be selected. Another very useful feature of this widget is its ability to display a scrollable list of times from which the user can select a value. So there is no need to actually type the time. This feature is provided by a special popup widget created from the dijit._TimePicker class. There are many formatting options for displaying time and date data. Dojo uses the Unicode locale conventions, which are explained in more detail at the Unicode Consortium web site. The URL for additional information on date and time conventions is as follows: http://www.unicode.org/reports/tr35/#Date_Format_Patterns
Display Examples
This example shows the widget after the user has clicked in the data entry area. A popup appears displaying the dijit._TimePicker widget, which allows the user to select a time from a scrollable list. The dijit._TimePicker widget will display five hours (although this example shows three hours for brevity) of times centered around the current time. Times are selectable in 15-minute increments.
7.2 The Dojo Form Widget Explained
HTML Markup Examples
Here is the HTML markup for creating a widget to display a time using the “medium” value for formatLength.
JavaScript Constructor Examples
Create a TimeTextBox widget using JavaScript. var obj = { name: "time", promptMessage="Enter the time.", constraints="{formatLength: ‘medium’}" }; var f1 = new dijit.form.TimeTextBox(obj);
This widget must still be added to the DOM so it displays on the page. Key Properties
Property constraints
Default null
Description This is the object that contains properties used to validate the data for any widget that is a subclass of ValidationTextBox. This widget, TimeTextBox, allows the following properties: min—Minimum value of data max—Maximum value of data The format of the date value should be ‘YYYY-MM-DD’. All of the constraint properties are optional.
am
"AM"
Provide an override for the “am” string.
pm
"PM"
Provide an override for the “pm” string.
timePattern
"hh:mm"Specify the string pattern for displaying time values. Following are some of the available markers: H…hours M…minutes S…seconds
123
124
Chapter 7
Dojo Form Widgets
Key Properties
Property formatLength
Default short
Description Specify the format to be used when displaying the time. Value
Resulting Format
short
5:45 PM
medium 5:45:31 PM long
strict
Key Methods
None
Key Styles
None
Key Events
None
Notes
None
false
5:45:31 PM Central Standard Time
When true exact matches are required for white space and abbreviations. When false requirements are looser.
7.2 The Dojo Form Widget Explained
Widget Name Super Classes
dijit.form.DateTextBox dijit._Widget
dijit.form._FormWidget
dijit.form.ValidationTextBox dijit.form.RangeBoundTextBox
dijit.form.TextBox
dijit.form.MappedTextBox dijit.form.TimeTextBox
File Location
dijit/form/DateTextBox.js Use dojo.require("dijit.form.DateTextBox");
Usage
This class creates a widget that allows the user to enter data representing a date. It also performs validation on the data to ensure that it is a properly formatted date value. The widget can be configured so that various date formats can be specified. Another very useful feature of this widget is its ability to display a calendar from which the user can select a value. This feature is provided by a special pop-up widget created from the dijit._Calendar class. There are many formatting options for displaying time and date data. Dojo uses the Unicode locale conventions, which are explained in more detail at the Unicode Consortium web site. The URL for additional information on date and time conventions is as follows: http://www.unicode.org/reports/tr35/#Date_Format_Patterns
Display Examples
This example shows the widget after the user has clicked in the data entry area. A popup appears displaying the dijit._Calendar widget, which allows the user to select a date. HTML Markup Examples
Here is the HTML markup for creating a widget for entering date values:
125
126
Chapter 7
Dojo Form Widgets
JavaScript Constructor Examples
Create a DateTextBox widget using JavaScript. var obj = { name: "date", promptMessage="Enter the date." }; var f1 = new dijit.form.DateTextBox(obj);
This widget must still be added to the DOM so it displays on the page. Key Properties
Property constraints
Default null
Description This is the object that contains properties used to validate the data for any widget that is a subclass of ValidationTextBox. This widget, TimeTextBox, allows the following properties: min—Minimum value of data max—Maximum value of data All of the constraint properties are optional.
am
"AM"
Provide an override for the “am” string.
pm
"PM"
Provide an override for the “pm” string.
datePattern
"m/d/yy" Specify the string pattern for displaying time values. Following are some of the available markers: y—years m—months d—day
formatLength short
Specify the format to be used when displaying the date. Value
Resulting Format
short
2/1/08
medium Feb 1, 2008
strict
long
February 1, 2008
full
Friday, February 1, 2008
false
When true exact matches are required for white space and abbreviations. When false requirements are looser.
7.2 The Dojo Form Widget Explained
Key Methods
None
Key Styles
None
Key Events
None
Notes
None
127
128
Chapter 7
Widget Name Super Classes
Dojo Form Widgets
dijit.form.ComboBox
dijit._Widget
dijit.form._FormWidget
dijit.form.TextBox
dijit.form.ValidationTextBox
File Location
dijit/form/ComboBox.js Use dojo.require("dijit.form.ComboBox");
Usage
This class creates a widget that is a combination of a text box and a select list, hence the name ComboBox. Like a tag, it contains a list of possible values that can be selected from a pull-down list. And like a text field, the user can type anything he wants (even if the value is not in the list). The list of values can be supplied statically as HTML markup or by specifying a function that will retrieve data from the server using Ajax. The widget also has an auto-complete feature. When auto-complete is enabled for the widget, the user can just type the first few characters of the field, and the widget displays the first matching value from the select list.
Display Examples
By typing an i in the text box the user is forcing the widget to filter out any option not beginning with an “i.” Also given that auto-complete is enabled, the first value in the select list that matches “i” is automatically entered into the text area. HTML Markup Examples
The following HTML markup would create a ComboBox widget showing a list of states.
Alabama Alaska
Most of the state values have been left out for brevity.
7.2 The Dojo Form Widget Explained
JavaScript Constructor Examples
The following JavaScript code would create a ComboBox widget with autocomplete enabled. The data will be populated from a data store retrieved from the server when the widget is built. var st = new dojo.data.ItemFileReadStore({url: ‘states.json’}); cb = new dijit.form.ComboBox({ name: "state", autoComplete: true, store: st, }, dojo.byId("stateList"));
This version of the constructor also automatically adds the widget to the DOM as a child of the DOM element with an id of “stateList”. Key Properties
Property item
Default null
Description This is the item that has been selected or entered on the widget.
pageSize
Infinity
store
null
This is a reference to the data store that provides the values for the pull-down list.
query
null
A data store may have more items than actually appear on the list. By specifying a query, the list will show only those items matching the query.
This determines the number of items shown on the pull-down list.
autocomplete true
When true the widget will complete the data entered by the user by filling in the rest of the field based on the first match in the list with whatever characters the user types in the text box.
searchDelay
100
This property introduces a delay between when the user types a key and when the search of the select list is started. The amount is in milliseconds. This is useful so that a number of keystrokes can be buffered, and the search is only started when the user pauses in their typing.
searchAttr
"name"
Determines the field from the data store that is used for matching.
ignoreCase
true
A value of false forces matching on case also. Otherwise, case is ignored.
hasDownArrow true
A value of true specifies that the text box will have a down arrow icon. Otherwise, the text box has no down arrow icon.
129
130
Chapter 7
Dojo Form Widgets
Key Methods
None
Key Styles
None
Key Events
None
Notes
None
7.2 The Dojo Form Widget Explained
Widget Name Super Classes
dijit.form.FilteringSelect
dijit._Widget
dijit.form._FormWidget
dijit.form.ValidationTextBox
dijit.form.TextBox
dijit.form.MappedTextBox
dijit.form.ComboBox
File Location
dijit/form/FilteringSelect.js Use dojo.require("dijit.form.FilteringSelect");
Usage
This class creates a widget that acts as a replacement for the HTML tag. It inherits from ComboBox, but only valid options from the list may be chosen. In other ways, it acts in the same way as ComboBox. Filtering of the select list is performed based on the characters entered by the user. The data in the select list may be built with HTML markup or by using a Dojo data store that can acquire data using Ajax.
Display Examples
By typing an i in the text box, the user is forcing the widget to filter out any option not beginning with an “i.”
This example shows what happens when the user types data that can’t be matched against anything in the select list.
131
132
Chapter 7
Dojo Form Widgets
HTML Markup Examples
The following HTML markup would create a FilteringSelect widget showing a list of states.
Alabama Alaska
Most of the state values have been left out for brevity. JavaScript Constructor Examples
The following JavaScript code would create a FilteringSelect widget with auto-complete enabled. The data will be populated from a data store retrieved from the server when the widget is built. var st = new dojo.data.ItemFileReadStore({url: 'states.json'}); cb = new dijit.form.FilteringSelect({ name: "state", autoComplete: true, store: st, }, dojo.byId("stateList"));
This version of the constructor also automatically adds the widget to the DOM as a child of the DOM element with an id of “stateList”. Key Properties
Same as for ComboBox.
Key Methods
Same as for ComboBox.
Key Styles
Same as for ComboBox.
Key Events
Same as for ComboBox.
Notes
When the user types invalid text, the last correct entry is saved so that only valid data is ever sent to the server.
7.2 The Dojo Form Widget Explained
Widget Name Super Classes
dijit.form.Form
dijit._Widget
File Location
dijit/form/Form.js Use dojo.require("dijit.form.Form");
Usage
This widget corresponds to the HTML tag. It turns the standard into a Dojo widget that allows you to use Dojo to manipulate it and connect events. The other advantage is that you can populate the values for the form elements using a JSON object or convert the values of elements in the form into a JSON object. So it makes working with the form elements as a group much easier.
Display Examples
There is not an HTML template associated with this widget, so there is specific visual display.
HTML Markup Examples
Name:
JavaScript Constructor Examples
Create a new Form widget. new dijit.form.Form( {method: "POST", id: "form1", action: "submit.jsp" });
Additionally, you would need to add every child element (form widgets) that you want in your form to this widget. Given the amount of code you would need to write to create all the form elements, it is likely that you would create this widget with HTML markup rather than with JavaScript. Key Properties
Property action
Default null
Description Standard property action for specifying the server resource to be requested when the form is submitted.
method
null
Standard property method for specifying the HTTP message type (GET or POST).
name
null
Standard property name for specifying the name property of the form DOM element.
target
null
Standard property target for the destination for the response from the server when the form is submitted.
133
134
Chapter 7
Key Methods
Dojo Form Widgets
Method
Description
execute
Function to be run when user hits the submit button.
submit
Programmatically submit form.
setValues
Fill in form values from a JSON structure. The properties in the JSON structure should correspond to existing elements in the form (matched on the name property in the HTML).
getValues()
Returns a JSON string containing properties created from the form element names and values. Both Dojo widget form elements and standard HTML form elements will be included in the JSON string.
isValid()
Run the isValid method for every widget in the form. Returns true only if every widget is valid otherwise returns false.
Key Styles
No corresponding HTML template exists for this widget so there are no Dojo styles.
Key Events
The primary event for this widget is the submission of the form either through user input by clicking the Submit button or programmatically by running the submit method for this widget. In both cases, the developer can provide custom behavior for form submission by overriding the submit method.
Notes
This widget is very useful when you wish to submit the form using Ajax rather than having the browser submit it automatically.
7.2 The Dojo Form Widget Explained
Summary HTML forms allow the web page to capture data from the user. Standard HTML form elements (text boxes, check buttons, select lists, and so on) provide very limited functionality. Dojo provides form widgets that are more feature rich replacements for the standard HTML elements. Dojo also provides form widgets that don’t correspond to any existing HTML form elements. All form widgets extend dijit.form._FormWidget and reside in the dijit.form package. The basic job of a Dojo form widget is to capture some single value from the user by presenting them with the appropriate widget that corresponds to their usage of the data. For example, a field representing a date should be presented with a calendar as the visual representation. This chapter provides a short write-up for most of the Dojo form widgets containing basic usage information.
Now that we’ve studied the various form widgets, we can move on to the next major category of widgets: layout widgets.We use the same approach to analyze them.
135
This page intentionally left blank
8 Dojo Layout Widgets
The world is but a canvas to the imagination. —Henry David Thoreau
T
he blank web page is the empty canvas on which you paint your application.Your brush is HTML markup, and your paint is the various widgets available to you. But layout without structure is chaos.We need a way to organize the visual elements of our site into a form that has meaning.The various layout widgets provided by Dojo give us that structure by providing organized containers into which we pour our content. In this chapter, we explore the various layout widgets provided in Dijit and try to understand the proper use of each.
8.1 Understanding Page Layout For many years, the standard technique for laying out a web page was to create a table with rows and cells that would contain the content. Each page element or widget could be placed in a single table cell, and by adjusting the height and width of the cells, the designer could create exactly the look that she desired. As the Cascading Style Sheet (CSS) specification evolved, it became possible to define layout with CSS properties, and the use of tables became much less common. But as Ajax techniques became more popular, and more sophisticated user interfaces became the norm for web sites, it was more and more necessary to find ways to make working with groups of page elements easier. One technique was to group elements into tags.The could be treated as a single page element and moved, hidden, or styled in a single step. In effect, the tag could act as a container that could hold other elements including complete widgets. Instead, we’ll use a special Dojo widget, which will act as a container for other widgets.
138
Chapter 8
Dojo Layout Widgets
The community of user interface developers has already developed a set of patterns for containers in desktop applications. For instance, one of the most useful patterns involves allowing child widgets to be placed in a container and automatically positioned to the top, bottom, left, or right sides of the container. This is known as the BorderLayout container in the Java AWT toolkit, and similar counterparts exist in many other GUI environments. In addition to this layout container, a number of other types of containers were also common in desktop applications. Dojo provides layout container widgets that implement many of the patterns common in desktop user interfaces. In this chapter we explore those widgets. Let’s start by examining the common features shared by the various layout containers. As we examine each of the Dojo container widgets, keep in mind that they contain children, which may themselves be other container widgets.The most typical child widget is a ContentPane, which can contain any arbitrary content—which is why we look at that one first.
8.1.1 The dijit.layout._LayoutWidget Class The first thing to keep in mind when discussing the properties and methods of LayoutWidget is that it is a subclass of dijit._Widget, so any widget created from this class also inherits all the properties and methods of dijit._Widget. See Chapter 6, “Introduction to Dojo Widgets,” to review those properties and methods. Additionally, dijit.form._LayoutWidget has its own properties and methods and also inherits methods and properties from dijit._Container and dijit._Contained. These are the properties and methods we are going to review now. 8.1.1.1 Properties in dijit.layout._LayoutWidget Much of the functionality derived from the layout widgets actually resides in the widgets that they contain. Layout widgets are the gift boxes that contain the widgets that we wish to use. Like a box, one of the most important aspects of a layout container is simply how large it is.We’ll see that reflected in the properties that allow us to define the size and placement of a layout container. The reason that size is such an important consideration for containers is that the size of the container constrains the size of the child widgets that are displayed within the container. Usually, HTML works in the opposite way. In other words, most DOM elements expand to the size of the DOM elements that they contain. But a Dojo container generally will occupy a fixed portion of the page regardless of how large its children are. The primary properties for a layout widget define its height and width and its position. However, these are style properties not properties of the widget object itself. So you should define them the way you would define other CSS properties, using stylesheets, named styles or by adding them as a style property of the widget tag itself as shown: style="width=95%; height=200px; left=50px; top=75px"
Other properties are inherited from dijit._Widget. Remember that inheritence allows the object to contain all of the properties and methods of its superclass. For a refresher on the dijit._Widget class, review Chapter 6.
8.2 Explanation of Dojo Layout Widgets
8.1.1.2 Methods in dijit.layout._LayoutWidget Table 8.1 describes the key methods for dijit.layout._LayoutWidget. As discussed before, these are not necessarily all the methods, just the ones that are most likely to be useful to a developer. Except for resize, the methods involve selecting children widgets of the container. Table 8.1
Methods in dijit.layout._LayoutWidget
Method
Description
resize(args)
This method will change the size of the layout container and then redisplay it by running the layout() method. It takes an argument that contains properties describing the new size and placement. Notice that the property names in the arg object are shorter than their corresponding CSS style names. The args object should have the following properties: W—width of the layout container in pixels h—height of the layout container in pixels l—left position of the layout container in pixels t—top position of the layout container in pixels
getPreviousSibling
Return the child widget before the current widget without setting focus to that widget.
getNextSibling
Return the child widget after the current child widget without setting focus to that widget.
addChild(widget)
Add a child widget to the container.
removeChild(widget)
Remove the child widget specified in the argument as widget from the container.
getChildren
Return a collection of children of the container.
hasChildren
Return true if the container has children.
focusNext
Change the focus to the child widget that is just after the widget currently having focus.
focusPrev
Change the focus to the child widget that is just before the widget currently having focus.
focusChild(widget)
Set the focus to the child widget specified in the parameter widget.
8.2 Explanation of Dojo Layout Widgets Now that we’ve reviewed the properties and methods that are a part of all layout container widgets, let’s review the specific container widgets available to us in Dojo.We use the same format for explaining each widget that was described in Chapter 7, “Dojo Form Widgets.”
139
140
Chapter 8
Widget Name Super Classes
Dojo Layout Widgets
dijit.layout.ContentPane
dijit._Widget
File Location
dijit/form/ContentPane.js Use dojo.require("dijit.layout.ContentPane");
Usage
This class creates a simple container for content. The content can be any HTML elements or Dojo widgets. It acts like a , which can be used to group child elements so they can be moved and hidden as a single entity, but it has some advantages. Like a it can size itself to the content. However, if you specify the size of the ContentPane but its children would display beyond its boundaries, this widget will produce scroll bars so that the content can be viewed. Any HTML body elements can be put in the content pane along with Dojo widgets. ContentPane widgets can be used by themselves but they are typically children of other layout containers such as LayoutContainer. The really powerful feature of this widget is that content can be loaded dynamically from the server using either a property when the widget is created or running a method after the widget is created. See the Key Properties and Key Methods sections for more detail.
Display Examples
This figure shows a ContentPane that contains a number of widgets, one of which extends beyond the boundaries of the pane so the widget provides a scroll bar so that all the content is accessible. Also notice that the second widget is loaded dynamically from the server using an Ajax request.
8.2 Explanation of Dojo Layout Widgets
HTML Markup Examples
Create a new ContainerPane with three child elements, which are them selves also ContainerPane widgets. Notice that the second widget has content that is dynamically loaded from the server.
First Widget
Third Widget
JavaScript Constructor Examples
The following code will create a content pane and attach it to an existing DOM element. cp = new dijit.layout.ContentPane( {}, dojo.byId("d1")); cp.setContent('Miscellaneous Content');
Note that the setContent method can be used to create child elements inside the pane instead of creating new children using their constructors. This is like using the innerHTML method on a regular DOM element. Key Properties
Property href
Default null
Description Reference to server resource containing dynamic content. The content will be requested when the ContentPane is shown.
preload
false
Determines when the dynamic content specified by href is actually fetched from the server. If preload is true, the content is fetched when the ContentPane is created; otherwise, the content is not fetched until the ContentPane is shown.
refreshOnShow
false
If this property is true, content will be fetched again every time the widget is shown.
141
142
Chapter 8
Property
Key Methods
Key Styles
Dojo Layout Widgets
Property
Default
Message shown when dynamic content is being fetched.
errorMessage
"Sorry, an error occurred"
Message shown if an error occurs while fetching dynamic content.
isLoaded
false
When true, the dynamic content has been loaded.
Method
Description
setContent(HTML)
To change the innerHTML use .setContent('new content')
setHref(URL)
To do an Ajax update use .setHref('url')
cancel()
Running this method will cancel any outstanding fetches for content.
refresh()
Runs the last content fetch again.
Style Name
Description
dijitContentPaneLoading Style for content loading message. dijitContentPaneError
Key Events
Notes
Description
loadingMessage "Loading…"
Style for content fetch error message.
Style Name
Description
onLoad
This event is called after new content is fetched and has been completely loaded.
onUnload
This event is called before a new fetch of content is started and before the existing content is removed.
onDownloadStart
This event is called before the fetch of dynamic content is started.
onContentError
This event is called if there is an error creating the content.
onDownloadError
This event is called if there is an error fetching dynamic content.
onDownloadEnd
This event is called after new dynamic content is fetched.
None
8.2 Explanation of Dojo Layout Widgets
Widget Name Super Classes
dijit.layout.LayoutContainer dijit._Widget
dijit.layout._LayoutWidget
File Location
dijit/form/LayoutContainer.js Use dojo.require("dijit.layout.LayoutContainer");
Usage
This class will create a widget that provides compartments for holding content. The compartments can be formatted using alignment properties. This is most like the traditional use of the