| Summary: A general overview of the Ext library and an introduction to using Ext to complete some common application tasks. New users should begin here. |
| Author: Brian Moeskau |
| Published: February 27, 2007 |
| Ext Version: 1.1 |
Languages: English Dutch Spanish Chinese Russian Portuguese French Korean
|
NOTE: This tutorial is specific to the 1.x branch of Ext. If you are using 2.0, please see the revised 2.0 version of this tutorial.
Anyone new to using the Ext library or trying to learn more about it has come to the right place. This tutorial will walk through Ext basic concepts and how to get a dynamic page up and running quickly. It is assumed that the reader has some Javascript experience and a basic understanding of the HTML document object model (DOM).
Download ExtIf you haven't done so already, you'll first want to download the most current Ext release which can always be found here: http://extjs.com/download.
There are several different options for what you can download, but you'll probably want to start with the most current stable production version. Once you download and unzip the file, a good place to start exploring would be the examples directory.
Let's Get Started| Download Example File |
We're going to walk through some of the most common tasks that people have to accomplish in Javascript and how to perform them using Ext. If you'd like to experiment as you go, you should download the starter files in IntroToExt.zip which we will use to build up a page of working Ext code.
Now you're ready to open ExtStart.js in your favorite IDE or text editor and take a look at it:
Ext.onReady(function() { alert("Congratulations! You have Ext configured correctly!"); });
Ext.onReady is probably the first method that you'll use on every page. This method is automatically called once the DOM is fully loaded, guaranteeing that any page elements that you may want to reference will be available when the script runs. You can go ahead and delete the alert() line now so that we can start adding some real code that actually does something useful!
Element: The Heart of ExtAlmost everything you do in Javascript will at some point involve referencing specific elements on your page so that you can do interesting things with them. Using traditional Javascript, selecting a DOM node by ID is done like this:
var myDiv = document.getElementById('myDiv');
This works just fine, but the object that is returned (a DOM node) doesn't offer much in the way of power or convenience. In order to do anything useful with that node, you are left still writing a lot of custom plumbing code yourself. Plus it is your responsibility to handle all of the differences in how the node can be used from browser to browser, which can be daunting.
Enter the Ext.Element object. The Element really is the heart of Ext as most of what you'll do involves getting access to Elements and performing actions on them. The Element API is fundamental to the entire Ext library, and if you spend the time to really learn only one class in Ext well, Element should be it!
The corresponding code to get an Ext Element by ID looks like this (the starter page ExtStart.html contains a div with the id "myDiv," so go ahead and add this code to ExtStart.js):
Ext.onReady(function() { var myDiv = Ext.get('myDiv'); });
So we are getting back an Element object now—what's so interesting about that?
This means that you can do all kinds of useful stuff with very minimal code. Here are just a few simple examples (see the Element API documentation for the complete list of everything that you can do). Go ahead and try adding some of these to ExtStart.js after the previous line where we got the 'myDiv' Element:
myDiv.highlight(); // The element's background will highlight to yellow then fade back myDiv.addClass('red'); // Add a custom CSS class (defined in ExtStart.css) myDiv.center(); // Center the element in the viewport myDiv.setOpacity(.25); // Make the element partially-transparent
Selecting DOM NodesOften it is either impractical or impossible to select DOM nodes by ID. Maybe the ID is not set, or you don't know it, or there are too many elements to practically reference directly by ID. Sometimes you may want to select nodes based on something other than ID, like an attribute or a CSS classname. For these reasons, Ext ships with an extremely powerful DOM selector library called DomQuery.
DomQuery can be used as a standalone library, but more often when using Ext, you'll use it in the context of selecting Elements so that you can then act on them via the Element interface. Luckily, the Element object itself supports querying via the Element.select method, which internally uses DomQuery to select elements. As a simple example of how you might use this, the ExtStart.html file contains several paragraph (<p>) tags, none of which have ids. If you wanted to easily select every paragraph and perform an action on all of them at once, you could do something like this:
// Highlights every paragraph Ext.select('p').highlight();
This example demonstrates a very handy aspect of Element.select—it returns a CompositeElement, which provides access to every underlying Element via the Element interface. This allows you to easily act on every Element instance returned by Element.select without looping and touching each one individually.
DomQuery supports a wide array of selection options, including most of the W3C CSS3 DOM selectors, basic XPath, HTML attributes and a lot more. Please see the DomQuery API documentation for complete details on this powerful library.
Responding to EventsSo far in our examples, all of the code we've written has been directly inside the onReady function, which means that it always executes immediately after the page loads. This doesn't give us much control—you will most commonly want your code to execute in response to specific actions or events that you choose to handle. To do this, you define event handlers that can respond to events using functions that you assign.
Let's start off with a simple example. Open up ExtStart.js and edit it so that your code looks like this:
Ext.onReady(function() { Ext.get('myButton').on('click', function(){ alert("You clicked the button"); }); });
The code still executes when the page loads, but there's an important difference. The function containing the alert() is defined, but is not actually executed immediately—it is assigned as the "handler" of the button click event. Spelled out in plain English, this code might read: "Get a reference to the Element with id 'myButton' and assign a function to be called anytime someone clicks on the Element."
Not surprisingly, Element.select allows you to do the same thing, but with an entire group of Elements at once. For example, to show our message when any paragraph in our test page is clicked, we could do this:
Ext.onReady(function() { Ext.select('p').on('click', function() { alert("You clicked a paragraph"); }); });
In these two examples, the event handling function is simply declared inline, without giving it a function name. The term for this type of function is an "anonymous function" since it is declared without ever being named. You can also assign an event to be handled by a named function, which is especially useful if you want to reuse the function and have it handle multiple events. For example, this code is functionally equivalent to the previous example:
Ext.onReady(function() { var paragraphClicked = function() { alert("You clicked a paragraph"); } Ext.select('p').on('click', paragraphClicked); });
So far we have looked at performing a generic action when our event is raised, but how do we actually know which specific Element raised the event so that we can perform some action on it? It turns out to be pretty easy—the Element.on method passes three extremely useful parameters to the event handling function (we're only going to look at the first one here, but you should explore the API documentation to learn more about event handling details). In our previous examples our handling function was ignoring these parameters, but with one simple change, we can provide an additional level of functionality. The first, and most important, parameter is the event that occurred. This is actually an Ext event object, which is both normalized across browsers and provides more information than the standard browser event. For example, the event's target DOM node can be retrieved with this simple addition:
Ext.onReady(function() { var paragraphClicked = function(e) { Ext.get(e.target).highlight(); } Ext.select('p').on('click', paragraphClicked); });
Note that target is a DOM node, so we first retrieve the corresponding Element, then perform whatever action we want on it. In this case, we are visually highlighting the paragraph.
Using WidgetsIn addition to the core javascript library that we've been discussing, Ext also includes one of the richest sets of Javascript UI widgets available today. There are far too many to cover in this introduction, but let's take a look at a couple of the widgets that people use most commonly and how easy they are to work with.
MessageBoxRather than a boring "Hello World" message box, let's add a little twist. We already have code that we wrote in the previous section that highlights each paragraph when you click on it. Let's modify that code to also show the text of the paragraph that was clicked in a message box. In the paragraphClicked function above, replace the line:
Ext.get(e.target).highlight();
...with this code:
var paragraph = Ext.get(e.target); paragraph.highlight(); Ext.MessageBox.show({ title: 'Paragraph Clicked', msg: paragraph.dom.innerHTML, width:400, buttons: Ext.MessageBox.OK, animEl: paragraph });
There are a couple of new concepts being shown here that are worth discussing. In the first line, we are now creating a local variable named paragraph that will hold a reference to the Element representing the DOM node that was clicked (in this case we know it will always be a paragraph since our click event is only associated with <p> tags). Why are we doing this? Well, looking ahead for a moment, we will need a reference to the Element to highlight it, and we'll also use the same Element for some of the MessageBox parameters. In general, it is bad practice to make the same function call multiple times to retrieve the same value or object reference, so by assigning it to a local variable and reusing the variable, we are being good object-oriented developers!
Now, on to the MessageBox call, which demonstrates the other new concept for us to discuss. At first glance, this may look simply like a list of parameters being passed to a method, but if you look closely, there is a very specific syntax. What is actually being passed to MessageBox.show() in this case is only one parameter: an object literal that contains a set of properties and values. In Javascript, an object literal is a dynamic, generic object that is created anytime you use the { and } characters surrounding a list of name/value properties, and the format for those properties is [property name] : [property value]. You'll see this pattern used extensively throughout Ext, so you should learn it well!
Why use an object literal? The main reason is flexibility. New properties can be added or removed from the object literal at any time, or defined in any order, while the method signature (the number and types of parameters expected by a method) never has to change. It also makes it far more convenient from the end developer's perspective when using methods with many optional parameters (as in the case of MessageBox.show). For example, let's say that a fictional method foo.action has four optional parameters, but you only need to pass one of them. In this case, your code might look like this: foo.action(null, null, null, 'hello'). However, if that method instead took an object literal, the code would look like this: foo.action({ param4: 'hello' }). Much easier to use, much more readable.
GridThe grid is one of the most popular widgets in Ext, and usually the first one that people want to see, so let's take a look at how easy it is to get a basic grid up and running. Replace any existing code you have in ExtStart.js so that it looks like this:
Ext.onReady(function() { var myData = [ ['Apple',29.89,0.24,0.81,'9/1 12:00am'], ['Ext',83.81,0.28,0.34,'9/12 12:00am'], ['Google',71.72,0.02,0.03,'10/1 12:00am'], ['Microsoft',52.55,0.01,0.02,'7/4 12:00am'], ['Yahoo!',29.01,0.42,1.47,'5/22 12:00am'] ]; var ds = new Ext.data.Store({ proxy: new Ext.data.MemoryProxy(myData), reader: new Ext.data.ArrayReader({id: 0}, [ {name: 'company'}, {name: 'price', type: 'float'}, {name: 'change', type: 'float'}, {name: 'pctChange', type: 'float'}, {name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'} ]) }); ds.load(); var colModel = new Ext.grid.ColumnModel([ {header: "Company", width: 120, sortable: true, dataIndex: 'company'}, {header: "Price", width: 90, sortable: true, dataIndex: 'price'}, {header: "Change", width: 90, sortable: true, dataIndex: 'change'}, {header: "% Change", width: 90, sortable: true, dataIndex: 'pctChange'}, {header: "Last Updated", width: 120, sortable: true, renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'lastChange'} ]); var grid = new Ext.grid.Grid('grid-example', {ds: ds, cm: colModel}); grid.render(); grid.getSelectionModel().selectFirstRow(); Ext.get('grid-example').show(); });
Note: from the new version Ext 2.0, a new class Ext.grid.GridPanel replaces the old one of Ext.grid.Grid. if you want to successfully run through this example in Ext 2.0+, you may want to replace the line of var grid = new Ext.grid.Grid(...); in above code with the line as below:
var grid = new Ext.grid.GridPanel({el: 'grid-example', ds: ds, cm: colModel});
While this looks like a lot, it is really only seven lines of code in total!
How easy was that? If all went well, you should end up with something that looks close to this:
Of course, there will probably be some details about this code that you may not fully understand at this point (like what the heck is a MemoryProxy?). The point of this example is to show how it's possible to create an extremely rich, visually-complex user interface component with very few lines of code—learning the details will be left as an exercise for the reader. There are many resources to help you with learning the grid, including the interactive grid demos and the grid API documentation.
And Many More...We've only seen the tip of the iceberg here. There are literally dozens of UI widgets to choose from in Ext, including automatic page layouts, tabs, menus, toolbars, dialogs, a tree view and many more. Please explore the examples section of the API documentation for a glimpse of everything that's available.
Using AjaxOnce you have your page created and you know how to interact with it through Javascript, you'll probably want to know how to get data to and from a remote server, most commonly to load and save data from a database on the server. Doing this asynchronously via Javascript without reloading the page is known commonly as Ajax, and Ext has excellent Ajax support built right in. For example, a common goal is to handle a user interaction, post something to the server asynchronously, then update an element of the UI in response to the action. Here's an example of a very simple HTML form containing a text input field, a button, and a div used to display a message (Note: you can add this code to ExtStart.html if you'd like to follow along, but you'll have to have access to a web server in order to run the server code below):
<div id="msg"></div> Name: <input type="text" id="name" /><br /> <input type="button" id="okButton" value="OK" />
Next, we'll add the Javascript required to get our data and post it to a server-based process (replace any existing code in ExtStart.js with this):
Ext.onReady(function(){ Ext.get('okButton').on('click', function(){ var msg = Ext.get('msg'); msg.load({ url: [server url], // <-- replace with your url params: 'name=' + Ext.get('name').dom.value, text: 'Updating...' }); msg.show(); }); });
(Note: when you check this example, open the page requesting it to the web server, that is, using http:// and not file:// in the URL.)
Hopefully the general pattern is starting to look familiar by now! The code is wrapping the okButton input with an Element object and attaching an anonymous function that will handle the event if anyone clicks on the button. Inside the click handler, we're using a special class built into Ext called the UpdateManager—this class makes sending an Ajax request, receiving a response and updating another Element extremely trivial. The UpdateManager can be used directly, or as we're doing here, it can be accessed via the Element that we want to update (in this case the 'msg' div) using the Element.load method. When Element.load is used, the server's response automatically replaces the innerHTML of the Element. Simply pass it the url to the server-based process that will handle the request, the querystring parameters to process (in this case passing in the value of the 'name' field) and the text to display in the Element's innerHTML while the request is being processed. Show the msg div (since it starts hidden by default) and that's it! Of course, as with most things in Ext, there are many more UpdateManager options supported, as well as different ways to process Ajax requests in different situations, but this shows how easy it is to get a basic example up and running.
The last piece of the Ajax puzzle is the process on the web server that actually handles the request and returns a response to the page. This process could be a server page, a servlet, an HTTP handler, a web service, even a Perl or CGI script—just about anything that can reside on a web server and process HTTP requests. Unfortunately, because of this variety there is no way to give a standard example that would cover all possibilities. Here are some examples in a few common languages to hopefully get you started (this code simply echoes whatever was passed from the 'name' field back to the client with 'From Server: ' added at the beginning, and that gets written to the 'msg' div):
Djangofrom django.http import HttpResponse def ajax_request(request): return HttpResponse('From Server: %s' % request.POST.get('name', 'nada'))
PHP<?php if(isset($_POST['name'])) { echo 'From Server: '.$_POST['name']; } ?>
Perl#!/usr/bin/perl use strict; use warnings; use CGI; my $Query = new CGI; print $Query->header(); print "Hello from : ".$Query->param('name'); exit;
ASP.Netprotected void Page_Load(object sender, EventArgs e) { if (Request.Form["name"] != null) { Response.Write("From Server: " + Request.Form["name"]); Response.End(); } }
ColdFusion<cfif StructKeyExists(form, "name")> <cfoutput>From Server: #form.name#</cfoutput> </cfif>
JSPFrom Server: ${param.name}
The real challenges when dealing with Ajax processing involve all of the plumbing code required to properly process and format real structured data on the server. There are several formats to choose from that people use commonly (most often either JSON or XML). There are also many language-specific libraries available to deal with Ajax processing that can work well with Ext, as Ext is language-neutral with regard to the server. As long as the result is sent to the page in the proper data format, Ext does not care what happens on the server!
What's Next?Now that you've had a small taste of what Ext is and what it has to offer, there are many resources available to help you really dive into the next level: