1.9. The Ext Namespace

The Ext namespace is chock-full of goodness, to put it mildly. As has been the case previously, it is not my intention to cover every single nook and cranny of it. My goal is to give you a solid overview of what's there, highlighting areas in more detail where I feel is warranted. So, without further ado, let's get to it!

1.9.1. Ext.Ajax

Ajax is, by most reckonings, the primary enabler of the whole RIA movement we are in the midst of. As such, you wouldn't expect any modern JavaScript library to not support it, and Ext JS is no exception. It provides a number of useful methods that allow you to fire asynchronous requests to a server. One of the simplest forms is this:

Ext.Ajax.request({
  url : "xxx", method : "post"
  params : { firstName : "Paul", lastName : "Newman" },
  headers : { fakeHeader : "someValue" }, disableCaching : true,
  success : function(opt, suc, res) {
    if (suc) {
      alert("The response was successful and was: " + res);
    }
  },
  failure : function(res, opt) {
    alert("Ajax failed: " + res);
  }
});

Here you can see the simple Ext.Ajax.request() method in action. It has a number of arguments that it accepts. The url argument tells the method what URL to request (xxx is obviously just a placeholder). The method argument, which defaults to GET but which I've overridden as POST here, specifies the HTTP method that will be used. The params argument is an object that includes extra parameters to include with the request. The disableCaching argument tells the method whether you want to ensure POST requests are never cached, which is what true indicates. This appends a dynamic parameter onto the request to ensure a unique URL is requested no matter what. The success and failure arguments define callback functions to be executed when the request succeeds, or if it fails (communication failures, for instance). Each is passed the options (the opt argument) that were used to make the call, and the response (the res argument) that came back from the server. The success function also gets a Boolean argument (suc) that indicates whether the request succeeded. In addition, you can pass a form argument that names a form on the page from which parameters will be generated. There are also the xmlData and the jsonData arguments, which provide the method with an XML document or a JSON object, respectively, from which to generate parameters.

When you call this method, it returns a Number that is the transaction ID for the request. This is useful because you can then call the Ext.Ajax.abort() method, passing that transaction ID to it, to cancel the request if it is still in flight. Related to this is the Ext.Ajax.isLoading() method, which similarly accepts the transaction ID and tells you if the request is still outstanding.

As you saw, the form argument lets you serialize a form to generate parameters for the request. If you need to serialize a form without making an Ajax request, you can use the Ext.Ajax.serializeForm() method, which takes in the name of the form (or a reference to the form node in the DOM) and returns to you a URL-encoded string of parameters generated from it.

There are also a number of useful properties that you can set on the Ext.Ajax class. For example, the autoAbort property, when true, will cause any new request to abort any already in progress. The disableCaching property allows you to globally set whether all Ajax requests will include that cache-busting parameter that ensures unique URLs for every request. The method property allows you to set the default method (GET or POST) for all Ajax requests. The timeout property lets you tell Ext.Ajax how long it should wait for a request to return before it assumes it timed out (the default is 30,000, or 30 seconds).

In addition to all this, the Ext.Ajax class uses an event-driven model that lets you handle certain events globally. For example:

Ext.Ajax.on('beforerequest', function() { alert("About to do Ajax"); });

This hooks an event listener to the specified event and will cause an alert() pop-up to open before every Ajax request by calling the function passed as the second argument. The other events you can handle are requestcomplete, whenever a response comes back from the server, and requestexception, which occurs any time an HTTP error occurs.

You can also use the Ext.Ajax.hasListener() method to determine if there is currently a listener for a given event (pass the name of the event you want to check as the argument to it). You can use the Ext.Ajax.removeListener() to stop handling a given event (or use the Ext.Ajax.purgeListeners() to stop handling all events in one statement). There is an Ext.Ajax.suspendEvents() to temporarily stop handling all events, and there is even an Ext.Ajax.fireEvents() method that lets you fire a specific event without firing an Ajax request (pass it the name of the event to fire as the first argument and an object as the second that contains the parameters to pass to the listener for the event).

The Ext.Ajax class is an especially clean and simple, and yet powerful, Ajax implementation. It is very robust and yet extremely easy to use, essentially boiling down to a single method!

1.9.2. Ext.DomHelper

