ajmiller's picture
From ajmiller rss RSS  subscribe Subscribe

Learningextjs 090702090641 Phpapp01 

 

 
 
Tags:  domain  name  registration  search 
Views:  527
Published:  September 11, 2010
 
0
download

Share plick with friends Share
save to favorite
Report Abuse Report Abuse
 
Related Plicks
Ncct   Ieee Software Abstract Collection Volume 1   50+ Abst

Ncct Ieee Software Abstract Collection Volume 1 50+ Abst

From: anon-147728
Views: 407 Comments: 0

 
See all 
 
More from this user
Viper Smart Start iPhone App Unlocks & Starts Your Car- David Novak (The Gadget Guy)

Viper Smart Start iPhone App Unlocks & Starts Your Car- David Novak (The Gadget Guy)

From: ajmiller
Views: 736
Comments: 0

360 Degrees Credentials Presentation

360 Degrees Credentials Presentation

From: ajmiller
Views: 297
Comments: 0

All about-bohemian-grov e

All about-bohemian-grove

From: ajmiller
Views: 744
Comments: 0

The Rating Process

The Rating Process

From: ajmiller
Views: 68
Comments: 0

I pad application development india,ipad app developer company

I pad application development india,ipad app developer company

From: ajmiller
Views: 85
Comments: 0

Foundation MIS - Guide to Computer Security

Foundation MIS - Guide to Computer Security

From: ajmiller
Views: 81
Comments: 0

See all 
 
 
 URL:          AddThis Social Bookmark Button
Embed Thin Player: (fits in most blogs)
Embed Full Player :
 
 

Name

Email (will NOT be shown to other users)

 

 
 
Comments: (watch)
 
 
Notes:
 