The Ext.DomHelper class is a handy utility class that allows you to easily create fragments of HTML and insert them into the DOM. If you've written code to work with the DOM methods, then you'll quickly realize how cool this class is (otherwise you'll just have to take my word for it!). Let's look at the complete source code for the example Ext_DomHelper.htm, shown in Listing 1-1.

Example 1.1. The Ext_DomHelper.htm Example
<html>
  <head>
    <title>Chapter 1 - Ext.util Namespace - EXT.DomHelper class</title>

    <script type="text/javascript" src="ext/adapter/ext/ext-base.js"></script>
    <script type="text/javascript" src="ext/ext-all.js"></script>

   <style>
     .cssTable {
       color : #ff0000;
       border : 1px solid #000000;
     }
     .cssCell {
       background-color : #eaeaea;
     }
   </style>

     <script>

       function testIt() {

         Ext.DomHelper.append("divTable", {
           id : "tblTable", tag : "table", cls : "cssTable", children : [
             { tag : "tr", id : "row1", children : [
                 { tag : "td", cls : "cssCell", id : "row1_cell1", html : "1_1"},
                 { tag : "td", cls : "cssCell", id : "row1_cell2", html : "1_2"},
                 { tag : "td", cls : "cssCell", id : "row1_cell3", html : "1_3"}
               ]
             },
             { tag : "tr", id : "row2", children : [
                 { tag : "td", cls : "cssCell", id : "row2_cell1", html : "2_1"},
                 { tag : "td", cls : "cssCell", id : "row2_cell2", html : "2_2"},
                 { tag : "td", cls : "cssCell", id : "row2_cell3", html : "2_3"}
               ]
             }
           ]
         });

Ext.DomHelper.applyStyles(Ext.getDom("row2_cell2"), "color:#00ff00");
    Ext.DomHelper.insertAfter(Ext.getDom("tblTable"), {
      tag : "div", id : "divDiv1", html : "I am divDiv1"
    });
    alert(Ext.DomHelper.markup({
      tag : "div", id : "divDiv1", html : "I am divDiv1"
    }));

   }

   Ext.onReady(testIt);

  </script>

  </head>

  <body>
    <div id="divTable"></div>
  </body>

</html>

If you load Listing 1-1 in your browser, you will see a simple page that looks something like Figure 1-19.

When the page loads, because of the Ext.onReady() statement the testIt() method will execute. In this method we see the first use of DomHelper:

Ext.DomHelper.append("divTable", {
  id : "tblTable", tag : "table", cls : "cssTable", children : [
    { tag : "tr", id : "row1", children : [
        { tag : "td", cls : "cssCell", id : "row1_cell1", html : "1_1"},
        { tag : "td", cls : "cssCell", id : "row1_cell2", html : "1_2"},
        { tag : "td", cls : "cssCell", id : "row1_cell3", html : "1_3"}
      ]
    },
    { tag : "tr", id : "row2", children : [
        { tag : "td", cls : "cssCell", id : "row2_cell1", html : "2_1"},
        { tag : "td", cls : "cssCell", id : "row2_cell2", html : "2_2"},
        { tag : "td", cls : "cssCell", id : "row2_cell3", html : "2_3"}
      ]
    }
  ]
});

Figure 1.19. The page you'll see when you load the page in Listing 1-1 in a browser

This builds a table and inserts it into the divTable <div>. We use the DomHelper.append() method, and it's a simple enough beast. The first argument it takes is the ID of the DOM node to insert the generated HTML fragment into. The second argument is an object that describes the fragment to generate. First, we tell it what HTML tag we want to create, table in this case, using the tag attribute. We could create anything we want here, but a table is a good example because it allows us to see the children attribute in action. Even before that, though, we set an id of tblTable on the generated table, and we assign a style class of cssTable using the cls attribute.

Now, on to the children array. We can create as many children as we wish, and each child can itself have a children attribute. This allows us to create a hierarchy of elements as deep as we wish. The html attribute on each child is the content to insert in the element created.

In other words, you're simply creating some number of nested objects, each with the same attributes (tag, html, cls, id, and children) that describes a snippet of HTML in object form. DomHelper takes care of converting that into HTML and inserting it into the DOM.

It would probably be enlightening to jump ahead in the code a bit. The append() method isn't the only choice. We can also use insertBefore() method to insert the fragment before a given element. There is also insertAfter(), which inserts the fragment after the given element. You could also use insertFirst(), which inserts the fragment as the first child of the given element. In the example code you'll find an example of Ext.DomHelper.insertAfter() in action:

Ext.DomHelper.insertAfter(Ext.getDom("tblTable"), {
  tag : "div", id : "divDiv1", html : "I am divDiv1"
});
alert(Ext.DomHelper.markup({
  tag : "div", id : "divDiv1", html : "I am divDiv1"
}));

You'll also notice the Ext.DomHelper.markup() method is used. This returns the HTML fragment generated by a call to one of the insert methods. So, the alert() dialog here is what you see in Figure 1-20.

Figure 1.20. The generated HTML fragment

Hopefully that markup doesn't present any surprises, but it can be interesting to see what Ext JS is generating for us.

As an exercise, I suggest you insert a call to Ext.DomHelper.markup() and pass it the code in the first Ext.DomHelper.insert() call. This will show you the generated markup for the table. Go ahead, do that now—I'll wait!

The other method you can see in action here is Ext.DomHelper.applyStyles(), which, as its name implies, allows you to apply styles to a given DOM node. The first argument is the node itself, so I've used the Ext.getDom() method to get a reference to the second cell in the second row of the generated table. It then changes the text color to green, which you'll see if you load the page (you can't really tell from a black-and-white screenshot on the printed page obviously).

The DomHelper class, as you can see, is a handy tool indeed that saves you from having to mess around with the DOM API, which is frequently not a pleasant experience.

1.9.3. Ext.DomQuery

CSS selector queries are all the rage these days. The jQuery library is perhaps the main catalyst for this, but Ext JS provides a robust engine for CSS selector queries as well, encapsulated in the Ext.DomQuery class. In Listing 1-2 you can see examples of a number of its methods.

WHAT ARE CSS SELECTOR QUERIES?

In a nutshell, CSS selector queries are a mechanism for querying an HTML (or XML) document to retrieve one or more elements on the page in a collection, usually with the purpose of styling them in some way. The CSS3 selector spec is one way to query for elements, XPath is another, and Ext.DomQuery supports both.

Sometimes you want to manipulate a particular element on a page, and using document.getElementById() is a good choice, assuming the element is singular. But what if you want to, for example, style all the cells of all tables on the page so that their text is red, and you want to do this on the fly? Especially given that the contents of the table are possibly dynamically generated, you certainly don't want to try to retrieve each of them individually by ID. CSS selector queries allow you to do this succinctly.

Getting into constructing queries is a pretty extensive topic that I won't be covering in any detail in this book, so you may want to do some reading on that topic yourself. The Ext JS documentation for Ext.DomQuery has a decent summary, and a link to the official spec that includes more information and some good details.


Example 1.2. The DomQuery Class in Action
<html>
  <head>
    <title>Chapter 1 - Ext.util Namespace - EXT.DomQuery class</title>

    <script type="text/javascript" src="ext/adapter/ext/ext-base.js"></script>
    <script type="text/javascript" src="ext/ext-all.js"></script>

    <style>
      .cssRow1 {
        color : #ff0000;
      }
      .cssRow2 {
        color : #0000ff;
      }
      .cssCell {
        background-color : #00ff00;
      }
      .cssCellAlt {
        background-color : #eaeaea;
      }
    </style>

    <script>

      function testIt() {

var query = "td[class="cssCell"]";
     var elems = Ext.DomQuery.select(query);
     for (var i = 0; i < elems.length; i++) {
       console.log(query + " = elems[" + i + "].firstChild.nodeValue = " +
         elems[i].firstChild.nodeValue);
     }
     query = "td[class="cssCellAlt"]";
     var f = Ext.DomQuery.compile(query);
     elems = f(Ext.getDom("row1"));
     for (var i = 0; i < elems.length; i++) {
       console.log(query + " = elems[" + i + "].firstChild.nodeValue = " +
         elems[i].firstChild.nodeValue);
     }
     query = "tr[class="cssRow2"]";
     console.log("Ext.DomQuery.is(Ext.getDom("row2"), " + query + ") = " +
       Ext.DomQuery.is(Ext.getDom("row2"), query));
     query = "td";
     elems = Ext.DomQuery.select(query);
     console.log("Filtered list = " +
       Ext.DomQuery.filter(elems, "td[class="cssCell"]").length);

     }

     Ext.onReady(testIt);

   </script>

 </head>

 <body>
   <table border="1" cellpadding="2" cellspacing="2">
     <tr id="row1" class="cssRow1">
       <td class="cssCell">row1_cell1</td>
       <td class="cssCellAlt">row1_cell2</td>
       <td class="cssCell">row1_cell3</td>
       <td class="cssCellAlt">row1_cell4</td>
     </tr>
     <tr id="row2" class="cssRow2">
       <td>row2_cell1</td>
       <td>row2_cell2</td>
       <td>row2_cell3</td>
       <td>row2_cell4</td>
     </tr>
   </table>
 </body>

</html>

The first thing to take note of is the table structure in the <body> of the document. It is this structure that we'll be querying against. Note too the style classes applied to the elements. It is these settings specifically that are queried against.

If you open this page in Firefox with Firebug installed, Figure 1-21 will be the output in Firebug's console pane.

NOTE

Of course, if you aren't using Firefox, or don't have Firebug installed... why not? Seriously, though, to run this example you'll need to replace the console.log() calls with suitable replacements; alert() should work fine in this case. The discussion that follows assumes you're using Firefox with Firebug installed.

Figure 1.21. The console output for this page

The first two lines of output are a result of this code:

var query = "td[class="cssCell"]";
var elems = Ext.DomQuery.select(query);
for (var i = 0; i < elems.length; i++) {
  console.log(query + " = elems[" + i + "].firstChild.nodeValue = " +
    elems[i].firstChild.nodeValue);
}

First, a simple selector query is created. The query td[class='cssCell'] looks up all <td> tags on the page that have a class attribute setting of cssCell. This query is passed to the Ext.DomQuery.select() method, which returns an array of matching elements (you can pass a second optional argument, a reference to a DOM Element, that would limit the scope of the query, instead of querying the entire document as this example does). We can then iterate over that array and output the value of the cell. We have to drill down through the hierarchy a bit because each element of the array is a DOM Element object, and the firstChild of the Element is the text within the cell (it's actually a text node), and then the nodeValue attribute of that child is the actual text contents of the cell.

Now, being able to do queries with Ext.DomQuery.select() is neat enough, but it turns out to not be the most efficient thing out there. Precompiling the query when you know you're going to be doing it a lot is far more efficient, and Ext.DomQuery allows for that via the compile() method:

query = "td[class="cssCellAlt"]";
var f = Ext.DomQuery.compile(query);
elems = f(Ext.getDom("row1"));
for (var i = 0; i < elems.length; i++) {
  console.log(query + " = elems[" + i + "].firstChild.nodeValue = " +
    elems[i].firstChild.nodeValue);
}

This time, we pass the query to Ext.DomQuery.compile(), which returns a Function object. We can then call on that function, passing in a root node to begin the search at (this is optional), and after that it works exactly as we saw before. The Ext.DomQuery.compile() method is important if you are going to be reusing the same query many times.

Something else that can come up is the need to determine if a given Element matches some query. You could perform a query and then see if you got any matches, but there's a more concise way to do it:

query = "tr[class="cssRow2"]";
console.log("Ext.DomQuery.is(Ext.getDom("row2"), " + query + ") = " +
  Ext.DomQuery.is(Ext.getDom("row2"), query));

The Ext.DomQuery.is() method allows you to pass in an Element (retrieve using Ext.getDom() here) and a query, and it will return true if the element matches the query and false if not.

Another commonly needed function is the ability to take an existing array of Elements and filter it based on a query. The code in the example that demonstrates looks like this:

query = "td";
elems = Ext.DomQuery.select(query);
console.log("Filtered list = " +
  Ext.DomQuery.filter(elems, "td[class="cssCell"]").length);

First, a query is performed to get an array of all the <td> elements on the page (a total of eight). Next, Ext.DomQuery.filter() is used to get an array of only those Elements matching the query td[class='cssCell']. That's why we get the display "2" in Firebug's console; only two <td> elements match that query. You can optionally pass a second boolean argument to Ext.DomQuery.filter(). If you pass true, you'll get only the elements that do not match the query.

1.9.4. Ext.Updater

Earlier we took a look at the Ext.Ajax class. Now we're going to look at another bit of Ajax functionality provided by Ext JS: the Ext.Updater class. This allows us to perform Ajax updates of a DOM element, and perhaps more importantly, allows us to do that periodically. Here's a simple example:

var u = new Ext.Updater("myDiv");
u.startAutoRefresh(30, "http://somedomain.com/somePage.jsp");

This will cause an Ajax request to fire every 30 seconds to the URL specified as the second argument to u.startAutoRefresh(). The results will be inserted into the DOM node with ID myDiv (presumably a <div>).

If you only need to update the element once as opposed to repeatedly, the Ext.Updater.update() method is available:

var e = Ext.get("myDiv");
var u = e.getUpdater();
u.update({
  url: "http://somedomain.com/somePage.jsp",
  params: { param1 : "Mister", param2 : "Softie" }
});

As you can see, passing parameters is available as well, so you can handle dynamic data easily. You can also see the Ext.get() method in use. This returns an Ext.Element object representing the specified DOM node. An Ext.Element object essentially "wraps" a DOM node and provides additional functionality to it, including methods like getUpdater().

If you have an instance of Ext.Updater(), as via the var u = e.getUpdater(); line in the example code but you no longer have a reference the DOM node it is bound to, you can call getEl() on the Updater to get such a reference. You can also call abort() on the Ext.Updater instance to abort any currently in-flight requests. The isAutoRefreshing() will return true if the Ext.Updater instance is set to automatically refresh and false if not. The isUpdating() method tells you if an update is currently in progress (true) or not (false). Finally, the refresh() method can be called on an Ext.Updater instance, even if it was a onetime update, to perform the update again.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.149.243.106