Slide 2: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Learning Ext JS Build dynamic, desktop-style user interfaces for your data-driven web applications Shea Frederick Colin Ramsay Steve 'Cutter' Blades BIRMINGHAM - MUMBAI
Slide 3: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Learning Ext JS Copyright © 2008 Packt Publishing All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews. Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the authors, Packt Publishing, nor its dealers or distributors will be held liable for any damages caused or alleged to be caused directly or indirectly by this book. Packt Publishing has endeavored to provide trademark information about all the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information. First published: November 2008 Production Reference: 1201108 Published by Packt Publishing Ltd. 32 Lincoln Road Olton Birmingham, B27 6PA, UK. ISBN 978-1-847195-14-2 -14-2 14-2 www.packtpub.com Cover Image by Michelle O'Kane (michelle@kofe.ie)
Slide 4: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Credits Authors Shea Frederick Colin Ramsay Steve 'Cutter' Blades Project Coordinator Neelkanth Mehta Reviewer James Kennard Indexer Monica Ajmera Senior Acquisition Editor David Barnes Proofreader Dirk Manuel Development Editor Swapna V. Verlekar Production Coordinator Rajni R. Thorat Technical Editor Gagandeep Singh Cover Work Rajni R. Thorat Copy Editor Sumathi Sridhar Project Manager Abhijeet Deobhakta Editorial Team Leader Akshara Aware
Slide 5: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 About the Authors Shea Frederick began his career in web development before the term 'Web Application' became commonplace. By the late 1990s, he was developing web applications for Tower Records that combined a call center interface with inventory and fulfillment. Since then, Shea has worked as a developer for several companies, building and implementing various commerce solutions, content management systems, and lead tracking programs. Integrating new technologies to make a better application has been a driving point for Shea's work. He strives to use open-source libraries, as they are often the launching pad for the most creative technological advances. After stumbling upon a young user interface library called yui-ext several years ago, Shea contributed to its growth by writing documentation, tutorials, and example code. He has remained an active community member for the modern yui-ext library—Ext JS. Shea's expertise is drawn from community forum participation, work with the core development team, and his own experience as the architect of several large Ext JS-based web applications. He currently lives in Baltimore, Maryland, with his wife and two dogs, and spends time skiing, biking, and watching the Steelers. A big loving thanks goes out to my wife Becky for looking over my shoulder to correct the many grammatical errors my fingers produce, and for always being there to support me. Colin Ramsay began his career building ASP websites as a part-time developer at university. Since then, he's been involved with a range of web technologies and employers in the North East of England, working on everything from flashin-the-pan web frameworks to legacy applications. Most recently, he has used this experience to provide a springboard for the formation of his UK-based web development company, Plastiscenic Limited. From writing articles and blog posts across the web, Colin has made the leap to book authoring with the patience and kind assistance of his friends and family.
Slide 6: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Steve Blades (who goes by the name of 'Cutter'), a Virginia native, raised in Georgia, began his computing career when he started learning BASIC at age 12, hammering out small programs on a Timex Sinclair 1000. As a linguist and Intelligence Analyst for the US Army, Cutter began learning HTML while stationed at the National Security Agency. On leaving the service, Cutter became part-owner of a growing Advertising Specialty company, developing business automation processes for the company by writing MS Office-based applications. From there, Cutter went on to become a Customer Support Technician with a local Internet Service Provider. Upon showing programming aptitude, he was later moved into their Corporate Support department, providing maintenance and rewrites to existing websites and applications. It was here that Cutter began to really dive into web application programming, teaching himself JavaScript, CSS, and ColdFusion programming. Cutter then took the position of IT Director for Seacrets, a large resort destination in Ocean City, Maryland, while also holding the same position for one of its owner's other companies, Irie Radio. Now, Cutter is the Senior Web Developer for Dealerskins, a company that develops and hosts websites for the automobile dealership industry. He lives and works in Nashville, Tennessee with his wife Teresa and daughter Savannah. Apart from work, side projects, and maintaining his blog (http://blog. cutterscrossing.com), Cutter also enjoys spending time with his family, is an avid reader and a videophile, and likes to relive his band days with a mic in hand. I would like to thank a few people for their support while I have been working on this project. First, thanks to Jack Slocum and the entire Ext JS team for giving us such a great library to write about. Thanks to the Dev Team at Dealerskins for helping proof my chapters. Thanks to my Mom, for buying me my first book on programming. But, most of all, thanks to my wife, Teresa, and my daughter, Savannah, for giving me the time, space, love, and support needed to work on this project. I could never have done it without them.
Slide 7: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 About the Reviewer James Kennard is an all-round computer specialist with a particular interest in web-based technologies. He authored the Joomla! CMS book Mastering Joomla! 1.5 Extension and Framework Development. He holds a B.Sc. in Computer Science and has worked for organisations such as LogicaCMG. James has recently taken an interest in user interfaces and overall UX—it is this which led him to the truly superb Ext JS project.
Slide 8: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098
Slide 9: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098
Slide 10: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Dedicated to our family, friends, and the Ext JS team.
Slide 11: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098
Slide 12: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Table of Content Preface Chapter 1: Getting Started About Ext Ext: Not just another JavaScript library Cross-browser DOM (Document Object Model) Event-driven interfaces Ext and AJAX Getting Ext Where to put Ext Including Ext in your pages What do those files do? Using the Ext library Time for action The example Not working? Adapters Using adapters I'm asynchronous! Localization English only A language other than English Multiple languages Ext JS online community Summary 1 9 9 11 12 12 12 13 13 14 15 15 16 17 17 18 18 19 20 20 21 21 22 22
Slide 13: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Table of Contents Chapter 2: The Staples of Ext Ready, set, go! Spacer image Widget Time for action What just happened? Using onReady More widget wonders Meet JSON and the config object The old way The new way—config objects What is a config object? 23 23 24 24 24 25 25 26 28 28 28 29 How does JSON work? Time for action Lighting the fire The workhorse—Ext.get Speed tip Summary 30 30 32 33 34 35 Chapter 3: Forms The core components of a form Our first form Nice form—how does it work? Form fields Validation Built-in validation—vtypes Styles for displaying errors Custom validation—create your own vtype Masking—don't press that key! Radio buttons and check boxes It's not a button, it's a radio button X marks the check box The ComboBox Database-driven ComboBox TextArea and HTMLEditor Listening for form field events ComboBox events Buttons and form action Form submission Talking back—the server responses 37 37 38 39 39 40 41 43 44 45 46 46 46 47 47 50 51 51 53 53 54 [ ii ]
Slide 14: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Table of Contents Loading a form with data Static data load Object reference or component config Instantiated Component config Summary 56 56 58 58 58 59 Chapter 4: Buttons, Menus, and Toolbars A toolbar for every occasion Toolbars The button Menu Split button Toolbar item alignment, dividers, and spacers Shortcuts Icon buttons Button handlers—click me! Load content on menu item click Form fields in a toolbar Toolbars in windows, grids, and panels Summary 61 61 61 63 63 64 65 66 66 67 68 69 70 71 Chapter 5: Displaying Data with Grids What is a grid anyway? Displaying structured data with a GridPanel Setting up a data store Adding data to our data store Defining your data for the data store Specifying data types 73 74 74 75 75 76 77 Displaying the GridPanel How did that work? Configuring the GridPanel Defining a Grids column model Using cell renderers Formatting data using the built-in cell renderers Creating lookup data stores—custom cell rendering Combining two columns Generating HTML and graphics Built-in features Client-side sorting Hidden/visible columns Column reordering [ iii ] 78 80 80 81 82 82 83 84 84 85 86 86 86
Slide 15: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Table of Contents Displaying server-side data in the grid Loading the movie database from an XML file Loading the movie database from a JSON file Loading data from a database using PHP Programming the grid Working with cell and row selections Listening to our selection model for selections Manipulating the grid (and its data) with code Altering the grid at the click of a button Advanced grid formatting Paging the grid Grouping Grouping store Summary 88 88 90 91 92 92 93 94 94 95 96 98 98 100 Chapter 6: Editor Grids What can I do with an editable grid? Working with editable grids Editing more cells of data Edit more field types Editing a date value Edit with a ComboBox 101 101 102 104 104 105 106 Reacting to a cell edit What's a dirty cell? Reacting when an edit occurs 106 107 107 Deleting and adding in the data store Removing grid rows from the data store Adding a row to the grid 108 109 110 Saving edited data to the server Sending updates back to the server Deleting data from the server Saving new rows to the server Summary 112 112 114 115 117 Chapter 7: Layouts What are layouts, regions, and viewports? Our first layout Splitting the regions I want options Tab panels Adding a tab panel 119 119 121 122 123 124 124 [ iv ]
Slide 16: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Table of Contents Widgets everywhere Adding a grid into the tabpanel Accordions Nesting an accordion layout in a tab Placing a toolbar in your layout A form to add new movies Tricks and advanced layouts Nested layouts Icons in tabs Programmatically manipulating a layout Now you see me, now you don't Give me another tab Summary 126 126 128 128 129 131 132 132 134 135 135 136 136 Chapter 8: Ext JS Does Grow on Trees Planting for the future From tiny seeds... Our first sapling Preparing the ground A tree can't grow without data JSON A quick word about ID Extra data 137 137 138 138 139 140 141 141 142 XML Tending your trees Drag and drop Sorting Editing Trimming and pruning Selection models Round-up with context menus Handling the menu 142 143 143 145 146 147 147 148 149 Filtering The roots TreePanel tweaks Cosmetic Tweaking TreeNode 150 151 151 152 152 Manipulating Further methods 153 154 Event capture 155 [v]
Slide 17: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Table of Contents Remembering state StateManager Caveats 156 156 157 Summary 157 Chapter 9: Windows and Dialogs Opening a dialog Dialogs Off the shelf Confirmation It's all progressing nicely 159 159 160 160 162 163 Roll your own Behavior 164 165 Windows Starting examples Paneling potential Layout 166 166 167 168 Configuration When I'm cleaning windows The extras Desktopping Further options Framing our window 169 169 169 170 171 171 Manipulating Events State handling Window management Default window manager behavior Multiple window example Customer service WindowGroups 172 173 174 175 175 175 179 Summary 180 Chapter 10: Effects It's elementary Fancy features It's ok to love Fxcellent functions Methodical madness Fading Framing Woooo: ghosting Highlighting Huffing and puffing Scaling the Ext JS heights 183 183 184 184 184 184 185 186 186 187 188 189 [ vi ]
Slide 18: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Table of Contents Sliding into action Switching from seen to unseen Shifting 189 190 190 And now, the interesting stuff The Fx is in Anchoring yourself with Ext Options Easy does it 191 191 192 192 194 Multiple effects Chaining Queuing Concurrency Blocking and Ext.Fx utility methods 195 195 196 196 196 Elemental Making a move Using Ext components Bring out the flash You're maskin', I'm tellin' Data binding and other tales Considering components 197 197 198 198 198 200 200 QuickTipping Summary 200 202 Chapter 11: Drag-and-Drop Drop what you're doing Life's a drag Sourcing a solution Approximating Snap! 205 205 206 206 206 207 Drop me off But wait: Nothing's happening! 207 208 Interacting the fool Zones of control Changing our lists 209 209 211 Registering an interest Extreme drag-and-drop DataView dragging Dealing with drag data Proxies and metadata Dropping in the details Drag-drop groups Nursing our drag-drop to health It's all in the details [ vii ] 211 212 212 213 214 215 216 216 217
Slide 19: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Table of Contents Configuration It's all under control Managing our movement Global properties Scroll management Dragging within components TreePanel GridPanel Using it in the real world Summary 217 217 218 218 219 220 220 221 221 222 Chapter 12: It's All about the Data Understanding data formats Basic remote panel data Gotchas with HTML data Other formats 223 223 223 227 227 The data store object Defining data More on mapping our data Pulling data into the store 228 229 230 231 Using a DataReader to map data Using a custom DataReader Getting what you want: Finding data Finding data by field value Finding data by record index Finding data by record ID 233 234 237 237 237 238 Getting what you want: Filtering data Remote filtering: The why and the how 238 238 Dealing with Recordset changes Many objects take a Store Store in a ComboBox Store in a DataView Stores in Grids Summary 244 246 246 247 247 248 Chapter 13: Code for Reuse: Extending Ext JS Object-oriented JavaScript Object-oriented programming with Ext JS Inheritance Break it down and make it simple Sounds cool, but what does it mean? Now, what was this overriding stuff? 249 249 251 251 251 253 253 [ viii ]
Slide 20: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Table of Contents Understanding packages, classes, and namespaces Packages Classes Namespaces What's next? Ok, what do we extend? Creating a custom namespace Our first custom class Overriding methods Understanding the order of events When can we do what? What is an event-driven application? 254 254 254 254 254 255 255 256 259 260 261 261 Creating our own custom events Our first custom component: Complete What's next? Breaking it down Using xtype: The benefits of lazy instantiation Using our custom components within other objects Summary 262 264 267 271 271 272 Chapter 14: The Power of Ext JS: What Else Can You Do? So much to work with Form widgets DateField TimeField NumberField CheckboxGroups and RadioGroups HtmlEditor Data formatting Basic string formatting Formatting dates Other formatting Managing application state Basic 'state' How do I get that window? Using the back button in Ext JS applications Accessing the DOM Finding DOM elements Manipulating the DOM Working with styles Ext JS for the desktop: Adobe AIR 273 273 273 274 275 276 276 277 278 278 279 280 281 281 282 282 282 283 283 284 284 [ ix ]
Slide 21: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Table of Contents Ext JS community extensions DatePickerPlus PowerWizard TinyMCE SwfUploadPanel ColorPicker Additional resources Samples and demos Ext JS API Ext JS forums Step-by-step tutorials Community manual Spket IDE Aptana Studio Google Summary Where do we go from here? 286 286 287 287 288 288 289 289 289 289 290 290 290 290 290 291 291 Index 293 [x]
Slide 22: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Preface Ext JS was developed by a unified team of programmers working toward a single goal—to provide a consistent core user interface and interaction library. Because of this, the code used for different functionalities and widgets is more coherent than in some other JavaScript libraries. Ext JS really shines in making web applications easyto-use and intuitive. If you are a web application developer, it's a great library to have in your arsenal. We start by outlining how to download and configure the Ext JS library. Covering everything from the simplest alerts to complex grids, layouts, and forms, this book will enable you to start creating rich, interactive web applications. We will use plenty of real-world examples that can be applied immediately to your ongoing projects. Sample code is broken down to its simplest form, allowing us to concentrate on learning the usage of the library. By the end of this book, we will end up with a sample application that uses the full spectrum of Ext JS components. What this book covers Chapter 1 introduces you to the process of installing the required Ext JS library files, and setting up a basic page that displays an alert-style message. This provides us with a way to test whether your setup was done correctly, and whether you're ready to play with some code. We also cover how to set up other base libraries such as jQuery, YUI, and Prototype, to work in conjunction with Ext JS. Chapter 2 covers how to interact with the web page and the user. With example code that uses simple components, we quickly start to see the level of user interactivity that Ext JS provides right out of the box. We assemble a series of dialogs that appear and modify the existing pages depending upon the users' inputs.
Slide 23: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Preface Chapter 3 launches us into using the first major widget—forms. We start by creating a simple form with three fields, explore the different form field types, and then add some simple validation to our form. From there we move on to creating custom validation and database-driven combo-box'es and handling form submissions. Chapter 4 provides an overview of how to use toolbars and buttons within your application. These components are typically undervalued, yet they provide crucial user interface functions. We jump straight into creating toolbars with buttons, split buttons, and menus, along with adding mechanical elements such as spacers and dividers. Next, we cover customizing the toolbar with stylized icon buttons and form fields. Chapter 5 covers grids—the most widely-utilized component in the Ext JS library. In this chapter, we learn how to set up a grid panel using both local and remote data, and in both in XML and JSON formats. We also discuss how to prepare different data types and how to create renderers that will style and format the data to your preference. Using the selection model and paging are among the many interesting points covered in this chapter. Chapter 6 dives into editor grids. Here, we learn how to set up an editor grid using different form field types, and how to save changes made in the grid back to the server or database. We also discuss tactics for adding and removing rows of data to and from our data store, and the server or the database. Chapter 7 explores the concept of using the layout component to bring all the portions of your application together into a cohesive web application. We start by using a viewport with a border layout to contain the many parts of our application. From there we are able to add other layout features such as tab panels, accordions, and toolbars. We finish up by learning how to nest layouts and make dynamic changes to the layout components. Chapter 8 discusses the presentation of hierarchical information using the Ext JS Tree support. Using real-world examples of hierarchical data, you will discover how to display and manipulate a Tree view. You will use AJAX techniques to persist the modifications to a server and learn how to tweak the Tree to support advanced scenarios. Chapter 9 demonstrates how Ext JS can provide attractive user prompts that can either present information or accept input. We then discuss the extension of these dialogs in the form of Ext.Window, a fully-fledged means of creating customizable pop-up windows. In Chapter 10, we take a tour of the visual effects available in the Ext JS effects package. You will learn how to apply animations to create smooth transitions and notifications to enhance the user experience. [2]
Slide 24: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Preface. . Chapter 11 shows how you can harness Ext.dd—the rich drag-and-drop functionality provided by Ext JS. A variety of different demonstrations allow you to understand the concepts behind Ext.dd, and how you can harness its potential within your own applications. Chapter 12 gets straight to the heart of every application—the data. Ext JS provides several different methods for retrieving data, with each method having its own pros and cons. This chapter will help you to decide what will work for your application, with step-by-step examples to guide you on your way. Chapter 13 shows the true power of Ext JS, providing an introduction to creating your own custom components by expanding upon Ext JS's extensible architecture. You will see how to create your own components by extending the existing framework, making pieces that you can re-use in your own applications. Chapter 14 wraps it all up, by showing you that with Ext JS there is more than meets the eye. You will discover some of the invisible architecture that allows you to perform important tasks such as data formatting and application state management. You will also find that you have a broad array of resources at your fingertips, as we show you the rich user community that exists around the library, and introduce you to additional resources to continue your journey in Learning Ext JS. What you need for this book At the ground level, this book requires the knowledge to write HTML pages by hand—if you can write an HTML document from memory in Windows Notepad (or in a good text editor) then that will be good enough. Familiarity with including external files such as style sheets and JavaScript files will also be necessary. Only a basic understanding of JavaScript, or another scripting or programming language, will be required. One of the things that will make life easier is having access to a web server, or a local development web server such as XAMPP or something similar. The XAMPP local web server is developed by Apache Friends (www.apachefriends.org) and comes in an easy–to-use install file. By default, it sets up Apache, PHP, and MySQL, which allows you to perform local web development easily. Running this book's examples from a local web server is useful and can save lots of time. [3]
Slide 25: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Preface A good editor and debugger are extremely useful, particularly if they are specific to JavaScript, as Aptana is. The makers of Aptana have created a very powerful tool for developing web applications in JavaScript. Their editor can debug JavaScript, CSS, PHP, and many other languages as you type, and the best part is that you can link the editor up with your libraries and classes to get code auto-completion specific to your development. The debugger can alert you to errors in your code before you get to the browser (enable the JSLint debugger), and can suggest fixes for the errors. The final point here is an absolute necessity—get Firefox and Firebug installed on your computer! Don't even ask why, because Firebug will soon become the program you just cannot do your job without. Soon, you will be wondering how you ever got any work done before Firebug. What it does is allows you to monitor and interact with the web page in real time. When you start working with singlepage web applications and AJAX, you quickly lose the ability to look at the requests and responses for communications such as form submission. One of the things that Firebug provides you with is a way to watch and inspect this communication. The other main thing that it does is allow you to modify the HTML and JavaScript in your web page and watch these changes take effect in real time. The built-in script debugger lets us pause code execution and inspect or even modify code and variables. Once you are set up with a local (or remote) development web server, your favorite editor and debugger, and Firefox with Firebug, you are ready to start Learning Ext JS. Who is this book for This book is written for Web Application Developers who are familiar with HTML, but may have little to no experience with JavaScript application development. If you are starting to build a new web application, or you are revamping an existing web application, then this book is for you. Conventions In this book, you will find a number of styles of text that distinguish between different kinds of information. Here are some examples of these styles, and an explanation of their meaning. Code words in text are shown as follows: "The config object used for this dialog has three elements " [4]
Slide 26: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Preface. . A block of code is set as follows: Ext.onReady(function(){ Ext.Msg.show({ title: 'Milton', msg: 'Have you seen my stapler?', buttons: { yes: true, no: true, cancel: true } }); }); When we wish to draw your attention to a particular part of a code block, the relevant lines or items will be shown in bold: { xtype: 'datefield', fieldLabel: 'Released', name: 'released' } New terms and important words are introduced in bold. Words that you see on the screen, in menus or dialog boxes for example, appear in the text like this: "We also have elements that can add space and vertical dividers, like the one used between the Menu and the Split buttons." Warnings or important notes appear in a box like this. Tips and tricks appear like this. Reader feedback Feedback from our readers is always welcome. Let us know what you think about this book, what you liked or may have disliked. Reader feedback is important for us to develop titles that you really get the most out of. To send us general feedback, simply drop an email to feedback@packtpub.com, and mention the book title in the subject of your message. [5]
Slide 27: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Preface If there is a book that you need and would like to see us publish, please send us a note in the SUGGEST A TITLE form on www.packtpub.com or email suggest@ packtpub.com. If there is a topic that you have expertise in and you are interested in either writing or contributing to a book, see our author guide on www.packtpub.com/authors. Customer support Now that you are the proud owner of a Packt book, we have a number of things to help you to get the most from your purchase. Downloading the example code for the book Visit http://www.packtpub.com/files/code/5142_Code.zip to directly download the example code. The downloadable files contain instructions on how to use them. Errata Although we have taken every care to ensure the accuracy of our contents, mistakes do happen. If you find a mistake in one of our books—maybe a mistake in text or code—we would be grateful if you would report this to us. By doing this you can save other readers from frustration, and help to improve subsequent versions of this book. If you find any errata, report them by visiting http://www.packtpub. com/support, selecting your book, clicking on the let us know link, and entering the details of your errata. Once your errata are verified, your submission will be accepted and the errata added to any list of existing errata. Existing errata can be viewed by selecting your title from http://www.packtpub.com/support. [6]
Slide 28: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Preface. . Piracy Piracy of copyright material on the Internet is an ongoing problem across all media. At Packt, we take the protection of our copyright and licenses very seriously. If you come across any illegal copies of our works in any form on the Internet, please provide the location address or website name immediately so we can pursue a remedy. Please contact us at copyright@packtpub.com with a link to the suspected pirated material. We appreciate your help in protecting our authors, and our ability to bring you valuable content. Questions You can contact us at questions@packtpub.com if you are having a problem with any aspect of the book, and we will do our best to address it. [7]
Slide 29: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098
Slide 30: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Getting Started In this chapter, we will cover the basics of Ext and what it can do for us. If you're accustom to the standard web development, then you'll be excited when you learn about the elegance in the architecture of Ext, just as I was. Unlike other JavaScript libraries, Ext handles the foundation for you, so with only a few lines of code, you can have a fully functional user interface. In this chapter, we will cover: • • • • • What Ext does and why you'll love using it How to get Ext and start using it in your web applications Using "adapters" to allow Ext to co-exist with other JavaScript libraries Taking advantage of AJAX technology Displaying Ext objects in your own language About Ext We will be working with the most recent release version of Ext which, at the time of writing, is the 2.x branch. The change from 1.x to 2.x was a major refactoring that included taking full advantage of the newly-created Component model, along with renaming many of the components to provide better organization. These changes have made 1.x code mostly incompatible with 2.x and vice versa (an upgrade guide that explains in more detail what has changed is available on the Ext web site). The 3.x branch is backwards-compatible with 2.x and compatible with everything that we will cover in this book. The Ext development team is dedicated to making future releases backwards-compatible.
Slide 31: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Getting Started The Ext library started out as an extension to the moderately popular, yet very powerful Yahoo User Interface library, providing what the YUI library lacked: an easy to use API (Application Programming Interface), and real world widgets. Even though the Yahoo User Interface tried to focus on the 'User Interface', it didn't contain much that was useful right out of the box. It wasn't long before Ext had developers and open-source contributors chipping in their knowledge to turn the basic YUI extension into one of the most powerful client-side application development libraries around. Ext provides an easy-to-use, rich user interface, much like you would find in a desktop application. This lets the web developers concentrate on the functionality of web applications instead of the technical caveats. The examples given on the Ext website speak the loudest about how amazing this library is: http://www.extjs.com/deploy/dev/examples/ One of the most striking examples is the Feed Viewer. This demonstrates the many aspects of Ext. However, it is a bit too complex to be used as a learning example. So for now, you can just revel in its brilliance. [ 10 ]
Slide 32: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 1 Another excellent example is the Simple Tasks task-tracking program, which utilizes a Google Gears database. Over the course of this book, you will learn how to build web interfaces as impressive as these. Ext: Not just another JavaScript library Ext is not just another JavaScript library—in fact, Ext can work alongside other JavaScript libraries by using adapters. We'll see how to work with adapters later in this chapter. Typically, we would use Ext in a web site that requires a high level of user interaction—something more complex than your typical web site. A web site that requires processes and a work flow would be a perfect example, or Ext could just be used to make your boss gasp with excitement. Ext makes web application development simple by: • Providing easy-to-use cross-browser compatible widgets such as windows, grids, and forms. The widgets are already fine-tuned to handle the intricacies of each web browser on the market, without us needing to change a thing. Interacting with the user and browser via the EventManager, responding to the users keystrokes, mouse clicks, and monitoring events in a browser such as a window resize, or font size changes. [ 11 ] •
Slide 33: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Getting Started • Communicating with the server in the background without the need to refresh the page. This allows you to request or post data to or from your web server using AJAX and process the feedback in real time. Cross-browser DOM (Document Object Model) I am sure I don't need to explain the pitfalls of browser compatibility. From the first time you create a DIV tag and apply a style to it, it becomes apparent that it's not going to look the same in every browser unless you are very diligent. When we use Ext widgets, the browser compatibility is taken care of by the Ext library, so that each widget looks exactly the same in most of the popular browsers, which are: • • • • Internet Explorer 6+ Firefox 1.5+ (PC, Mac) Safari 2+ Opera 9+ (PC, Mac) Event-driven interfaces Events describe when certain actions happen. An event could be a user action such as a click on an element, or it could be a response to an AJAX call. When a user interacts with a button, there is a reaction, with not just one but many events happening. There is an event for the cursor hovering over the button, and an event for the cursor clicking on the button, and an event for the cursor leaving the button. We can add an event listener to execute some code block when any or all of these events take place. Listening for events is not strictly related to the user interface. There are also system events happening all the time. When we make AJAX calls, there are events attached to the status of that AJAX call to listen for the start, the completion, and the failure. Ext and AJAX The term AJAX (Asynchronous JavaScript and XML) is an overly-complicated acronym for saying that processes can take place in the background while the user is performing other tasks. A user could be filling out a form while a grid of data is loading—both can happen at the same time, with no waiting around for the page to reload. [ 12 ]
Slide 34: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 1 Getting Ext Everything we will need can be downloaded from the Ext website, at http://www.extjs.com/download. Grab the Ext SDK (Software Development Kit), which contains a ton of useful examples and the API reference. Most importantly, it contains the resources that Ext needs to run properly. Where to put Ext Once you get the SDK file, uncompress it onto your hard drive, preferably in its own folder. My approach to folder naming conventions is based on the standard Linux structure where all libraries go into a lib folder. So for the sake of the examples in this book, uncompress all of the files in the SDK into a folder named lib. After extracting everything from the SDK download file, your directory tree should look like this: To make it easier when we upgrade our Ext library to the most recently-released version, let us rename the ext-2.0.1 folder to extjs. The SDK contains a version of Ext JS that has everything you need included in it, commonly called ext-all. It also contains a version used for development referred to as the debug version, which is what we will primarily use. The debug version makes it easier to locate errors in your code because it's uncompressed and will report back relevant line numbers for errors. When it's time to release our creation to the general public, we can switch our application to use the standard ext-all, and everything will continue to work as it was. [ 13 ]
Slide 35: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Getting Started Included in the SDK file are a specification of dependencies, documentation, example code, and more. The adapter and resources folders shown in bold are required for Ext to work properly; everything else is just for development purposes. • • • • • • adapter: Files that allow you to use other libraries along side Ext build: Files that can be used to custom-build an ext-all.js docs: The documentation center (this will only work when run on a web server) examples: Plenty of amazing and insightful examples resources: Dependencies of the Ext library, such as CSS and images source: The complete source code for Ext When you're ready to host your page on a web server, the adapter and resources folders will need to be uploaded to the server. Including Ext in your pages Before we can use Ext in our pages, we need to reference the Ext library files. To do this, we need to include a few of the files provided in the SDK download in the HEAD portion of our HTML page. <html> <head> <title>Getting Started Example</title> <link rel="stylesheet" type="text/css" href="lib/extjs/resources/css/ext-all.css" /> <script src="lib/extjs/adapter/ext/ext-base.js"></script> <script src="lib/extjs/ext-all-debug.js"></script> </head> <body> <!-- Nothing in the body --> </body> </html> The path to the Ext files must be correct and is relative to the location of our HTML file. These files must be included in the following order: • ext-all.css: The main Ext CSS file • An external js library file, if needed (one not used in the examples in this book; however if you need to use an external library it is covered in the 'Adapters' section of this chapter) [ 14 ]
Slide 36: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 1 • • ext-base.js: The Ext 'adapter'—we will learn more about this file later in this chapter • ext-all.js or ext-all-debug.js: The primary Ext library file A theme file could also be included here, or at any point after the main Ext CSS file What do those files do? We have included the following three files that Ext requires to run in our page: • ext-all.css: A stylesheet file that controls the look and feel of Ext widgets. This file must always be included as-is, with no modifications. Any changes to the CSS in this file would break future upgrades. If the look and feel of Ext needs to be adjusted, another stylesheet containing the overrides should be included after the ext-all.css file. • ext-base.js: This file provides the core functionality of Ext. It's the engine of the Ext car. This is the file that we would change if we wanted to use another library, such as jQuery, along with Ext. • ext-all-debug.js/ext-all.js: All of the widgets live in this file. The debug version is used for development, and then swapped out for the non-debug version for production. Once these files are in place, we can start to actually use the Ext library and have some fun. If you are working with a server-side language such as PHP or ASP.NET, you might choose to "include" these lines in the header dynamically. For most of the examples in this book, we will assume that you are working with a static HTML page. Using the Ext library Now that we've added the Ext library to our page, we can start writing the code that uses the Ext library. In the first example, we will use Ext to display a message dialog. This might not sound like much, but it's a start. [ 15 ]
Slide 37: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Getting Started Time for action We can run some Ext code by adding a script section in the head of our document, right after where the Ext library has been included. Our example will bring up an Ext style alert dialog: <html> <head> <title>Getting Started Example</title> <link rel="stylesheet" type="text/css" href="lib/extjs/resources/css/ext-all.css" /> <script src="lib/extjs/adapter/ext/ext-base.js"></script> <script src="lib/extjs/ext-all-debug.js"></script> <script> Ext.onReady(function(){ Ext.Msg.alert('Hello', 'World'); }); </script> </head> <body> <!-- Nothing in the body --> </body> </html> We're not going to cover exactly what our example script is doing yet. First, let's make sure that the Ext library is set up properly. If we open up our page in a web browser, we should be able to see an alert message like the one shown here: Just like a "real" dialog, you can drag it around, but only within the constraints of the page. This is because this isn't a real dialog; it's a collection of DIV tags and images put together to imitate a dialog. You can also see that the Close and Ok buttons get highlighted when you move the cursor over them—not bad for one line of code! Ext is taking care of a lot of the work for us here, and throughout this book, we'll see how to get it to do much more for us. [ 16 ]
Slide 38: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 1 You may have noticed that we are working with an empty document that has no elements in the body. Ext does not require any pre-existing markup for it to function properly; it generates everything it needs on its own. The example Let's take a look at that example code we just ran. Every Ext component we use will start with "Ext" and will most likely be contained within an onReady function that we Ext" will cover with more detail in the next chapter. Ext.onReady(function(){ Ext.Msg.alert('Hello', 'World'); }); Ext has a very human-readable interface. You can almost read it as a sentence—when Ext is ready, it displays a message box in the alert style with Hello for a title and World as the body. Our alert message starts with Ext.Msg, which is the starting point for all message style windows, and is shorthand for "MessageBox". The alert portion tells Ext exactly which style of message window to use. Not working? If the library is not set up correctly, we might receive an 'Ext' is undefined error. This message means the Ext library was not loaded. Usually, this is caused by having an incorrect path to one or more of the Ext library files that are included in our document. Double-check the paths to the included library files, and make sure they are pointing to the right folders and that the files exist. If everything is in its correct place, you should see an adapter folder along with the files ext-all.js and ext-all-debug.js in your lib/extjs folder. [ 17 ]
Slide 39: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Getting Started Another common problem is that the CSS file is either missing or is not referenced correctly, which will result in a page that looks awkward, as shown in the example below:. If this happens, check to make sure that you have extracted the resources folder from the SDK file, and that your paths are correct. The resources folder should reside under the lib/extjs folder. Adapters When Ext was first being developed (initially called "yui-ext"), it required the YUI library to be in place to do the behind-the-scenes work. Later on, Ext was given the option of using two other frameworks—jQuery or Prototype with Scriptaculous (Protaculous). This means that if we were using other libraries already or if we felt some other base library was somehow superior or better suited your needs, we could continue using that library in conjunction with Ext by using the appropriate adapter. Either way, Ext will function the same, and all of the components will work identically, no matter which adapter you choose. Ext also has its own adapter, an adapter to itself. If you have no preference for another library or framework, then go with the Ext built-in the adapter. Using adapters To use an adapter, you must first include the external library that you want to use, and then include the related adapter file that is located in the adapters folder of the Ext SDK. Our example code uses the Ext adapter. To use any of the other libraries, just replace the default Ext adapter script include line with the lines for the specific libraries, as shown below: [ 18 ]
Slide 40: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 1 Default Ext adapter: <script src="lib/extjs/adapter/ext/ext-base.js"></script> For jQuery, include these files in the head of your document: <script src="lib/jquery.js"></script> <script src="lib/jquery-plugins.js"></script> <script src="lib/extjs/adapter/jquery/ext-jquery-adapter.js"> </script> For YUI, include these files in the head. The utilities file is located in the build/ utilities folder of the YUI Library download: <script src="lib/utilities.js"></script> <script src="lib/extjs/adapter/yui/ext-yui-adapter.js"></script> For "Prototype + Scriptaculous", include these files in the head: <script src="lib/prototype.js"></script> <script src="lib/scriptaculous.js?load=effects"></script> <script src="lib/extjs/adapter/prototype/ ext-prototype-adapter.js"></script> After the adapter and base libraries have been included, we just need to include the ext-all.js or ext-all-debug.js file. I'm asynchronous! The Web 1.0 way of doing things has all of our code happening in succession—waiting for each line of code to complete before moving on to the next. Much like building a house, the foundation must be complete before the walls can be built, then the walls must be complete before the roof is built. With Ext, we can easily start working on the roof of our house before the foundation has even been thought about. Imagine the roof of our house is being built in a factory, while at the same time we are building the foundation, then the walls, and we come in when all of this is done and set the roof that has already been built on top of it all. Web 1.0 Web 2 .0 > < = > = > [ 19 ]
Slide 41: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Getting Started This introduces some things we're not use to having to cope with, such as the roof being complete before the walls are done. No longer are we forced to take a line-by-line approach to web development. Ext helps us out by giving us events and handlers to which we can attach our functionality. We can set up an event that waits around, watching to see when the walls of the house are built, and then sets the roof on top once this has happened. This method of thinking about web pages is hard for most people who have grown up in web development. But it won't be long before you are an expert at it. Standard JavaScript alert messages pause the code execution, which can cause unexpected results. You should not be using the built in JavaScript alert messages, and instead use Ext's MessageBox widget, which does not pause that code execution. Localization Ext objects can be displayed in your specific language, and currently there are over 40 translations (unfortunately, Klingon is not yet available). All of these translations . are created by the community—users like you and I who have the need to use Ext in their own native language. The included language files are to be used as a starting point. So let's take the language we want to use and copy it to our lib folder. By copying the language file to our lib folder, we can edit it and add translated text to it without it getting overwritten when we upgrade the Ext library files. There are three scenarios for localization that require three separate approaches: • • • English only A single language other than English Multiple languages English only This requires no modifications to the standard setup, and there are no extra files to include because the English translation is already included in the ext-all.js file. [ 20 ]
Slide 42: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 1 A language other than English The second option requires that we include one of the language files from the build/locale folder. This option works by overwriting the English text strings, so it should be included after all of the other library files, as shown below: <link rel="stylesheet" type="text/css" href="lib/extjs/resources/css/ext-all.css" /> <script src="lib/extjs/adapter/ext/ext-base.js"></script> <script src="lib/extjs/ext-all-debug.js"></script> <script src="lib/extjs/build/locale/ext-lang-es.js"></script> I have included the Spanish translations for this example. Let's see what our test page looks like now: Elements that are part of the UI have been localized—these generally include calendar text, error messages, tool tip info messages, paging info, and loading indicators. Messages that are specific to your application, such as the Hi title, and Hello World Example text will need to be translated and added to the ext-lang-XX.js file (where 'XX' is your two letter language code) or added to a new language file of your own. The preferred method is to create a language file of our own with just the additions and changes we need, this leaves us prepared for upgrades and fixes in the primary language file. Multiple languages The third method of switching between different languages is basically the same as the second. We would just need to add some server-side scripting to our page to enable the switching between language files. Unfortunately, switching between languages cannot be done entirely dynamically. In other words, we can't do it in real time and watch it happen on the screen. [ 21 ]
Slide 43: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Getting Started Ext JS online community The online community for Ext is full of quite a few very knowledgeable people, and often, the Ext core developers are answering questions on the forum. http://www.extjs.com/forum/ If you run into problems, or run up against a wall, a search of the forum is likely to yield what you are looking for. I would suggest getting the Google forum search tool that is available in the Learn section of the Ext web site. http://www.extjs.com/learn/ When asking questions in the forum, be sure to include as much detail about the error(s) as possible. Posting the exact text of an error message and only the relevant portions of your code is the best way to get a response from the community. Summary In this chapter, we have covered the basics of what you need to do to get Ext up and running, and what a simple script looks like. It's easy to miss a minor detail and get stuck with an error message that makes no sense. But now, you should be prepared to conquer any initial errors that you might come across. The example we created showcases what Ext excels at: providing the user interface. We only used dialogs, but, as you now know, a few lines of code are all that are needed to display an Ext widget. The main goal of this chapter was to get Ext installed and working, so we can start creating some really sweet widgets. [ 22 ]
Slide 44: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 The Staples of Ext In this chapter, we will start to use and interact with Ext widgets for the first time, by creating a series of dialogs that interact with each other, the user, and the web page. We will be using the onReady, MessageBox, and get functions to learn how to create different types of dialogs and modify HTML and styles on our page. Furthermore, in this chapter, we will be: • • • • Finding out how to configure Ext widgets easily Waiting for the DOM (Document Object Model) to be made available for interaction Using dialogs to figure out what the user wants to do Dynamically changing the HTML and CSS on our page in response to the user's inputs We will start by covering some of the core functions of Ext. We will take a look at how the example given in the first chapter worked, and will expand upon it. The following core functions of Ext will be used on every project that we work on during the course of this book: • • • • Ext.onReady: This function makes sure that our document is ready to be thrashed out Ext.Msg: This function creates application-style message boxes for us configuration objects: This function defines how Ext widgets will act Ext.get: This function accesses and manipulates elements in the DOM Ready, set, go! In this section, we'll look at the onReady event—the first thing that you need to deal with when you are working with Ext. We will also see how to display some different types of dialogs, and how to respond to the users' interaction with those dialogs. Before we get to that, we need to cover some ground rules about working with Ext.
Slide 45: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 The Staples of Ext Spacer image Before we proceed any further, we should provide Ext with something it needs—a spacer image. Ext needs a 1 pixel by 1 pixel, transparent, GIF image to stretch in different ways, giving a fixed width to its widgets. We need to set the location of this spacer image using the following line: Ext.onReady(function(){ Ext.BLANK_IMAGE_URL = 'images/s.gif'; }); You're probably wondering why we need a spacer image at all. The user interface of Ext is created using CSS, but the CSS needs underlying HTML elements to style so that it can create the look and feel of Ext components. The one HTML element that is an exact, predictable size across all browsers is an image. So an image is used to define how an Ext component is drawn. This is a part of how Ext maintains its cross-browser compatibility. Widget Ext has many "widgets". These include components such as a message box, grid, window, and pretty much everything else that serves a particular user interface function. I prefer to view components like onReady more as core functions, and only refer to components that provide a specific user interface role as a "widget"—like the grid that is used to present tabular data to the user. Time for action Let's create a new page (or just modify the 'getting started' example page) and add the code to display a dialog when the page is ready: Ext.onReady(function(){ Ext.BLANK_IMAGE_URL = 'images/s.gif'; Ext.Msg.show({ title: 'Milton', msg: 'Have you seen my stapler?', buttons: { yes: true, no: true, cancel: true } }); }); [ 24 ]
Slide 46: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 2 As we did in the previous chapter, we have placed our code inside an onReady function. We can then start to code our dialog and configure it using a config object. The config object used for this dialog has three elements, the last of which is a nested object for the three buttons. Here is how our code now looks in a browser: This displays what appears to be a very minimal dialog, but if we start clicking on things, the built-in functionality of Ext becomes apparent. The dialog can be dragged around the screen by grabbing the title bar, just like the dialog in a typical desktop application. There is a close button built–in, and pressing the Escape key when the dialog has focus, or clicking on the Cancel button will close the dialog. What just happened? Let's take a closer look at the two core Ext functions we have just used: • Ext.onReady: This function provides a way to make our code wait until the DOM is available, before doing anything. This is needed because JavaScript starts executing as soon as it is encountered in the document, at which point, our DOM elements might not exist. • Ext.Msg.show: This is the core function used for the creation of a dialog. It takes care of everything needed to have a working dialog. There are some shortcuts that can be used for common dialog types, which will help you save time. We will cover these in just a minute. Using onReady It's time to examine the code we just used to display our dialog. Ext.onReady(function(){ Ext.Msg.show({ title: 'Milton', msg: 'Have you seen my stapler?', buttons: { yes: true, [ 25 ]
Slide 47: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 The Staples of Ext no: true, cancel: true } }); }); The onReady function is what we use to make our code wait until the document is ready. The argument passed to onReady is a function, which can be passed in as a function name, or created in-line, as we have done in the example code. This method of creating a function in-line is referred to as an anonymous function, which is used when you plan on calling a particular function only once. If we were executing a function that will be used again, then we could define and call it like this: Function stapler(){ Ext.Msg.show({ title: 'Milton', msg: 'Have you seen my stapler?', buttons: { yes: true, no: true, cancel: true } }); } Ext.onReady(stapler()); When we start to make our application bigger, we are not likely to use many anonymous functions, and will probably opt for creating re-usable functions. The buttons record can also specify the text to display on the button. Instead of passing a boolean value, just pass it the text you want, for example, {yes: 'Maybe'}. More widget wonders Let's get back to making our little application as annoying as possible by adding an icon and buttons! This can be done by adding a style for the icon, and modifying the config to have an icon record along with a buttons record. [ 26 ]
Slide 48: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 2 First, let's discuss the CSS we need. Add the following code into the head of the document, within a style tag: .milton-icon { background: url(milton-head-icon.png) no-repeat; } Also, we will make some changes to our widgets configuration. The icon record just needs our style name as the value, milton-icon. We have also included a function to be executed when a user clicks on any of the buttons in the dialog. This function is created as an anonymous function, and in this case, it is merely used to pass variables: Ext.Msg.show({ title: 'Milton', msg: 'Have you seen my stapler?', buttons: { yes: true, no: true, cancel: true }, icon: 'milton-icon', fn: function(btn) { Ext.Msg.alert('You Clicked', btn); } }); In our case, the function has only one argument, which is the name of the button that was clicked. So if our user was to click the Yes button, the btn variable would contain a value of yes. Using the example code, we are taking the name of the button clicked, and passing it to alert, as the message. The built-in functionality takes care of making sure the Cancel button, the close icon in the upper right corner, and the Esc key are all tied together to perform the cancel action. This is one of the many ways in which Ext makes the coding of web applications easier for us. [ 27 ]
Slide 49: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 The Staples of Ext Meet JSON and the config object In our example, we are utilizing what's called a config object, which is the primary way to get Ext to do what you want. This is what provides the configuration of the different options that are available for the function that is being used. The old way We used to call functions with a pre-determined set of arguments. This means that we had to remember the order of the arguments every time the function was used. var test = new TestFuntion( 'three', 'fixed', 'arguments' ); This old way of using functions can create many problems: • • • It requires us to remember the order of the arguments It does not describe about what the arguments represent It provides less flexibility in dealing with optional arguments The new way—config objects Using a config object, we are able to have a larger level of flexibility, and can tell what our variables are in descriptive plain text. The order of our arguments no longer matters—firstWord could be the last item, and thirdWord could be the first, or they could be in any random order. With the config object method of passing arguments to your functions, the arguments no longer needs to be tied down to a specific place. var test = new TestFunction({ firstWord: 'three', secondWord: 'fixed', thirdWord: 'arguments' }); This method also allows for unlimited expansion of our function's arguments. Using fewer arguments or adding new arguments is simple. Another great result that comes by using a config object is that the prior usage of your functions will not be harmed by the addition or subtraction of arguments at a later point. var test = new TestFunction({ secondWord: 'three' }); [ 28 ]
Slide 50: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 2 var test = new TestFunction({ secondWord: 'three', fourthWord: 'wow' }); What is a config object? If you are familiar with CSS or JSON, you'll notice that a config object looks similar to these, mostly because they are all the same. Config objects are just ways of structuring data so that it can easily be read by programming languages—in our case, JavaScript. For an example, let's take a look at the config portion of our example code: { title: 'Milton', msg: 'Have you seen my stapler?', buttons: { yes: true, no: true, cancel: true }, icon: 'milton-icon', fn: function(btn) { Ext.Msg.alert('You Clicked', btn); } } The particular config that we are using here may appear complex at first, but once we get to know it, it becomes an extremely fast way of configuring widgets. Just about every Ext widget uses a configuration object, so this is something that we will want to become very familiar with. The config object will become our new best friend. Here are some key things to remember when working with a config object: • • Curly brackets wrap around your whole record set, which symbolizes the records inside the brackets as being part of an object—{records}. Each record consists of a set of name/value pair, with the name and value separated by a colon, and pairs separated by commas—{name0: value0, name1: value1}. • The records' values can contain any type of data, including boolean, array, function, or even another object—{ name0: true, name1: { name2: value2 } }. [ 29 ]
Slide 51: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 The Staples of Ext • Square brackets identify an array—{name: [ 'one', 'two', 'three' ] }. An array can also contain objects with records, values, or any number of other things. The best thing about using JSON to configure our widgets is that if we want more options, we just start typing them out. Presto! Unlike a typical function call, the order of your config options has become irrelevant, and there can be as few or as many as necessary. How does JSON work? Sometimes, you will hear people talk about eval, which generally refers to JSON. The eval function is what JavaScript uses to interpret a JSON string, converting it into the objects, arrays, and functions that we are using. Time for action Ok! So now we've seen how to get our Ext JS party started and ask the user a question. Now let's see what we can do with their answers. Let's add to our dialog's function so that we can decide what to do in response to each of the button-clicks. A switch statement can take care of deciding what to do in each case: fn: function(btn) { switch(btn){ case 'yes': Ext.Msg.prompt('Milton', 'Where is it?'); break; case 'no': Ext.Msg.alert('Milton', 'Im going to burn the building down!'); break; case 'cancel': Ext.Msg.wait('Saving tables to disk...','File Copy'); break; } } Remember those built in dialog types I mentioned earlier? Well we just used some of them. They let us accomplish some common tasks without spending time writing the config needed for each standard scenario. [ 30 ]
Slide 52: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 2 Click OK and you get a prompt. A prompt is the common name for a small window that allows you to enter a single value, and is a standard element in almost every user interface. Click No and you get an alert. I'm sure you are familiar with the standard alert dialog in JavaScript. I remember the first time I used an alert dialog in JavaScript. I was so excited to have an alert message on my home page that I made it pop up and say "Click OK if you are a moron". Click the Cancel button(or click the close button or press the Escape key) and you will (or get a wait message that's using a progress dialog. The progress dialog we are using can be controlled by Ext and be notified when it should disappear. But for the sake of simplicity, in this example, we are letting it run forever. Button focus and tab orders are built into Ext. Typically the OK or Yes button will be the default action. So pressing Enter on your keyboard will trigger that button, and pressing Tab will move you through the buttons and other items in the dialog. [ 31 ]
Slide 53: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 The Staples of Ext Lighting the fire Now, we can start causing some reactions in our page, based on the users' responses to the dialogs. We are going to add to our switch statement, which takes care of a Yes button click. The prompt function can handle a third argument, which is the function to be executed after the Yes button has been clicked. We are defining this so that the function will check to see if the value entered into our prompt dialog is equal to the office and then write this text to a DIV in our page if it is, and a default text of Dull Work if it does not. The code also applies a style to the same DIV, which uses a "Swingline" stapler background image. case 'yes': Ext.Msg.prompt('Milton', 'Where is it?', function(btn,txt) { if (txt.toLowerCase() == 'the office') { Ext.get('my_id').dom.innerHTML = 'Dull Work'; }else{ Ext.get('my_id').dom.innerHTML = txt; } Ext.DomHelper.applyStyles('my_id',{ background: 'transparent url(images/stapler.png) 50% 50% no-repeat' }); }); break; The no case will display an alert message, which also styles the document when the No button is clicked. case 'no': Ext.Msg.alert('Milton', 'Im going to burn the building down!', function() { Ext.DomHelper.applyStyles('my_id',{ 'background': 'transparent url(images/fire.png) 0 100% repeat-x' }); [ 32 ]
Slide 54: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 2 Ext.DomHelper.applyStyles(Ext.getBody(),{ 'background-color': '#FF0000' }); Ext.getBody().highlight('FFCC00',{ endColor:'FF0000', duration: 6 }); }); break; The workhorse—Ext.get Ext is able to work so well, because it has a foundation that provides access to the DOM, and to many functions that allow manipulation of the DOM. Of these functions, get is one of the most used. Ext.get('my_id'); [ 33 ]
Slide 55: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 The Staples of Ext This gives us access to an element in the document with the ID, my_id. If we take a look at the first example, it is using getBody , which retrieves the body element and applies our effect to that. Let's switch that around to use my_id instead. But first, we will need to create a my_id element in our document: <div id='my_id' style='width:200px;height:200px;'>test</div> If we add this to the body section of our document, and change our effect to reference this instead of the body, then our effect will happen only to the my_id div we created: Ext.get('my_id').highlight('FF0000',{ endColor:'0000FF', duration: 3 }); If we now looked at our document in a browser, we would see a 200-pixel square box changing color, instead of the entire body of the document changing color. Bear in mind that IDs are unique. So once we have used my_id, we cannot use this ID again in our document. If duplicate IDs exist in your document, then the last one found will be used. But this should be considered as a bug, and not a design practice. For the most part, Ext creates and tracks its own IDs, and most of the time, we will default to Ext's tracking of the document elements and not create them on our own. Having duplicate IDs in your document can lead to strange behavior, such as a widgets always showing up in the upper left corner of the browser, and is therefore best avoided. Speed tip This isn't exactly a speed tip, but is more about conserving memory by using something called a "flyweight" to perform simple tasks, which results in higher speed by not clogging up the browser's memory. The same highlight effect we just used, could be written using a flyweight instead: Ext.fly('my_id').highlight('FF0000',{ endColor:'0000FF', duration: 3 }); This is used when we want to perform an action on an element in a single line of code, and we do not need to reference that element again. The flyweight re-uses the same memory over and over each time it is called. [ 34 ]
Slide 56: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 2 Here is an example of using a flyweight incorrectly: var my_id = Ext.fly('my_id'); Ext.fly('another_id'); my_id.highlight('FF0000',{ endColor:'0000FF', duration: 3 }); Because the flyweight re-uses the same memory each time it is called, by the time we run the highlight function on our my_id reference, the memory has changed to actually contain a reference to another_id. Summary Using only a few lines of code, we have created a fun program that will keep you entertained for hours! Well, maybe not for hours, but for at least a few minutes. Nonetheless, we have the beginnings of the basic functionality and user interface of a typical desktop application. We have learned the basics of using configuration objects, and I'm sure this will make even more sense after we have had the chance to play with some more Ext widgets. But the real point here is that the configuration object is something that is very fundamental when using Ext. So the quicker you can wrap your head around it, the better off you will be. Don't worry if you are not entirely comfortable with the configuration object yet. We have plenty of time to figure it out. For now, let's move on to one of my favorite things—forms. [ 35 ]
Slide 57: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098
Slide 58: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Forms In this chapter, we will learn how to create Ext forms, which are similar to the HTML forms that we use, without the usability restrictions and boring user interface. We use some different form field types to create a form that validates and submits asynchronously. Then we will create a database-driven, drop-down menu (ComboBox), and add some more complex field validation and masking. We will then finish it off with a few advanced topics that will give our forms some serious 'wow' factor. The goals of this chapter include: • • • Creating a form that uses AJAX submission Validating field data and creating custom validation Loading form data from a database The core components of a form The possibilities are endless with Ext forms. Key listeners, validation, error messages, and value restrictions are all built in with simple config options. Extending a form option for your own specific needs can be done easily, which is something we will cover later on in this chapter. Here are some of the core form components that you should become familiar with: • • Ext.form.FormPanel: Groups fields together in a panel, much as the FORM tag does for a standard HTML form Ext.form.Field: As the primary handler of form field creation and interaction, it can be compared to the INPUT tag in HTML
Slide 59: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Forms Our first form To start with, let's create a form with multiple field types, a date picker, validation, error messages, and AJAX submission—just a simple one for our first try. For this example, our fields will be created using a config object instead of an instantiated Ext.form.Field component. This method will work just fine, will take less time to code, and will help our code run faster. A basic HTML page like the one we used in the previous example will be used as a starting point. The standard Ext library files need to be included and, as with everything we create in Ext, our code will need to be wrapped in the onReady function. Ext.onReady(function(){ var movie_form = new Ext.FormPanel({ url: 'movie-form-submit.php', renderTo: document.body, frame: true, title: 'Movie Information Form', width: 250, items: [{ xtype: 'textfield', fieldLabel: 'Title', name: 'title' },{ xtype: 'textfield', fieldLabel: 'Director', name: 'director' },{ xtype: 'datefield', fieldLabel: 'Released', name: 'released' }] }); }); When we run this code in a browser, we end up with a form panel that looks like this: [ 38 ]
Slide 60: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 3 Nice form—how does it work? The FormPanel is very similar to an HTML form. It acts as the container for our form fields. Our form has a url config so the form knows where to send the data when it is submitted. It also has a renderTo config, which defines where the form is displayed on the page. The items config element is the important one as it contains all of our form fields. The items config element is an array of fields. Each field element has an xtype that defines which type of Ext component will be used: text, date, or number. This could even be a grid or some other type of Ext component. Form fields Now we know that each type of field is defined by its xtype. But where do xtypes come from, and how many of them are there? An xtype is just a reference to a particular Ext component, so a 'textfield' xtype is the same as its Ext.form.TextField counterpart. Here are examples of some of the xtypes that are available to us: • • • • • • textfield timefield numberfield datefield combo textarea Because these are all just Ext components, we could easily be using a grid, toolbar, or button—pretty much anything! A recurring theme in Ext components is that everything is interchangeable, and everything shares the same core functions. This ensures that just about any scenario can be handled with the Ext library. Our basic field config is set up like this: { xtype: 'textfield', fieldLabel: 'Title', name: 'title' } Of course, we have the xtype that defines what type of a field it is—in our case it is a textfield. The fieldLabel is the text label that is displayed to the left of the field, although this can also be configured to be displayed on the top or the right side of the field. The name config is just the same as its HTML counterpart and will be used as the variable name when sending the form data to the server. [ 39 ]
Slide 61: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Forms The names of most of the config options for Ext components match their counterparts in HTML. This is because Ext was created by web developers, for web developers. Making our date field isn't much different from making the text field. Change the xtype to a datefield, and we're done. { xtype: 'datefield', fieldLabel: 'Released', name: 'released' } Validation A few of our sample fields could have validations that present the users with errors if the user does something wrong. Let's add some validation to our first form. One of the most commonly-used types of validation is checking to see if the user has entered any value at all. We will use this for our movie title field. In other words, let's make this field a required one: { xtype: 'textfield', fieldLabel: 'Title', name: 'title', allowBlank: false } Setting up an allowBlank config option and setting it to false (the default is true) is easy enough. Most forms we build will have a bunch of required fields just like this. Each type of Ext field also has its own set of specialized validations that are specific to the data type of that field. For instance, a date field has ways to disable certain days of the week, or to use a regular expression to disable specific dates. The following code disables every day except Saturday and Sunday: { xtype: 'datefield', fieldLabel: 'Released', name: 'released', disabledDays: [1,2,3,4,5] } [ 40 ]
Slide 62: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 3 In this example, everyday except Saturday and Sunday is disabled. Keep in mind that the week starts on 0 for Sunday, and ends on 6 for Saturday. When we use other types of fields, we have different validations, like number fields that can restrict the size of a number or how many decimal places the number can have. The standard validation options for each field type can be found in the API reference. Built-in validation—vtypes Another more complex type of validation is the vtype. This can be used to validate and restrict user input, and report back error messages. It will work in just about any scenario you can imagine because it uses regular expressions to do the grunt work. Here are some built-in vTypes that can come in handy: • • • • email url alpha alphanum [ 41 ]
Slide 63: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Forms These built-in vtypes are intended to be simplistic, and mostly used as a starting point for creating your own vtypes. Here is an alpha vtype being used with a QuickTips balloon error message: Ext.onReady(function(){ var movie_form = new Ext.FormPanel({ url: 'movie-form-submit.php', renderTo: document.body, frame: true, title: 'Movie Information Form', width: 250, items: [{ xtype: 'textfield', fieldLabel: 'Title', name: 'title', allowBlank: false },{ xtype: 'textfield', fieldLabel: 'Director', name: 'director', vtype: 'alpha' },{ xtype: 'datefield', fieldLabel: 'Released', name: 'released', disabledDays: [1,2,3,4,5] }] }); }); All we did was add a vtype to the director field. This will validate that the value entered is composed of only alphabetic characters. [ 42 ]
Slide 64: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 3 Now we're starting to see that the built-in vtypes are very basic. The built-in alpha vtype restricts our fields to alphabet characters only. In our case, we want the user to enter a director's name, which would usually contain only alphabet characters, with just one space or a hyphen. Capitalizing the first characters in the names could possibly make them look pretty. A search of the Ext forum is likely to come back with a vType that someone else has created that is either exactly what you need, or close enough to use as a starting point for your own requirements. Styles for displaying errors Forms are set up by default with a very bland error display which shows any type of error with a squiggly red line under the form field. This error display closely mimics the errors shown in programs like Microsoft Word when you spell a word incorrectly. We do have other options for displaying our error messages, but we will need to tell Ext JS to use it. The preferred option is to display the error message in a balloon. This utilizes the standard squiggly line, but also adds a balloon message that pops up when you mouse over the field. We just need to add a line of code before our form is created that will initialize the balloon messages. Typically this is the first line within the OnReady function. For example: Ext.onReady(function(){ Ext.QuickTips.init(); // our form here }); This is all that needs to happen for your form fields to start displaying error messages in a fancy balloon. [ 43 ]
Slide 65: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Forms Custom validation—create your own vtype If you're like me, regular expressions can leave you in a stupefied gaze at your monitor, so I always try to find something that is close to what I need and then modify it, rather than start from scratch. To create our own vtype, we need to add it to the vtype definitions. Each definition has a value, mask, error text, and a function used for testing: • • • xxxVal: This is the regular expression to match against xxxMask: This is the masking to restrict user input xxxText:This is the error message that is displayed As soon as we figure out the regular expressions we need to use, it's fairly straight forward creating our own vType—so lets try one out. Here is a validation for our director's name field. The regular expression matches a pair of alpha strings, separated by a space, and each starting with a capital letter. Sounds like a good way to validate a name—right? Ext.form.VTypes['nameVal'] = /^[A-Z][A-Za-z\-]+ [A-Z][A-Za-z\-]+$/; Ext.form.VTypes['nameMask'] = /[A-Za-z\- ]/; Ext.form.VTypes['nameText'] = 'In-valid Director Name.'; Ext.form.VTypes['name'] = function(v){ return Ext.form.VTypes['nameVal'].test(v); } It's hard to look at this all at once, so let's break it down into its main parts. We first start with the regular expression that validates the data entered into our form field: Ext.form.VTypes['nameVal'] = /^([A-Z]{1})[A-Za-z\-]+ ([A-Z]{1})[A-Za-z\-]+/; Next, we add the masking, which defines what characters can be typed into our form field. This is also in the form of a regular expression: Ext.form.VTypes['nameMask'] = /[A-Za-z]/; Then, we have the text to be displayed in a balloon if there is an error: Ext.form.VTypes['nameText'] = 'In-valid Director Name.'; [ 44 ]
Slide 66: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 3 And finally, the part that pulls it all together—the actual function used to test our field value: Ext.form.VTypes['name'] = function(v){ return Ext.form.VTypes['nameVal'].test(v); } Put all this together and we have our own custom vtype without much effort, and that can be used over and over again. Masking—don't press that key! Masking is used when a particular field is forced to accept only certain keystrokes, such as numbers only, or letters only, or just capital letters. The possibilities are limitless, because regular expressions are used to decide what keys to filter out. This mask example would allow an unlimited string of capital letters: maskRe: /[A-Z]/ Instead of using the masking config, consider creating a vType to accomplish your masking. If the formatting requirements should happen to change, it will be centrally-located for easy changing. So when the day arrives where your boss comes to you freaking out and tells you, "Remember those product codes that I said would always be ten numbers, well it turns out they will be eight letters instead", you can make the change to your vType, and go play Guitar Hero for the rest of the day! [ 45 ]
Slide 67: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Forms Radio buttons and check boxes Radio buttons and check boxes are a necessary evil. They are clumsy, and hard to work with. I try to use them only as a last resort, when nothing else will do the job. But let's add them to our form just so we can say that we did. It's not a button, it's a radio button Lets first add a set of radio buttons to our form: { xtype: 'radio', fieldLabel: 'Filmed In', name: 'filmed_in', boxLabel: 'Color' },{ xtype: 'radio', hideLabel: false, labelSeparator: '', name: 'filmed_in', boxLabel: 'Black & White' } These radio buttons work much like their HTML counterparts. Give them all the same name, and they will work together for you. I also like to hide the labels for the trailing radio buttons by setting hideLabel to true and labelSeperator to an empty value. This gives the form a cleaner look. X marks the check box Sometimes, we need to use check boxes for boolean values—sort of an on/off switch. { xtype: 'checkbox', fieldLabel: 'Bad Movie', name: 'bad_movie' } [ 46 ]
Slide 68: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 3 The ComboBox The ComboBox, or SELECT as its known in HTML, also called a drop-down menu, is a highly-useful form element. It reduces the users' need to touch the keys on their keyboards. The Ext ComboBox has a ton of practical uses, and just as many configuration options to keep track of. First, let's make a combo using local data. To do this, we need to create a data store. There are a few different types of data store, each of which can be used for different situations. However, for this one, we are going to use a simple store: var genres = new Ext.data.SimpleStore({ fields: ['id', 'genre'], data : [['1','Comedy'],['2','Drama'],['3','Action']] }); Just like the other fields in our form, we add it to the items config. A few other config options are needed when we are setting up a combo box. The store is the obvious one-this is the data that populates the options for our combo. The other things we need are the mode, which determines if the data is coming from a local source or a remote source, and the displayField, which determines which column of data is displayed in the combo options: { xtype: 'combo', name: 'genre', fieldLabel: 'Genre', mode: 'local', store: genres, displayField:'genre', width: 120 } This gives us a combo box that uses local data, which is good for small lists, or lists that don't change often. What happens when our list needs to be pulled up from a database? Database-driven ComboBox The biggest change that needs to happen is on the server side—getting your data and formatting it into a JSON string that the combo box can use. Whatever server-side language is used, we will need a JSON library to 'encode' the data. If we're using PHP 5.1 or higher, this is built in. [ 47 ]
Slide 69: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Forms To check our version of PHP, we can either execute a command in a terminal window or run a single line of PHP code. If we have access to this command line we can run php –v to check our version, otherwise, running a script that just has the single line <?php phpinfo(); ?> will do the job. This is what we would use to generate our JSON data using PHP 5.1 or higher: <?php // connection to database goes here $result = mysql_query('SELECT id, genre_name FROM genres'); If (mysql_num_rows($result) > 0) { while ($obj = mysql_fetch_object($result)) { $arr[] = $obj; } } Echo '{rows:'.json_encode($arr).'}'; ?> When we use remote data, there are a few more things that need to happen. First, the data store needs to know what format the data is in. We specify this by using a data reader—in our case, it's the JSON Reader. var genres = new Ext.data.Store({ reader: new Ext.data.JsonReader({ fields: ['id', 'genre_name'], root: 'rows' }), proxy: new Ext.data.HttpProxy({ url: 'data/genres.php' }) }); The first argument for the data reader is an object containing the configuration of our reader—specifically, which fields will be read and what the root element is. The fields list is simply an array of field names; notice that we left out sort_order—this field will not be available to our data set. Our root is the element that contains our array of data, in this case it's rows, but could just as easily be bobs-crab-shack, or whatever you felt like: {rows:[ { "id":"1", "genre_name":"Comedy", "sort_order":"0" },{ [ 48 ]
Slide 70: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 3 "id":"2", "genre_name":"Drama", "sort_order":"1" },{ // snip...// }] } We have also set up the proxy—typically this will be an HTTP Proxy that retrieves data from the same domain as the web page. This is the most common method, but there is also a ScriptTagProxy that can be used to retrieve data from a different domain. All we need to provide for our proxy is the URL to fetch our data from. Whenever we specify a 'proxy' we are actually using AJAX. This requires that you have a web server running, otherwise AJAX will not work. Simply running your code from the file system in a web browser will not work. Let's throw in a call to the load function at the end, so the data is loaded into our combo box before the user starts to interact with it. genres.load(); This gives us a combo box that's populated from our database, and should look like this: Another way to pre-load the data store is to set the autoLoad option to true in our data store configuration: var genres = new Ext.data.Store({ reader: new Ext.data.JsonReader({ fields: ['id', 'genre_name'], root: 'rows' }), proxy: new Ext.data.HttpProxy({ url: 'data/genres.php' }), autoLoad: true }); [ 49 ]
Slide 71: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Forms TextArea and HTMLEditor We are going to add a text field to our movie information form, and Ext has a couple of options for this. We can either use the standard textarea that we were familiar with from using HTML, or we can use the HTMLEditor field, which provides rich text editing: • • textarea: Similar to a typical HTML textarea field htmleditor: A rich text editor with a button bar for common formatting tasks If we set hideLabel to true and clear out the label separator then we can have a textarea that spans the entire width of our form panel. This gives a nice look to the form: { xtype: 'textarea', name: 'description', hideLabel: true, labelSeparator: '', height: 100, anchor: '100%' } By changing just the xtype, as shown below, we now have a fairly simple HTML editor with built-in options for font face, size, color, italics, bold, and so on. This is the first Ext component we have used that requires the QuickTips component to be initialized before we can use it. { xtype: 'htmleditor', name: 'description', hideLabel: true, labelSeparator: '', height: 100, anchor: '100%' } [ 50 ]
Slide 72: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 3 Listening for form field events Ext makes it extremely simple to listen for particular user actions, such as clicking on an element or pressing a particular key. A common task would be listening for the Enter key to be pressed, and then submitting the form. So let's see how this is accomplished: { xtype: 'textfield', fieldLabel: 'Title', name: 'title', allowBlank: false, listeners: { specialkey: function(f,e){ if (e.getKey() == e.ENTER) { movie_form.getForm().submit(); } } } } The specialkey listener is called whenever a key related to navigation is pressed. This listener is also called every time the arrow keys are pressed, along with Tab, Esc, and so on. That's why we have to check to see if it was the Enter key before we take action. Now the form will only be submitted when you press Enter. ComboBox events It seems that combo boxes commonly need to have events attached to them. Let's take our genre combo box and attach a listener to it that will run when an item in the list is selected. First let's add a dummy item to our data as the first item in the list and call it New Genre: var genres = new Ext.data.SimpleStore({ fields: ['id', 'genre'], data : [ ['0','New Genre'], ['1','Comedy'], ['2','Drama'], ['3','Action'] ] }); [ 51 ]
Slide 73: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Forms Then, we add the listener to our combo: { xtype: 'combo', name: 'genre', fieldLabel: 'Genre', mode: 'local', store: genres, displayField:'genre', width: 130, listeners: { select: function(f,r,i){ if (i == 0){ Ext.Msg.prompt('New Genre','Name',Ext.emptyFn); } } } } The listener is set up to wait for a select event and then run the function that is specified. Each listener type has its own set of variables that is passed to the function—these can be looked up in the API reference. For the select event, our function is passed three things: • • • The form field The data record of the selected combo item The index number of the item that was clicked on Once the list item is selected, we can see which item in the list was selected. The third argument in our listener function is the index of the item that was clicked. If that has an index of zero (the first item in the list), then we will prompt the user to enter a new genre using the prompt dialog we learned about in the previous chapter. [ 52 ]
Slide 74: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 3 Just about every component in Ext has a listener. A list of valid events for these listeners can be found at the bottom of the API documentation page for each component. Buttons and form action Now, we have quite a mess of a form with only one problem – it doesn't send data to the server, which was the actual point behind creating our form in the first place. To do, this we are going to add some buttons. Our buttons are added to a buttons config object, similar to the way that the form fields were added. These buttons really only need two things: the text to be displayed on the button, and the function(which is called the handler) to execute when the button is clicked. buttons: [{ text: 'Save', handler: function(){ movie_form.getForm().submit({ success: function(f,a){ Ext.Msg.alert('Success', 'It worked'); }, failure: function(f,a){ Ext.Msg.alert('Warning', 'Error'); } }); } }, { text: 'Reset', handler: function(){ movie_form.getForm().reset(); } }] The handler is provided with a function—or a reference to a function—that will be executed once the button is clicked. In this case, we are providing an anonymous function. Form submission Our FormPanel has a url option that contains the name of the file that the form data will be sent to. This is simple enough—just like an HTML form, all of our fields will be posted to this url, so they can be processed on the server side. [ 53 ]
Slide 75: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Forms Inside our Save button, we have an anonymous function that runs the following code. This will run the actual submission function for our form, which sends the data to the server using AJAX. No page refresh is needed to submit the form. It all happens in the background, while the page you are looking at remains the same: movie_form.getForm().submit({ success: function(f,a){ Ext.Msg.alert('Success', 'It worked'); }, failure: function(f,a){ Ext.Msg.alert('Warning', 'Error'); } }); In order for our form submission to work properly, it must be run from a web server. success and failure options provided to the submit call handle the server's response. These are also anonymous functions, but could just as easily be references to functions created earlier on in the code. Did you notice that the functions have a pair of arguments passed to them? These will be used to figure out what response the server gave. But first, we need to discuss how to provide that response on the server side. Talking back—the server responses When our form is submitted to the server, a script on the server side will process the post data from the form, and decide if a true or false 'success' message should be sent back to the client side. Error messages can be sent back along with our response, and these can contain messages that correspond to our form field names. When using forms and server-side validation, a success boolean value is required. An example of a response from the server would look like this: { success: false, errors: { title: "Sounds like a Chick Flick" } } When the success flag is set to false, it triggers the Ext form to read in the error messages and apply them to the form's validation to present the user with error messages. [ 54 ]
Slide 76: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 3 Server-side validation of our form submission gives us a way to look up information on the server side, and return errors based on this. Let's say we have a database of bad movie names, and we don't want users to submit them to our database. We can submit the form to our script, which checks the database and returns a response based on the database lookup of that name. If we wanted to filter out chick flicks the response could look something like this: { success: false, errors: { title: "Sounds like a Chick Flick" }, errormsg: "That movie title sounds like a chick flick." } The false success response triggers the forms error messages to be displayed. An errors object is passed with the response. The form uses this object to determine each of the error messages. A name/value pair exists in the errors object for each form field's error. Our example response also passes an errormsg, which is not used by the form, but is going to be accessed separately to present our own error message. Let's take the extra error message that we were passing back, and display it in a message box. buttons: [{ text: 'Save', handler: function(){ movie_form.getForm().submit({ success: function(f,a){ Ext.Msg.alert('Success', 'It worked'); }, failure: function(f,a){ Ext.Msg.alert('Warning', a.result.errormsg); } }); } }, { text: 'Reset', handler: function(){ movie_form.getForm().reset(); } }] Our submit form action passes information back to the success and failure handlers. The first argument is an Ext form object, and the second is an Ext action object. Let's take a look at what's available in the Ext action object: [ 55 ]
Slide 77: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Forms Option failureType response result type String Object Object String Description Reports both client-side and server-side errors Contains raw information about the server's response, including useful header information Parsed JSON object based on the response from the server The type of action that was performed–either submit or load Now that we know what is available to the failure handler, we can set up some simple error checking: failure: function(f,a){ if (a.failureType === Ext.form.Action.CONNECT_FAILURE) {Ext.Msg.alert('Failure', 'Server reported: '+a.response.status+' '+a.response.statusText); } if (a.failureType === Ext.form.Action.SERVER_INVALID){ Ext.Msg.alert('Warning', a.result.errormsg); } } By checking the failure type, we can determine if there was a server connection error and act accordingly, even providing details about the server's specific error message by using the result property. Loading a form with data There are three basic ways in which forms are used in a user interface: • • • To input data for a separate action—say, Google search To create new data To change existing data It's the last option that we are interested in now. To accomplish this, we need to learn how to load that data from its source (static or database) into our user interface. Static data load We can take data from somewhere in our code, and display it as the value in a form field. This single line of code sets a fields value: movie_form.getForm().findField('title'). setValue('Dumb & Dumber'); [ 56 ]
Slide 78: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 3 Once we start working with more complex forms, this method becomes a hassle. That's why we also have the ability to load our data via an AJAX request. The server side would work much as it did when we loaded the combo box: <?php // connection to database goes here $result = mysql_query('SELECT * FROM movies WHERE id = '.$_ REQUEST['id']); If (mysql_num_rows($result) > 0) { $obj = mysql_fetch_object($result); Echo '{success: true, data:'.json_encode($obj).'}'; }else{ Echo '{success: false}'; } ?> This would return a JSON object containing a success flag, and a data object that would be used to populate the values of the form fields. The returned data would look something like this: { success: true, data:{ "id":"1", "title":"Office Space", "director":"Mike Judge", "released":"1999-02-19", "genre":"1", "tagline":"Work Sucks", "coverthumb":"84m.jpg", "price":"19.95", "available":"1" } } To trigger this, we need to use the form's load handler: movie_form.getForm().load({ url:'data/movie.php', params:{ id: 1 } }); [ 57 ]
Slide 79: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Forms Providing it with a url and params config will do the trick. The params config represents what is sent to the server side script as post/get parameters. By default, these are sent as post parameters. Object reference or component config Throughout these first few chapters, we have started to use more and more configuration objects to set up our Ext JS components, instead of instantiating them. Let's do a quick comparison of the two methods. Instantiated var test = new Ext.form.TextField({ fieldLabel: 'Title', name: 'title', allowBlank: false }); Here, the component has been created and memory used right away, even if it is not displayed on the screen yet. Depending on how your end users work with your application, they might never even need or use this particular text field. However, when it is the time to display this field to the end users, it shows up really fast. Component config { xtype: 'textfield', fieldLabel: 'Title', name: 'title', allowBlank: false } [ 58 ]
Slide 80: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 3 With the component config, we have a 'description' of what has to happen when it is time to use the field. No memory is used right away. It's only when the user needs it that the memory is used. At that point, the field is rendered after the user has clicked on or interacted with something else, which can slow the initial display slightly. This method of setting up components has many other advantages; one of them is being able to send configurations 'over the wire'. The method of sending configurations 'over the wire' means that server-side code can generate a configuration to create a client-side component. Summary We have taken the foundation of the classic web application—forms—and injected them with the power of Ext JS, creating a uniquely-flexible and powerful user interface. The form created in this chapter can validate user input, load data from a database, and send that data back to the server. From the methods outlined in this chapter, we can go on to create forms for use in simple text searches, or a complexly validated data entry screen. [ 59 ]
Slide 81: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098
Slide 82: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Buttons, Menus, and Toolbars The unsung heroes of every application are the simple things like buttons, menus, and toolbars. In this chapter, we will cover how to add these items to our applications. Our example will contain a few different types of buttons, both with and without menus. A button can simply be an icon, or text, or both. Toolbars also have some mechanical elements such as spacers and dividers that can help to organize the buttons on your toolbars items. We will also cover how to make these elements react to user interaction. A toolbar for every occasion Just about every Ext component—panels, windows, grids can accept a toolbar panels, on either the top or the bottom. The option is also available to render the toolbar standalone into any DOM element in our document. The toolbar is an extremely flexible and useful component that will no doubt be used in every application. • • • Ext.Toolbar: The main container for the buttons Ext.Button: The primary handler for button creation and interaction Ext.menu: A menu Toolbars Our first toolbar is going to be rendered standalone in the body of our document. We will add one of each of the main button types, so we can experiment with each: • • Button—tbbutton: This is the standard button that we are all familiar with. Split Button—tbsplit: A split button is where you have a default button action and an optional menu. These are used in cases where you need to have many options in the same category as your button, of which there is a most commonly used default option.
Slide 83: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Buttons, Menus, and Toolbars • Menu—tbbutton+menu: A menu is just a button with the menu config filled in with options. Ext.onReady(function(){ new Ext.Toolbar({ renderTo: document.body, items: [{ xtype: 'tbbutton', text: 'Button' },{ xtype: 'tbbutton', text: 'Menu Button', menu: [{ text: 'Better' },{ text: 'Good' },{ text: 'Best' }] },{ xtype: 'tbsplit', text: 'Split Button', menu: [{ text: 'Item One' },{ text: 'Item Two' },{ text: 'Item Three' }] }] }); }); As usual, everything is inside our onReady event handler. The items config holds all of our toolbars elements—I say elements and not buttons because the toolbar can accept many different types of Ext components including form fields—which we will be implementing later on in this chapter. The default xtype for each element in the items config is tbbutton. We can leave out the xtype config element if tbbutton is the type we want, but I like to include it just to help me keep track. [ 62 ]
Slide 84: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 4 The button Creating a button is fairly straightforward; the main config option is the text that is displayed on the button. We can also add an icon to be used alongside the text if we want to. Here is a stripped-down button: { xtype: 'tbbutton', text: 'Button' } Menu A menu is just a button with the menu config populated—it's that simple. The menu items work along the same principles as the buttons. They can have icons, classes, and handlers assigned to them. The menu items could also be grouped together to form a set of option buttons, but first let's create a standard menu. This is the config for a typical menu config: { xtype: 'tbbutton', text: 'Button', menu: [{ text: 'Better' },{ text: 'Good' },{ text: 'Best' }] } [ 63 ]
Slide 85: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Buttons, Menus, and Toolbars As we can see, once the menu array config is populated, the menu comes to life. To group these menu items together, we would need to set the group config and the boolean checked value for each item: menu: [{ text: 'Better', checked: true, group: 'quality' }, { text: 'Good', checked: false, group: 'quality' }, { text: 'Best', checked: false, group: 'quality' }] Split button The split button sounds like a complex component, but it's just like a button and a menu combined, with a slight twist. By using this type of button, you get to use the functionality of a button while adding the option to select an item from the attached menu. Clicking the left portion of the button that contains the text triggers the button action. However, clicking the right side of the button, which contains a small down arrow, triggers the menu. { xtype: 'tbsplit', text: 'Split Button', menu: [{ text: 'Item One' },{ text: 'Item Two' },{ text: 'Item Three' }] } [ 64 ]
Slide 86: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 4 Toolbar item alignment, dividers, and spacers By default, every toolbar aligns elements to the leftmost side. There is no alignment config for a toolbar, so if we want to align all of the toolbar buttons to the rightmost side, we need to add a fill as the first item in the toolbar. If we want to have items split up between both the left and right sides, we can also use a fill: { xtype: 'tbfill' } Pop this little guy in a tool-bar wherever you want to add space and he will push items on either side of the fill to the ends of the tool bar, as shown below: We also have elements that can add space or vertical dividers, like the one used between the Menu Button and the Split Button. The spacer adds a few pixels of empty space that can be used to space out buttons, or move elements away from the edge of the toolbar: { xtype: 'tbspacer' } A divider can be added in the same way: { xtype: 'tbseparator' } [ 65 ]
Slide 87: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Buttons, Menus, and Toolbars Shortcuts Ext has many shortcuts that can be used to make coding faster. Shortcuts are a character or two that can be used in place of a configuration object. For example, consider the standard toolbar filler configuration: { xtype: 'tbfill' } The shortcut for a toolbar filler is a hyphen and a greater than symbol: '->' Not all of these shortcuts are documented. So be adventurous, poke around the source code, and see what you can find. Here is a list of the commonly-used shortcuts: Component Fill Separator Spacer Shortcut '->' '-' or 'separator' '' Description The fill that is used to push items to the right side of the toolbar. A vertical bar used to visually separate items. Empty space used to separate items visually. The space is two pixels wide, but can be changed by overriding the ytb-spacer CSS class. Add any text or HTML directly to a toolbar by simply placing it within quotes. TextItem 'Your Text' Icon buttons The standard button can act as an icon button like the ones you see used in text editors to make text bold or italic. Two steps need to be taken to make an icon button—defining an image to be used as the icon and applying the appropriate class to the button. { xtype: 'tbbutton', cls: 'x-btn-icon', icon: 'images/bomb.png' } [ 66 ]
Slide 88: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 4 This could just as easily be an icon beside text by changing the style class and adding the text config. { xtype: 'tbbutton', cls: 'x-btn-text-icon', icon: 'images/bomb.png', text: 'Tha Bomb' } Button handlers—click me! A button needs to do more than just look pretty—it needs to react to the user. This is where handlers come in. A handler is a function that is executed when a button or menu item is clicked. The handler config is where we add our function: { xtype: 'tbbutton', text: 'Button', handler: function(){ Ext.Msg.alert('Boo', 'Here I am'); } } This code will pop up an alert message when the button is clicked. Sometimes, we need to make changes to the button when it's clicked, so each button handler passes ach a reference to itself for this purpose. The first argument of our handler is a reference to the component that triggered the event. { xtype: 'tbbutton', text: 'Button', handler: function(f){ f.disable(); } } We can take this reference to the button—a reference to itself—and access all of the properties and functions of that button. For this sample, we have called the disable function which grays out the button and makes it unselectable. We can have more fun than just disabling a button. Why don't we try something more useful? [ 67 ]
Slide 89: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Buttons, Menus, and Toolbars Load content on menu item click Lets take our button click and do something more useful with it. For this example, we are going to add a config option to each menu item that will be used to determine what content file to load in the body of our page: { xtype: 'tbsplit', text: 'Help', menu: [{ text: 'Genre', helpfile: 'genre', handler: Movies.showHelp },{ text: 'Director', helpfile: 'director', handler: Movies.showHelp },{ text: 'Title', helpfile: 'title', handler: Movies.showHelp }] } Note the helpfile config option that we have added to each of the menu items config. We have made this config property up so that we have a way to store a variable that is unique to each menu item. This is possible because config properties can be anything we need them to be, and can be created on the fly. In this case, we are using a config property as a variable that holds the name of the file we want to load. The other new thing we are doing is creating a collection of functions to handle the menu item click. These functions are all organized into a Movies class. var Movies = function() { return { showHelp : function(btn){ var helpbody = Ext.get('helpbody'); if (!helpbody) { Ext.DomHelper.append(Ext.getBody(), { tag:'div', id:'helpbody' }); } Movies.doLoad(btn.helpfile); }, [ 68 ]
Slide 90: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 4 doLoad : function(file){ Ext.get('helpbody').load({ url: 'html/' + file + '.txt' }); } }; }(); I don't want to get bogged down with too much detail about this Movies class just yet, but essentially all it does is handle our menu item clicks. This class will load a text file into the body of our web page via an AJAX request—which text file it loads is related to which menu item is clicked. So once this Movies class is in place in our page, we will be able to bring up this page in our browser and click on each menu item to load the relevant help file into the body of the page. . Next, we will try using a text field to perform this same type of action. Form fields in a toolbar Like most things in Ext, a tool bar can accept just about any Ext component. Naturally, form fields and combo boxes are very useful items to have on a toolbar. { xtype: 'textfield' } In the same way as we created form fields in the last chapter, we have added the form fields to the items array, which will place the form fields within the toolbar. Now let's make the form field do something useful, by having it perform the same functionality as our help menu, but in a more dynamic way. { xtype: 'textfield', listeners: { specialkey: Movies.doSearch } } [ 69 ]
Slide 91: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Buttons, Menus, and Toolbars This listener is added directly to the form field's config. For this, we are using a 's s specialkey listener, which we used in the previous chapter. This is the listener that is used to capture edit keystrokes, such as Enter and Delete among others. The handler function will be added to our small Movies class created earlier: doSearch : function(frm,evt){ if (evt.getKey() == evt.ENTER) { Movies.doLoad(frm.getValue()); } } Now we have a text field in our toolbar that enables us to type in the name of the text file to load. Try some of the samples used in our menu, such as director or title. Toolbars in windows, grids, and panels All of the toolbars we have been working with have an items config. If we want to place one of these toolbars into another Ext component, such as a panel or a window, we can simply take the contents of the items config for a toolbar, and place it within one of the two pre-set containers that exist for panel-type components. Panel-type components, such as the window and the grid, have a top and bottom toolbar config: • • tbar: The top toolbar bbar: The bottom toolbar [ 70 ]
Slide 92: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 4 If we wanted to place a toolbar at the top of a window, filling the tbar config with an array of toolbar items would give us what we wanted: new Ext.Window({ title: 'Help', id: 'helpwin', width: 300, height: 300, tbar: [{ text: 'Close', handler: function(){ Ext.getCmp('helpwin').close(); } },{ text: 'Disable', handler: function(t){ t.disable(); } }], autoLoad: 'html/' + btn.helpfile + '.txt' }).show(); Ext also has a custom toolbar for paged grids that contains all of the buttons for moving through pages of results. We will cover this special toolbar in the grid chapter later in this book. Summary In this chapter, we had the chance to play with a couple of different ways to create toolbar items, including using a config object or its shortcut. The many options available for toolbars make them a useful component for everything from the simplest button bar, to a complex combination of buttons, menus, and form fields. Interacting with the buttons, menus and form fields is easy using the built-in handlers. [ 71 ]
Slide 93: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098
Slide 94: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Displaying Data with Grids The grid is, without doubt, one of the most widely-used components of Ext. We all have data, and this needs to be presented to the end user in an easy-to-understand manner. The spreadsheet (a.k.a.: grid) is the perfect way to do this—the concept has been around for quite a while because it works. Ext takes that concept and makes it flexible and downright amazing! In this chapter we shall be: • • • • • Using a GridPanel to display structured data in a user-friendly grid Reading data from the server (or database) to display in the grid Working with a grid's events and manipulating the grid's features Using some advanced data formatting techniques for grids Paging data in a grid We will cover how to define the rows and columns, but more importantly, we will learn how to make the grid flashier. We can do this by adding custom rendered cells that contain images, and change styles based on data values. In doing this we are adding real value to our grid by breaking out of the boundaries of spreadsheets!
Slide 95: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Displaying Data With Grids What is a grid anyway? Ext grids are similar to a spreadsheet; there are two main parts to each spreadsheet: • • Columns Rows Here our columns are Title, Released, Genre, and Price. Each of the rows contains movies such as The Big Lebowski, Super Troopers, and so on. The rows are really our data; each row in the grid represents a record of data. Displaying structured data with a GridPanel Displaying data in a grid requires two Ext components: • • A store that acts like an in-memory database, keeping track of the data we want to display A grid panel that provides a way to display the data stored in a data store [ 74 ]
Slide 96: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 5 Before we start to create each of these, let's look at some of the terminology that will be used, because this can be confusing at first: • Columns: This refers to a whole column of data, and would contain information only relevant to the display of data down through the entire column, including the heading. In Ext JS, this information is part of the Column Model. • Fields: This also refers to an entire column of data, but is refers to the actual data values. With Ext JS, this is used in the reader, for loading data. Setting up a data store The first thing we need to do is set up our data, which will be placed into a data store. The data store types available in Ext give us a consistent way of reading different data formats such as XML and JSON, and reading this data in a consistent way throughout all of the Ext widgets. Regardless of whether this data it is JSON, XML, an array, or even a custom data type of your own, it's all accessed in the same way thanks to the data store. Some data stores available, by default, in Ext are: • • • Simple (Array) XML JSON A custom data store could be created to read data that does not fit into these categories. The Ext JS forums provide user-contributed data readers for things such as CSV and ColdFusion formats of data. Adding data to our data store In our first attempt, we are going to create a grid that uses simple local array data. The data we're using below is taken from a very small movie database of some of my favorite movies, and is similar to the data that will be pulled from an actual database later in this chapter. The data store needs two things: the data itself, and a description of the data—or what could be thought of as the fields. A reader will be used to read the data from the array, and this is where we define the fields of data contained in our array. The reader acts as an interpreter of sorts; it knows how to interpret a string of data as rows of data to be used with Ext JS. [ 75 ]
Slide 97: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Displaying Data With Grids The following code should be placed inside the Ext OnReady function: var store = new Ext.data.Store({ data: [ [ 1, "Office Space", "Mike Judge", "1999-02-19", 1, "Work Sucks", "19.95", 1 ],[ 3, "Super Troopers", "Jay Chandrasekhar", "2002-02-15", 1, "Altered State Police", "14.95", 1 ] //...more rows of data removed for readability...// ], reader: new Ext.data.ArrayReader({id:'id'}, [ 'id', 'title', 'director', {name: 'released', type: 'date', dateFormat: 'Y-m-d'}, 'genre', 'tagline', 'price', 'available' ] }); If we viewed this code in a browser we would not see anything—that's because a data store is just a way of loading and keeping track of your data. The web browser's memory has our data in it. Now we need to decide how to display it to the user. Defining your data for the data store The reader needs to know which fields to read in as data for our data store, so we will need to define these. [ 76 ]
Slide 98: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 5 Fields are defined using an array of objects—or if the data is to be read verbatim, just a string specifying the field name. All except one of our fields in this example can be defined with a simple name. For example, the title field could be defined using an object like this: {name: 'title'} However, in our case, because we are just reading in the data as a string, we can simply pass the field name and save some typing: 'title' The released field is different because we want to treat its data appropriately, as a date type. For each field format type, there may be options to define the format of the data more explicitly. With the date type, there is a dateFormat string that needs to be defined. If you have used PHP, these date format strings will look familiar, because Ext uses the same date format strings that PHP does. {name: 'released', type: 'date', dateFormat: 'Y-m-d'} Specifying data types Ext JS has many ways to properly read in particular data types. They are shown here: Field Type string int float boolean date Description String data Number Floating point number True/False data Date data dateFormat config needed Uses JavaScripts parseInt function Uses JavaScripts parseFloat function Information Below are a few useful data types that I take advantage of very often: Field Type date Description Data containing a date Usage You also have to specify the dateFormat. This tells Ext how to turn text data into dates Y-m-d means 'full 4 digit year-numbered month-numbered day' dateFormat in Ext is the same as in PHP, and there's a handy reference to different date formats online here: http://www.php.net/date [ 77 ]
Slide 99: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Displaying Data With Grids Field Type int Description Numeric data Usage Treats the value as an integer—this is useful when you plan on making comparisons of your data to perform other actions, such as adding two columns together Takes care of reading the different ideas of what boolean values are, such as converting a string to an actual boolean value, or translating zero and one to boolean values boolean or bool True/False data If we were to display the data just as the reader sees it, we would end up with something like this: Now that is ugly—here's a breakdown of what happened: • The released date has been type set properly as a date, and interpreted from the value in our data. It's provided in the standard ugly JavaScript date format—luckily Ext has ways to make this look pretty. The Price column has been type set as a floating point number. Note that there is no need to specify the decimal precision. The Avail column has been interpreted as a true boolean value, even if the raw data was not a true boolean value. • • This is why it's useful to specify the type of data that is being read, and apply any special options that are available. Displaying the GridPanel The thing that pulls everything together is the GridPanel, which takes care of placing the data into columns and rows, along with adding column headers, and boxing everything together in a neat little package. [ 78 ]
Slide 100: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 5 The movie data isn't much good to anybody just sitting in the computer's memory. Let's display it in a grid: 1. Add your data store to the following GridPanel code: Ext.onReady(function(){ // add your data store here var grid = new Ext.grid.GridPanel({ renderTo: document.body, frame:true, title: 'Movie Database', height:200, width:500, store: store, columns: [ {header: "Title", dataIndex: 'title'}, {header: "Director", dataIndex: 'director'}, {header: "Released", dataIndex: 'released', renderer: Ext.util.Format.dateRenderer('m/d/Y')}, {header: "Genre", dataIndex: 'genre'}, {header: "Tagline", dataIndex: 'tagline'} ] }); }); 2. Load it in a browser, and here's what you will see: [ 79 ]
Slide 101: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Displaying Data With Grids How did that work? Our data store is passed into the grid along with a column model that determines how the columns and column headers are to be displayed. This is different from the field data used in the reader, which was defined so that the reader knew how to read data. Configuring the GridPanel The GridPanel is the widget that ties everything together: Ext.grid.GridPanel Only a few basic things are needed to set up the GridPanel: Field type renderTo Description Where should the grid panel be displayed? Frames the grid panel Size in pixels Usage This needs to be a valid DOM object, or the ID of a DOM element. Later on, we will pass the GridPanel directly into the other widgets to be rendered. So this config option will become obsolete. This just adds a nice border around the GridPanel along with a title bar. It's not required, but looks good when rendered to the page. A height is almost always required when using a grid, as the grid itself cannot determine its own height. When we get into using grids in a layout, this will no longer be needed. This is a reference to a valid data store where our data lives. This is an array of objects defining the columns of our grid. This is set to true to alternate the colors in the rows of data. frame height and width store columns stripeRows Our data Column model Stripe rows Our basic setup for a grid panel will look something like this: var grid = new Ext.grid.GridPanel({ renderTo: Ext.getBody(), frame:true, title: 'Movie Database', height:200, width:500, store: store, columns: [ insert columns here ] }); [ 80 ]
Slide 102: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 5 We can almost read through the configuration like a sentence: Render our grid into the body of the document, frame it, and give it a title of 'Movie Database'. The height will be 200 and the width 500; it will use our 'store' data store and have the columns specified. The one reason why I love object-based configuration so much is that it is human readable. We never have to go to the manual to look up what argument 3 of function x is; we simply say "make it 200 tall and 500 wide". Defining a Grids column model To define our grid's columns, we need to create an array of objects that define how these columns are to be displayed and treated. columns: [ {header: {header: {header: {header: {header: ] 'Title', dataIndex: 'title'}, 'Director', dataIndex: 'director'}, 'Released', dataIndex: 'released'}, 'Genre', dataIndex: 'genre'}, 'Tagline', dataIndex: 'tagline'} This will create grid column headers that look like this: The object defining each column can have many config options, but requires that at least a header and dataIndex be defined. The header config is simply the text to be displayed in the column header. The dataIndex config is the name of the data field to be used in that column. We defined these when we set up the data stores reader. Here are some other useful config options for the column model: Option renderer Description Specifies how the data should be displayed Hides the column Usage Can be used to format the data for this column into your preferred format. Any type of data can be transformed. We will learn about these in the next few pages. Boolean value defining whether or not the column should be displayed. hidden [ 81 ]
Slide 103: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Displaying Data With Grids Option width Description Specifies the column width in pixels Specifies whether the column is sortable Usage The width of the column. Default is 100 pixels; overflowing content is hidden. Boolean value specifying whether or not the column can be sorted. sortable Using cell renderers We can do some pretty neat things with cell rendering. There are few limitations to stop us from making the cell look like or contain whatever we want. All that needs to be done is to specify one of the built-in cell formatting functions provided by Ext JS, such as usMoney, or create our own cell renderer that returns a formatted value. Let's take a look at using the built-in cell renderers first. Then we can look at creating our own. Formatting data using the built-in cell renderers Many built-in formatting functions exist to take care of common rendering requirements. One that I use quite often is the date renderer: renderer: Ext.util.Format.dateRenderer('m/d/Y') Some other renderers include some commonly-required formatting, such as money, capitalize, and lowercase. Here are some renderers that most people find useful: Renderer dateRenderer Description Formats a date for display Upper and lower case conversion Pretty text Usage Can be used to format the data for this column into your preferred date format. Any type of date can be transformed. Converts the string to completely upper or lower case text. Formats a text string to have correct capitalization. uppercase lowercase capitalize [ 82 ]
Slide 104: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 5 Creating lookup data stores—custom cell rendering We're going to start by taking the 'genre' column, which has a numeric value, and looking up that value in the data store we created in the Forms chapter to find the textual representation of our genre number. First, we add a config option to the column model that tells it which function to use for rendering the cell's content. {header: 'Genre', dataIndex: 'genre', renderer: genre_name} Now let's create that function. The function call is passed the value of its cell as the first argument. The second argument is a cell object, while the third is the data store for that grid—neither of which we will use for this renderer. So let's just leave them. function genre_name(val){ return genres.queryBy(function(rec){ if (rec.data.id == val){ return true; }else{ return false; } }).itemAt(0).data.genre; } The renderer function is passed the value of the current cell of data. This value can be tested, and actions can be performed on it—whatever value is returned by the function is rendered to the grid cell. A queryBy handler is used to filter the data from our store. It accepts a function that performs a comparison against each row of data, and returns true to use the row that matches. Just for good measure, here is a compacted version of the same function. It's not as easy to read as the first version, but accomplishes the same result. function genre_name(val){ return genres.queryBy(function(rec){ return rec.data.id == val; }).itemAt(0).data.genre; } [ 83 ]
Slide 105: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Displaying Data With Grids Combining two columns The lookup data store is a very useful renderer. However, it's more common for developers to combine two columns to form a single cell, for example, to perform a calculation on a pair of columns to figure out a total, percentage, remainder, and so on or to concatenate two or more text fields. Let's just take the title of our movie, and append the tagline field underneath the title. The first step will be to hide the tagline column, since it will be displayed along with the title field—we don't need it shown in two places. Hiding the column can be done in our column model. {header: 'Tagline', dataIndex: 'tagline', hidden: true} The next step is our renderer function that will take care of combining the fields. function title_tagline(val, x, store){ return '<b>'+val+'</b><br>'+store.data.tagline; } I went ahead and bolded the title as well, to provide some contrast between the two pieces of data. As you can see, HTML tags work just fine within grid cells. The next step would be to add the renderer config to our column model, referencing the title_tagline function that we just created. {header: 'Title', dataIndex: 'title', renderer: title_tagline} This will make the title column look like this: Generating HTML and graphics Let's get some visuals by placing an image into each row, which will show the cover art for each movie title. As we just found out, we can use plain HTML within the cell. So all that needs to happen is to create a renderer that grabs our field containing the filename of the image and write that into an IMG tag as the SRC attribute. function cover_image(val){ return '<img src=images/'+val+'>'; } [ 84 ]
Slide 106: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 5 With this fairly straightforward function, and setting a column renderer, we have an image in our grid: {header: 'Cover', dataIndex: 'coverthumb', renderer: cover_image} If you make all these renderer additions, the grid should now look like this: Built-in features Ext has some very nice built-in features to help complete the spreadsheet-like interface. Columns have a built-in menus that provide access to sorting, displaying, and hiding columns. [ 85 ]
Slide 107: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Displaying Data With Grids Client-side sorting Unless specified as a server-side (remotely) sorted grid, an Ext grid is able to sort columns on the client side. Server-side sorting should be used if the data is paged, or if the data is in such a format that client-side sorting is not possible. Client-side sorting is quick, easy, and built-in: {header: 'Tagline', dataIndex: 'tagline', sortable: true} We can also accomplish this after the grid has been rendered: var colmodel = grid.getColumnModel(); colmodel.getColumnById('tagline').sortable = true; Our column model controls the display of columns and column headers. If we grab a reference to the column model by asking for it from the grid, then we can make changes to the columns after it has been rendered. We do this by using the getColumnById handler that the column model provides us with, and which accepts the column ID as the argument. Hidden/visible columns Using the column header menu, columns can be hidden or shown. This can also be changed at a config level, to have columns hidden by default, as shown below: {header: "Tagline", dataIndex: 'tagline', hidden: true} The more exciting way is to do this after the grid has been rendered, by using the functions Ext provides: Var colmodel = grid.getColumnModel(); colmodel.setHidden(colmodel.getIndexById('tagline'),true); Grabbing a reference to the column model again will allow us the make this change. Column reordering Dragging a column header will allow the user to reorder the entire column into a new order within the grid. All of this is enabled by default as part of the built-in functionality of the grid. [ 86 ]
Slide 108: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 5 Any column can be dragged to a different order in the grid . This screenshot shows the Price column being moved to between the Title and Director columns. We can disable this functionality entirely by setting a config option in the GridPanel: enableColumnMove: false This move event—and many other events in the grid—can be monitored and responded to. For example, we could monitor the movement of columns and pop up a message based on where the column was moved to: grid.getColumnModel().on('columnmoved', function(cm,oindex,nindex) { var title = 'You Moved '+cm.getColumnHeader(nindex); if (oindex > nindex){ var dirmsg = (oindex-nindex)+' Column(s) to the Left'; }else{ var dirmsg = (nindex-oindex)+' Column(s) to the Right'; } Ext.Msg.alert(title,dirmsg); } ); Many different events can be monitored using the same technique. The grid, data store, and column model each have their own set of events that can be monitored, all of which we will learn about in more detail later in this chapter. [ 87 ]
Slide 109: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Displaying Data With Grids Displaying server-side data in the grid With Ext we can pull data into our web page in many ways. We started by pulling in local array data for use in the grid. Now we are going to pull the data in from an external file and a web server. Loading the movie database from an XML file We have this great movie database now, but each time I want to add a new movie I have to edit the JavaScript array. So why not store and pull our data from an XML file instead? This will be easier to update, and the XML file could even be generated from a database query or a custom script. Lets take a look at an example of how our XML file would be laid out like: <?xml version="1.0" encoding="UTF-8"?> <dataset> <row> <id>1</id> <title>Office Space</title> <director>Mike Judge</director> <released>1999-02-19</released> <genre>1</genre> <tagline>Work Sucks</tagline> <coverthumb>84m.jpg</coverthumb> <price>19.95</price> <active>1</active> </row> <row> <id>3</id> <title>Super Troopers</title> <director>Jay Chandrasekhar</director> <released>2002-02-15</released> <genre>1</genre> <tagline>Altered State Police</tagline> <coverthumb>42m.jpg</coverthumb> <price>14.95</price> <active>1</active> </row> //...more rows of data removed for readability...// </dataset> [ 88 ]
Slide 110: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 5 The other change we would need to make is to alter the data reader, and set the location of our XML file so that the data store knows where to fetch the data from. There are four basic changes that need to happen when moving from local to remote data: • The url config option, specifying the location of our data, needs to be added—this will replace the data config option that we used to store local data The reader is changed from an ArrayReader to an XmlReader to deal with the differences involved in reading from an XML format instead of an array format The XmlReader is told which element contains a record or row of data by setting the record config option A call needs to be added to the load function that tells our data store to pull in the data from the file and parse it into memory • • • var store = new Ext.data.Store({ url: 'movies.xml', reader: new Ext.data.XmlReader({ record:'row', id:'id' }, [ 'id', 'coverthumb', 'title', 'director', {name: 'released', type: 'date', dateFormat: 'Y-m-d'}, 'genre', 'tagline', {name: 'price', type: 'float'}, {name: 'available', type: 'bool'} ]) }); store.load(); Try making these changes and see if your grid still works—there should be no noticeable difference when changing data sources or formats. Note that to make the change from local to remote data, and from an array format to an XML format, the only changes we needed to make were to the data store. Ext isolates these types of changes by using a common data store that is able to use an external reader to read many formats. [ 89 ]
Slide 111: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Displaying Data With Grids Loading the movie database from a JSON file We're in the same boat as XML with this data format. Just changing the reader and setting up some config options will take care of everything. The JSON rows of data are expected to be in the form of an array of objects— our movies.json file will therefore contain data like this: { success:true, rows:[ { "id":"1", "title":"Office Space", "director":"Mike Judge", "released":"1999-02-19", "genre":"1", "tagline":"Work Sucks", "coverthumb":"84m.jpg", "price":"19.95", "active":"1" },{ "id":"3", "title":"Super Troopers", "director":"Jay Chandrasekhar", "released":"2002-02-15", "genre":"1", "tagline":"Altered State Police", "coverthumb":"42m.jpg", "price":"14.95", "active":"1" } //...more rows of data removed for readability...// ] } The main difference between setting up a JSON reader versus an XML reader, is that the JSON reader needs to know the name of the root element that holds our array objects (the data). So instead of specifying a record config, we need to specify a root config: var store = new Ext.data.Store({ url: 'movies.json', reader: new Ext.data.JsonReader({ root:'rows', [ 90 ]
Slide 112: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 5 id:'id' }, [ 'id', 'coverthumb', 'title', 'director', {name: 'released', type: 'date', dateFormat: 'Y-m-d'}, 'genre', 'tagline', {name: 'price', type: 'float'}, {name: 'available', type: 'bool'} ]) }); store.load(); This grid will have an identical look and the same functionality as the array and the XML grids that we created earlier. JSON is a format native to JavaScript, and will end up being the quickest format for the data store to read, which means that our grid will be displayed much faster. Loading data from a database using PHP The setup for our GridPanel stays the same. But instead of grabbing a static file with the JSON data, we can pull the data from a PHP script that will fetch the data from a database, and format it into JSON that Ext is able to read: <?php // connect to database $sql = "SELECT * FROM movies"; $arr = array(); If (!$rs = mysql_query($sql)) { Echo '{success:false}'; }else{ while($obj = mysql_fetch_object($rs)){ $arr[] = $obj; } Echo '{success:true,rows:'.json_encode($arr).'}'; } ?> [ 91 ]
Slide 113: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Displaying Data With Grids The PHP code used in these examples is meant to be the bare minimum needed to get the job done. In a production environment you would want to account for security against SQL injection attacks, other error checking, and probably user authentication—which the example code does not account for. Programming the grid Most of the code we have written so far concerns configuring the grid prior to it being displayed. Often, we will want the grid to do something in response to user input. One of the common interactions in a grid is to select or move the rows of data. Ext JS refers to this interaction and how it's handled as the "selection model". Let's see how to set one up. Working with cell and row selections Ext grids provide ways of monitoring user interaction with the grids rows, cells and columns with a thing called the selection model. The selection model is used to determine how rows, columns, or cells are selected, and how many items can be selected at a time. This allows us to create listeners for these selection events, along with giving us a way to query which rows have been selected. Some of the selection models are: • • • • CellSelectionModel: This lets the user to select a single cell from the grid RowSelectionModel: This lets the user select an entire row from the grid ColumnSelectionModel: This lets the user select an entire column from the grid CheckBoxSelectionModel: This one uses a checkbox to enable row selections Choosing a selection model is something that depends on your project's requirements. For our movie database, we will use a row selection model, which is the most commonly used type of selection model. The selection model is defined in the GridPanel config by using the sm config option. sm: new Ext.grid.RowSelectionModel({ singleSelect: true }) [ 92 ]
Slide 114: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 5 We will also pass the selection model a config that specifies single row selections only. This stops the user from selecting multiple rows at the same time. Listening to our selection model for selections Listeners for a grid can be included in many different places depending on the desired interaction. Earlier, we applied a listener to our column model because we wanted to listen for column activity. Here, we will add a listener to the selection model because we want to know when a user has selected a movie. sm: new Ext.grid.RowSelectionModel({ singleSelect: true, listeners: { rowselect: { fn: function(sm,index,record) { Ext.Msg.alert('You Selected',record.data.title); } } } }) [ 93 ]
Slide 115: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Displaying Data With Grids Selecting a row now brings up an alert dialog. Let's take a look at what is happening here: • • A listener is set for the rowselect event. This waits for a row to be selected, and then executes our function when this happens. Our function is passed a selection model, the numeric index of the row selected (starting with zero for the first row), and the data record of the row that was selected. Using the data record that our function received, we can grab the title of the movie selected and put it into a message dialog. • Manipulating the grid (and its data) with code Many functions are available for manipulating the grid and the data in the grid. These can be tied into other Ext widgets to create pretty much any functionality needed. Altering the grid at the click of a button Here, we are going to add a top toolbar, which will have a button that brings up a prompt allowing the movie title to be edited. tbar: [{ text: 'Change Title', handler: function(){ var sm = grid.getSelectionModel(); if (sm.hasSelection()){ var sel = sm.getSelected(); Ext.Msg.show({ title: 'Change Title', prompt: true, buttons: Ext.MessageBox.OKCANCEL, value: sel.data.title, fn: function(btn,text){ if (btn == 'ok'){ sel.set('title', text); } } }); } } }] [ 94 ]
Slide 116: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 5 All we are really doing here is changing the data store. The data in our database on the web server has stayed the same, and the web server has no idea whether anything has changed. It's up to us to communicate this change to the server via an AJAX request or via some other method you may prefer to use. Let's take a quick look at what's happening here: • • • sm: The selection model is retrieved from our grid sel: We used the selection model to retrieve the row that has been selected sel.data: Using the data object of the selected item, we can grab its data This basic method can be used to create many fun user interactions. Our limitation is that there are only 24 hours in a day, and sleep catches up with everyone! Advanced grid formatting Because we are in the mood to create some user-grid interactions, let us add some more buttons that do fun stuff. [ 95 ]
Slide 117: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Displaying Data With Grids Here is a button we can add to the top toolbar to allow us to hide or show a column. We will also change the text of the button based on the visibility of the column: { text: 'Hide Price', handler: function(btn){ var cm = grid.getColumnModel(); var pi = cm.getIndexById('price'); if (cm.isHidden(pi)){ cm.setHidden(pi,false); btn.setText('Hide Price'); }else{ cm.setHidden(pi,true); btn.setText('Show Price'); } btn.render(); } } We use a new handler here—getIndexById, which, as you can imagine, gets the column index, and will be a number from zero to one less than the total number of columns. This number is an indicator of where that column is in relation to the other columns. In our grid code, the column price is the fourth column, which means that the index is 3 because indexes start at zero. Paging the grid Paging requires that we have a server-side element (script) that will break up our data into pages. Let's start with that. PHP is well-suited to this, and the code is easy to understand and interpret into other languages. So we will use PHP for our example. When a paging grid is paged, it will pass start and limit parameters to the server-side script. This is typical of what's used with a database to select a subset of records. Our script can read in these parameters and use them pretty much verbatim in the database query. Here is a typical PHP script that would handle paging. We will name the file movies-paging.php. <?php // connect to database $start = ($_REQUEST['start'] != '') ? $_REQUEST['start'] : 0; $limit = ($_REQUEST['limit'] != '') ? $_REQUEST['limit'] : 3; $count_sql = "SELECT * FROM movies"; $sql = $count_sql . " LIMIT ".$start.", ".$limit; [ 96 ]
Slide 118: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 5 $arr = array(); If (!$rs = mysql_query($sql)) { Echo '{success:false}'; }else{ $rs_count = mysql_query($count_sql); $results = mysql_num_rows($rs_count); while($obj = mysql_fetch_object($rs)){ $arr[] = $obj; } Echo '{success:true,results:'.$results.', rows:'.json_encode($arr).'}'; } ?> This PHP script will take care of the server-side part of paging. So now we just need to add a paging toolbar to the grid—it's really quite simple! Earlier we had used a top toolbar to hold some buttons for messing with the grid. Now we are going to place a paging toolbar in the bottom toolbar slot (mostly because I think paging bars look dumb on the top). [ 97 ]
Slide 119: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Displaying Data With Grids The following code will add a paging toolbar: bbar: new Ext.PagingToolbar({ pageSize: 3, store: store }) And of course we need to change the url of our data store to the url of the PHP server-side paging code. A totalProperty is also required when paging data. This is the variable name that holds the total record count of rows in the database. var store = new Ext.data.Store({ url: 'movies-paged.php', reader: new Ext.data.JsonReader({ root:'rows', totalProperty: 'results', id:'id' }, [ // data column model removed for readability ]) }); Grouping Grouping grids are used to provide a visual indication that sets of rows are similar to each other. It also provides us with sorting that is confined to each group. So if we were to sort by the price column, the price would sort only within each group of items. Grouping store A special store is required, which is called...wait for it...the GroupingStore...tada! The setup is similar to a standard store. We just need to provide a few more configuration options, such as the sortInfo and the groupField. No changes to the actual data are needed because Ext JS takes care of grouping on the client side. var store = new Ext.data.GroupingStore({ url: 'movies.json', sortInfo: { field: 'genre', direction: "ASC" }, groupField: 'genre', reader: new Ext.data.JsonReader({ [ 98 ]
Slide 120: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 5 root:'rows', id:'id' }, // reader column model here //) }); We also need to add a view configuration to the grid panel. This view helps the grid to visually account for grouped data. var grid = new Ext.grid.GridPanel({ renderTo: document.body, frame:true, title: 'Movie Database', height:400, width:520, store: store, autoExpandColumn: 'title', columns: // column model goes here //, view: new Ext.grid.GroupingView() }); After making the changes needed for a grouping grid, we end up with something that looks like this: [ 99 ]
Slide 121: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Displaying Data With Grids If you now expand the context menu for the column headings, you will see a new item in the menu for Group By This Field that will allow the user to change the grouping column on the fly. Summary We have learned a lot in this chapter about presenting data in a grid. With this new-found knowledge we will be able to organize massive amounts of data into easy to understand grids. Specifically, we covered: • • • • Creating data stores and grids for display Reading XML and JSON data from a server and displaying it in a grid Rendering cells of data for a well formatted display Altering the grid based on user interaction We also discussed the intricacies of each of these elements, such as reading data locally or from a server—along with paging. We also covered formatting cells using HTML, images, and even lookups into separate data stores. Now that we've learned about standard grids, we're ready to take it to the next level, by making our grid cells editable just like a spreadsheet—which is the topic of the next chapter. [ 100 ]
Slide 122: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Editor Grids In the previous chapter we learned how to display data in a structured grid that users could manipulate. But one major limitation was that there was no way for the users to edit the data in the grid in-line. Fortunately, Ext provides an EditorGridPanel, which allows the use of form field type editing in-line—and we will learn about it in this chapter. This works much like Excel, allowing the user to click on and edit cell data immediately. In this chapter you will learn to: • • • • Present the user with editable grids that are connected to a data store Send edited data back to the server, enabling users to update server-side databases using the Ext JS editor grid Manipulate the grid from program code, and respond to events Use tricks for advanced formatting and creating more powerful editing grids But first, let's see what you can do with an editable grid. What can I do with an editable grid? The EditorGridPanel is very similar to the forms we were working with earlier. In fact, an editor grid uses the exact same form fields as our form. By using form fields to perform the grid cell editing we get to take advantage of the same functionality that a form field provides. This includes restricting input, and validating values. Combine this with the power of an Ext GridPanel, and we are left with a widget that can do pretty much whatever we want.
Slide 123: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Editor Grids All of the fields in this table can be edited in-line using form fields such as the text field, date picker, and combo box. Working with editable grids The change from a non-editable grid to an editable grid is quite a simple process to start with. The complexity comes into the picture when we start to create a process to handle edits and send that data back to the server. But once you learn how to do it, that part can be quite simple as well. Let's see how you would update the grid we created at the start of Chapter 5 to make the title, director, and tagline editable. Here's what the modified code will look like: var title_edit = new Ext.form.TextField(); var director_edit = new Ext.form.TextField({vtype: 'name'}); var tagline_edit = new Ext.form.TextField({ maxLength: 45 }); var grid = new Ext.grid.EditorGridPanel({ renderTo: document.body, frame:true, title: 'Movie Database', height:200, width:520, clickstoEdit: 1, store: store, columns: [ {header: "Title", dataIndex: 'title', [ 102 ]
Slide 124: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 6 editor: title_edit}, {header: "Director", dataIndex: 'director', editor: director_edit}, {header: "Released", dataIndex: 'released', renderer: Ext.util.Format.dateRenderer('m/d/Y')}, {header: "Genre", dataIndex: 'genre', renderer: genre_name}, {header: "Tagline", dataIndex: 'tagline', editor: tagline_edit} ] }); There are four main things that we need to do to make our grid editable. These are: • • • • The grid definition changes from being Ext.grid.GridPanel to Ext.grid. EditorGridPanel We add the clicksToEdit option to the grid config—this option is not required, but defaults to two clicks Create a form field for each column that we would like to be editable Pass the form fields into our column model via the editor config The editor can be any of the form field types that already exist in Ext JS, or a custom one of your own. We start by creating a text form field that will be used when editing the movie title. var title_edit = new Ext.form.TextField(); Then add this form field to the column model as the editor: {header: "Title", dataIndex: 'title', editor: title_edit} The next step will be to change from using the GripPanel component to using the EditorGridPanel component, and to add the clicksToEdit config: var grid = new Ext.grid.EditorGridPanel({ renderTo: document.body, frame:true, title: 'Movie Database', height:200, width:520, clickstoEdit: 1, // removed extra code for clarity }) [ 103 ]
Slide 125: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Editor Grids Making these changes has turned our static grid into an editable grid. We can click on any of the fields that we set up editors for, and edit their values. Here we see some changes have been made to the titles of a few of the movies, turning them into musicals. The editor gets activated with a single click on the cell of data; pressing Enter, the Tab key, or clicking away from the field will save the change, and pressing the Escape key will discard any changes. This works just like a form field, because, well… it is a form field. The little red tick that appears in the upper-left corner indicates that the cell is 'dirty', which we will cover in just a moment. First, let's make some more complex editable cells. Editing more cells of data For our basic editor grid, we started by making a single column editable. To set up the editor, we created a reference to the form field: var title_edit = new Ext.form.TextField(); Then we used that form field as the editor for the column: {header: "Title", dataIndex: 'title', editor: title_edit} That's the basic requirements for each field. Now let's expand upon this knowledge. Edit more field types Now we are going to create editors for the other fields. Different data types have different editor fields and can have options specific to that field's needs. [ 104 ]
Slide 126: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 6 Any form field type can be used as an editor. These are some of the standard types: • • • • • • TextField NumberField ComboBox DateField TimeField CheckBox These editors can be extended to achieve special types of editing if needed, but for now, lets start with editing the other fields we have in our grid—the release date and the genre. Editing a date value A DateField will work perfectly for editing the release date column in our grid. So let's use that. We first need to set up the editor field and specify which format to use: release_edit = new Ext.form.DateField({ format: 'm/d/Y' }); Then we apply that editor to the column, along with the renderer that we used earlier: {header: "Released", dataIndex: 'released', renderer: Ext.util.Format.dateRenderer('m/d/Y'), editor: release_edit} [ 105 ]
Slide 127: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Editor Grids This column also takes advantage of a renderer, which will co-exist with the editor. Once the editor field is activated with a single click, the renderer passes the rendering of the field to the editor and vice versa. So when we are done with editing the field, the renderer will take over formatting the field again. Edit with a ComboBox Let's set up an editor for the genres column that will provide us with a list of the valid genres to select from—sounds like a perfect scenario for a combo box. var genre_edit = new Ext.form.ComboBox({ typeAhead: true, triggerAction: 'all', mode: 'local', store: genres, displayField:'genre', valueField: 'id' }); Simply add this editor to the column model, like we did with the others: {header: "Genre", dataIndex: 'genre', renderer: genre_name, editor: genre_edit} Now we end up with an editable field that has a fixed selection of options. Reacting to a cell edit Of course, we now need to figure out how to save all of this editing that we have been doing. I am sure the end user would not be so happy if we threw away all of their changes. We can start the process of saving the changes by listening for particular edit events, and then reacting to those with our own custom handler. Before we start coding this, we need to understand a bit more about how the editor grid works. [ 106 ]
Slide 128: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 6 What's a dirty cell? A field that has been edited and has had its value changed is considered to be 'dirty' until the data store is told otherwise. This 'dirty' value has been saved to a temporary data store that contains a version of our data with all of the changes made. Our original data store stays unchanged. We can save the changes to the primary data store by calling the commit function, or we can discard the changes by calling the reject handler. These handlers can be called for the entire grid, for a single cell of data, or as the result of an event that is happening. Let's imagine e is an edit event object. We could reject a record by calling the reject handler: e.record.reject(); Alternatively, we can save our change by committing it: e.record.commit(); Reacting when an edit occurs To save our changes to the data store, we are going to listen for an edit being completed, which is accomplished by listening for the afteredit event. The listener we need is added to the grid panel: var grid = new Ext.grid.EditorGridPanel({ // more config options clipped //, title: 'Movie Database', store: store, columns: // column model clipped //, listeners: { afteredit: function(e){ if (e.field == 'director' && e.value == 'Mel Gibson'){ Ext.Msg.alert('Error','Mel Gibson movies not allowed'); e.record.reject(); }else{ e.record.commit(); } } } }); As with other listeners in Ext, the editor grid listeners are given a function to execute when the event occurs. The function for afteredit is called with a single argument: an object, which has a number of useful properties. We can use these properties to make a decision about the edit that just happened. [ 107 ]
Slide 129: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Editor Grids Property grid record field value originalValue row column Description The grid that the edit event happened in The entire record that's being edited; other column values can be retrieved using this objects 'data' property The name of the column that was edited A string containing the new value of the cell A string containing the original value of the cell The index of the row that was edited The index of the column that was edited For instance, if we wanted to make sure that movies directed by Mel Gibson never made it into our database, we could put a simple check in place for that scenario: if (e.field == 'director' && e.value == 'Mel Gibson'){ Ext.Msg.alert('Error','Mel Gibson movies not allowed'); e.record.reject(); }else{ e.record.commit(); } First, we check to see that the director field is the one being edited. Next, we make sure the new value entered for this field is not equal to Mel Gibson. If either of these is false, we commit the record back to the data store. This means that once we call the commit handler, our primary data store is updated with the new value. e.record.commit(); We also have the ability to reject the change—sending the changed value into the black hole of space, lost forever. e.record.reject(); Of course, all we have done so far is update the data that is stored in the browsers' memory. I'm sure you're just dying to be able to update a web server. We will get to that soon enough. Deleting and adding in the data store We are going to create two buttons to allow us to alter the data store—to add or remove rows of data. Let us set up a top toolbar (tbar) in the grid to house these buttons: var grid = new Ext.grid.EditorGridPanel({ // more config options clipped //, [ 108 ]
Slide 130: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 6 tbar: [{ text: 'Remove Movie' }] } Removing grid rows from the data store Let's add a remove button to the toolbar in our grid. When this button is clicked, it will prompt the user with a dialog that displays the movie title. If the Yes button is clicked, then we can remove the selected row from the data store, otherwise we will do nothing. { text: 'Remove Movie', icon: 'images/table_delete.png', cls: 'x-btn-text-icon', handler: function() { var sm = grid.getSelectionModel(); var sel = sm.getSelected(); if (sm.hasSelection()){ Ext.Msg.show({ title: 'Remove Movie', buttons: Ext.MessageBox.YESNOCANCEL, msg: 'Remove '+sel.data.title+'?', fn: function(btn){ if (btn == 'yes'){ grid.getStore().remove(sel); } } }); }; } } [ 109 ]
Slide 131: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Editor Grids Let's take a look at what is happening here. We have defined some variables that we will use to determine if there were selections made, and what the selections were: • • • sm: The selection model is retrieved from our grid sel: We used the selection model to retrieve the row that has been selected grid.getStore().remove(sel): Passing the data stores remove function, a row will remove that row from the store and update the grid It's as simple as that. The local data store that resides in the browser's memory has been updated. But what good is deleting if you can't add anything—just be patient, grasshopper! Adding a row to the grid To add a row we have a bit of a twist. We need to have a definition of what the data looks like in order to be able to create a new row—just like it was created for the data reader. var ds_model = Ext.data.Record.create([ 'id', 'coverthumb', 'title', 'director', {name: 'released', type: 'date', dateFormat: 'Y-m-d'}, 'genre', 'tagline', {name: 'price', type: 'float'}, {name: 'available', type: 'bool'} ]); Once we have this definition of the data, we can insert a new row fairly easily. A button can be added to the same top toolbar that will be used to insert the row: { text: 'Add Movie', icon: 'images/table_add.png', cls: 'x-btn-text-icon', handler: function() { grid.getStore().insert( 0, new ds_model({ title:'New Movie', director:'', genre:0, tagline:'' [ 110 ]
Slide 132: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 6 }) ); grid.startEditing(0,0); } } The first argument to the insert function is the point at which to insert the record. I have chosen zero, so the record will be inserted at the very top. If we wanted to insert the row at the end we could simply retrieve the row count for our data store. Because the row index starts at zero, and the count at one, incrementing the count is not necessary because the row count will always be one greater than the last item in the index. grid.getStore().insert( grid.getStore().getCount(), new ds_model({ title:'New Movie', director:'', genre:0, tagline:'' }) ); grid.startEditing(grid.getStore().getCount()-1,0); Now we are back to inserting a row. The second argument is the new record definition, which can be passed with some default values. new ds_model({ title:'New Movie', director:'', genre:0, tagline:'' }) [ 111 ]
Slide 133: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Editor Grids After inserting the new row, we call a function that will activate a cells editor. This function just needs a row and column index number to activate the editor for that cell. grid.startEditing(0,0); This gives our user the ability to start typing the movie title directly after clicking the Add Movie button. Saving edited data to the server Everything we have done so far is related to updating the local data store residing in the memory of the web browser. More often that not, we will want to save our data back to the server to update a database, file system, or something along those lines. This section will cover some of the more common requirements of grids used in web applications to update server-side information. • • • Updating a record Creating a new record Deleting a record Sending updates back to the server Earlier, we had set up a listener for the afteredit event. We will be using this afteredit event to send changes back to the server on a cell-by-cell basis. [ 112 ]
Slide 134: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 6 To update the database with cell-by-cell changes, we need to know three things: • • • field: What field has changed Value: What the new value of the field is record.id: Which row from the database the field belongs to This gives us enough information to be able to make a distinct update to a database. We communicate with the server (using AJAX) by calling the connection request method. listeners: { afteredit: function(e){ var conn = new Ext.data.Connection(); conn.request({ url: 'movie-update.php', params: { action: 'update', id: e.record.id, field: e.field, value: e.value }, success: function(resp,opt) { e.commit(); }, failure: function(resp,opt) { e.reject(); } }); } } This will send a request to the movie-update.php script with four parameters in the form of post headers. The params that we pass as a config object into the data connection are all sent through the headers to our script on the server side. The movie-update.php script should be coded to recognize the 'update' action and then read in the id, field, and value data and then proceed to update the file system or database, or whatever else we need to make it happen. [ 113 ]
Slide 135: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Editor Grids This is what's available to us when using the afteredit event: Option grid record field value originalValue row column Description Reference to the current grid Object with data from the row being edited Name of the field being edited New value entered into the field Original value of the field Index of the row being edited—this will help in finding it again Index of the column being edited Deleting data from the server When we want to delete data from the server, we can handle it in very much the same way as an update—by making a call to a script on the server, and telling it what we want done. For the delete trigger, we will use another button in the grids toolbar. { text: 'Remove Movie', icon: 'images/table_delete.png', cls: 'x-btn-text-icon', handler: function() { var sm = grid.getSelectionModel(); var sel = sm.getSelected(); if (sm.hasSelection()){ Ext.Msg.show({ title: 'Remove Movie', buttons: Ext.MessageBox.YESNOCANCEL, msg: 'Remove '+sel.data.title+'?', fn: function(btn){ if (btn == 'yes'){ var conn = new Ext.data.Connection(); conn.request({ url: 'movie-update.php', params: { action: 'delete', id: e.record.id }, success: function(resp,opt) { grid.getStore().remove(sel); [ 114 ]
Slide 136: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 6 }, failure: function(resp,opt) { Ext.Msg.alert('Error', 'Unable to delete movie'); } }); } } }); }; } } Just as with edit, we are going to make a request to the server to have the row deleted. The movie-update.php script would see that the action is delete and execute the appropriate action. Saving new rows to the server Here we are going to add another button that will add a new row. It sends the request to the server with the appropriate parameters and reads the insert id from the server's response. Using this insert id, we are able to add the row to our data store with the unique identifier generated on the server side for that row. { text: 'Add Movie', icon: 'images/table_add.png', cls: 'x-btn-text-icon', handler: function() { var conn = new Ext.data.Connection(); conn.request({ url: 'movies-update.php', params: { action: 'insert', title:'New Movie' }, success: function(resp,opt) { var insert_id = Ext.util.JSON.decode( resp.responseText ).insert_id; grid.getStore().insert(0, new ds_model({ id:insert_id, title:'New Movie', director:'', genre:0, tagline:'' [ 115 ]
Slide 137: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Editor Grids }) ); grid.startEditing(0,0); }, failure: function(resp,opt) { Ext.Msg.alert('Error','Unable to add movie'); } }); } } Much like editing and deleting, we are going to send a request to the server to have a new row inserted. This time, we are actually going to take a look at the response to get the insert id (the unique identifier for that row) to pass back to our grid so that when we start editing that row, it will be easy to save our changes. success: function(resp,opt) { var insert_id = Ext.util.JSON.decode( resp.responseText ).insert_id; grid.getStore().insert(0, new ds_model({ id:insert_id, title:'New Movie', director:'', genre:0, tagline:'' }) ); grid.startEditing(0,0); } Our success handler function has a couple of arguments, the first is the response object, which contains the response text from our movie-update.php script. Because that response is in a JSON format, we're going to decode it into a usable object and grab the insert id value. var insert_id = Ext.util.JSON.decode( resp.responseText ).insert_id; When we insert this row into our data store, we can use the insert id that was retrieved. [ 116 ]
Slide 138: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 6 Summary The Ext JS grid functionality is one of the most advanced portions of the framework. With the backing of the Ext.data package, the grid can pull information from a remote server in an integrated manner—this support is built into the grid class. Thanks to the array of configuration options available, we can present this data easily in a variety of forms, and set it up for manipulation by our users. In this chapter, we've seen how the data support provided by the grid offers an approach to data manipulating that will be familiar to many developers. The amend-and commit approach allows fine-grained control over the data that is sent to the server when used with a validation policy, along with the ability to reject changes. As well as amending the starting data, we've seen how the grid provides functionality to add and remove rows of data. We've also shown how standard Ext JS form fields such as the ComboBox can be integrated to provide a user interface on top of this functionality. With such strong support for data entry, the grid package provides a very powerful tool for application builders. In the next chapter, we'll demonstrate how components such as the grid can be integrated with other parts of an application screen by using the extensive layout functionality provided by the Ext JS framework. [ 117 ]
Slide 139: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098
Slide 140: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Layouts A layout turns your forms, grids, and other widgets into a true web application. The most widely-used layout styles can be found in operating systems such as Microsoft's Windows, which uses border layouts, resizable regions, accordions, tabs, and just about everything else you can think of. To keep looks consistent between browsers, and to provide common user interface features, Ext JS has a powerful layout management system. The sections are manageable, and can be moved or hidden, and they can appear at the click of a k button, right when and where you need them to. In this chapter you will learn to: • • • • Lay out an application style screen Create tabbed sections Manage Ext widgets within a layout Learn advanced and nested layouts What are layouts, regions, and viewports? Ext uses Panels, which are the basis of most layouts. We have used some of these, such as FormPanel and GridPanel, already. A viewport is a special panel-like component that encloses the entire layout, fitting it into the whole visible area of our browser. For our first example, we are going to use a viewport with a border layout that will encapsulate many panels.
Slide 141: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Layouts A viewport has regions that are laid out in the same way as a compass, with North, South, East and West regions—the Center region represents what's left over in the middle. These directions tell the panels where to align themselves within the viewport and, if you use them, where the resizable borders are to be placed: North West Center East South The example we're creating will look like the following image, and combines many of the previous examples we have created: [ 120 ]
Slide 142: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 7 This layout is what's called a 'border' layout, which means that each region is separated by a somewhat three dimensional border bar that can be dragged to resize the regions. This example contains four panel regions: • • • • North: The toolbar West: A form Center: Grid in a tab panel East: A plain panel containing text Note that there is no 'South' panel in this example—not every region needs to be used in every layout. Our first layout Before we create our layout that uses only four regions let's go ahead and create a layout that utilizes all the regions, and then remove the South panel. We are going to create all of the regions as 'panels', which can be thought of as blank canvases to which we will add text, HTML, images, or even Ext JS widgets. var viewport = new Ext.Viewport({ layout: 'border', renderTo: Ext.getBody(), items: [{ region: 'north', xtype: 'panel', html: 'North' },{ region: 'west', xtype: 'panel', split: true, width: 200, html: 'West' },{ region: 'center', xtype: 'panel', html: 'Center' },{ region: 'east', xtype: 'panel', split: true, width: 200, html: 'East' },{ region: 'south', xtype: 'panel', html: 'South' }] }); [ 121 ]
Slide 143: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Layouts Each region is defined as one of the four compass directions—East, West, North, and South. The remainder in the middle is called the center region, which will expand to fill all of the remaining space. Just to take up some blank space in each region and to give a visual indicator as to where the panels are, we defined an 'HTML' config that has just text. (This could also contain complex HTML if needed, but there are better ways to set the contents of panels which we will learn about soon.) Ext JS provides an easy, cross-browser compatible, speedy way to get a reference to the body element, by using Ext.getBody(). If everything works out ok, you should see a browser that looks like this: Now we have a layout with all five regions defined. These regions can have other text widgets added into them, seamlessly, by using the xtype config. Alternatively they can be divided up separately into more nested regions—for instance, the center could be split horizontally to have its own South section. A 'Center' region must always be defined. If one is not defined, the layout will produce errors and appear as a jumbled set of boxes in the browser. Splitting the regions The dividers are set up for each panel by setting the split flag—the positioning of the dividers is determined automatically based on the region the panel is in. split: true For this page, we have set the West and East regions as 'split' regions. This, by default, makes the border into a resizing element for the user to change the size of that panel. [ 122 ]
Slide 144: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 7 I want options Typically, when a split is used, it's combined with a few other options that make the section more useful, such as width, minSize, and collapseMode. Here are some of the more commonly-used options: Option split collapsible Value true/false true/false Description Boolean value that places a resizable bar between the sections Boolean value that adds a button to the title bar which lets the user collapse the region with a single click When set to 'mini', this adds a smaller collapse button that's located on the divider bar, in addition to the larger collapse button on title bar; the panel also collapses into a smaller space Title string placed in the title bar CSS styles applied to the body element of the panel. The smallest size that the user can drag this panel to The largest size that the user can drag this panel to Can be used to space the panel away from the edges or away from other panels; spacing is applied outside of the body of the panel Same idea as margins, but applies only when the panel is collapsed collapseMode title bodyStyle minSize maxSize margins Only option is mini mode, or undefined for normal mode String CSS Pixels, ie: 200 Pixels, ie: 250 In pixels: top, right, bottom, left, i.e.,: 3 0 3 3 In pixels: top, right, bottom, left, i.e.,: 3 0 3 3 cmargins Let's add a couple of these options to our west panel: { region: 'west', xtype: 'panel', split: true, collapsible: true, collapseMode: 'mini', title: 'Some Info', bodyStyle:'padding:5px;', width: 200, minSize: 200, html: 'West' } [ 123 ]
Slide 145: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Layouts Adding these config options to our west panel would give us the following look: Normal/Expanded Collapsed Expanding and collapsing a panel that does not have a width specified can produce rendering problems. Therefore, it's best to specify a width for panels—of course this is not needed for the center, as this panel automatically fills the remaining space. Tab panels With Ext JS, tab panels are also referred to as a "card" layout because they work much like a deck of cards where each card is layered directly above or below the others and can be moved to the top of the deck, to be visible. We also get pretty much the same functionality in our tab panel as a regular panel, including a title, toolbars, and all the other usual suspects (excluding tools). Adding a tab panel If the Ext JS component is a panel type component, for instance GridPanel and , FormPanel, then we can add it directly to the layout using its xtype. Let's start by creating a tabPanel: { region: 'center', xtype: 'tabpanel', items: [{ title: 'Movie Grid', html: 'Center' }] } [ 124 ]
Slide 146: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 7 The items config is an array of objects that defines each of the tabs contained in this tabpanel. The title is the only option that's actually needed to give us a tab, and right now html is just being used as a placeholder, to give our empty tab some content. We will also need to add an activeTab config that is set to zero to our tab panel. This is the index of the tabs in the panel left to right starting with zero and counting up for each tab. This tells the tab panel at position zero to make itself active by default, otherwise, we would have no tabs displayed, resulting in a blank section until the user clicked a tab. { region: 'center', xtype: 'tabpanel', activeTab: 0, items: [{ title: 'Movie Grid', html: 'Center' }] } If we take a look at this in a browser, we should see a tab panel in the center section of our layout. Adding more tabs is as easy as adding more items into the items array. Each tab item is basically its own panel, which is shown or hidden, based on the tab title that has been clicked on the tab panel. { region: 'center', xtype: 'tabpanel', activeTab: 0, items: [{ title: 'Movie Grid', [ 125 ]
Slide 147: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Layouts html: 'Center' },{ title: 'Movie Descriptions', html: 'Movie Info' }] } Both the Movie Grid and Movie Descriptions tabs are just plain panels right now. So let's add some more configuration options and widgets to them. Widgets everywhere Earlier, I mentioned that any type of panel widget could be added directly to a layout, just as we had done with the tabs. Let's explore this by adding another widget to our layout—the grid. Adding a grid into the tabpanel As we now have these tabs as part of our layout, let's start by adding a grid panel to one of the tabs. Adding the xtype config option to the grid config code you created in Chapter 5, will produce a grid that fills one entire tab: { region: 'center', xtype: 'tabpanel', activeTab: 0, items: [{ title: 'Movie Grid', xtype: 'gridpanel', store: store, autoExpandColumn: 'title', columns: // add column model //, view: // add grid view spec // },{ title: 'Movie Descriptions', html: 'Movie Info' }] } [ 126 ]
Slide 148: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 7 xtypes offer a quick way to instantiate a new component with minimal typing. This is sometimes referred to as 'lazy rendering' because the components sit around waiting to be displayed before they actually execute any code. This method can help conserve memory in your web application. As we are adding this grid to a tab—which is essentially just a panel—there are some things that we no longer need (like the renderTo option, width, height, and a frame). The size, title, and border for the grid are now handled by our tab panel. Now we should have a layout that looks like this: [ 127 ]
Slide 149: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Layouts Accordions The accordion is a very useful layout that works somewhat like a tab panel, where we have multiple sections occupying the same space, with only one showing at a time. This type of layout is commonly used when we're lacking the horizontal space needed for a tab panel, but instead have more vertical space available. When one of the accordion panels is expanded, the others will collapse. Expanding and collapsing the panels can be done either by clicking the panel's title bar or by clicking the plus/ minus icons along the rightmost side of the panel. Nesting an accordion layout in a tab We can nest a layout within a panel to create a more complex layout. For this example, we will nest an accordion panel within one of our tabs. By setting the layout to 'accordion' and adding three items, we will end up with three panels in our accordion. { title: 'Movie Descriptions', layout: 'accordion', items: [{ title: 'Office Space', autoLoad: 'html/1.txt' },{ title: 'Super Troopers', autoLoad: 'html/3.txt' },{ title: 'American Beauty', autoLoad: 'html/4.txt' }] } This gives us a tab that has within it three accordion panels, which will load text files into their body sections. Note that the config on this is very similar to a tab panel— the consistency between widgets in Ext JS makes it easy to set up different types of widgets without having to look at the API reference for each one. [ 128 ]
Slide 150: This material is copyright and is licensed for the sole use by Roman Heinrich on 25th December 2008 Am Hilligenbusch 47, , Paderborn, NRW, 33098 Chapter 7 Now we should have a layout that looks like, this when we switch to the Movie Descriptions tab: Each panel now has a description of the movie, which was loaded from a text file on the web server. Let's take a closer look at that. autoLoad: 'html/1.txt' This loads the file from the URL specified into the body section of the panel. The file loaded can contain any type of HTML, which will show up just as if it were in a browser by itself. As this is done via AJAX, if you're running the examples from your file system instead of a local web server they will not load. Note that the JavaScript contained within the loaded content will not be executed and any HTML will be ignored. Placing a toolbar in your layout Next, let's add a toolbar to the North section of our layout. We can use the toolbar for menus, buttons, and a couple of form fields, or maybe just a blinking marquee with our name scrolling across it. We can change these easily later. Let's take our toolbar items we used in the example code in Chapter 4—Buttons, Menus, and Toolbar—and add them to this toolbar. We should also copy over the Movies class we created in the toolbar chapter, if we want the buttons to work. [ 129 ]

   
Time on Slide Time on Plick
Slides per Visit Slide Views Views by Location