Showing posts with label extjs. Show all posts
Showing posts with label extjs. Show all posts

11 April 2011

IIS6 to IIS7 - Catching Ajax errors

The way Ajax errors are sent to the browser has changed between IIS6 and IIS7. Errors used to be sent automatically and you could parse the XML on the client. Now, the developer is required to do a little more work because IIS traps the error and stops code execution before reaching the end of the method.
For example, the Ext JS Ajax call takes an object with 5 parameters: method, url, params, success and failure. The last parameter is a callback function that is executed if the server sends back a failure.
The good news is that you have to make a small change to the server-side code (only). Another piece of good news is that the code is generic - the snippet will work with most web methods.
To make it work, create a try... block around the code that may throw an error. (This example is written in C#.) Next, add the following catch block:

catch (Exception e) {
HttpResponse Response = HttpContext.Current.Response;
Response.StatusCode = 500;
Response.Write(e.Message);
HttpContext.Current.ApplicationInstance.CompleteRequest();
Response.End();
}

The code above intercepts the error and returns it to the client. If you already had Ajax code listening for failure, you will not have to change the client side at all.

Note: Special thanks to this blog post by Rick Strahl.

28 March 2011

Ext JS - Mixed Collection Extension

At the top of my wish list for Ext JS is some recursive container search logic. There are times when you need to access a control on a form and can get it via a search term.

 In this case, I wanted to look for the control with a tab index of one greater than the current control. Ext.getCmp would make one control dependent on another.  This logic enables me to find the next control in the container by searching for by property for the next largest tabIndex property.

This extension will recursively search an Ext JS (v 2.x) mixed collection for the first object that has the property you are looking for.  The new method is called 'findByProperty'.


/* Extends the mixed collection object and recursively finds an object */

Ext.override(Ext.util.MixedCollection, {

    findByProperty: function (property, value, defaultValue) {

        var obj = defaultValue,

            notFound = true,

            find = function (itm, idx, len) {

                if (itm.items) {
                    this.items.each(find);
                }

                if (itm[property] && itm[property] === value) {
                    obj = itm;
                    notFound = false;
                }

                return notFound;
            };

        this.each(find);

        return obj;
    }
});



Where:
  • property is the string property you are looking for
  • value is the property value 
  • defaultValue is the optional value to be returned if nothing is found

21 March 2011

Ext JS: relayEvents

I have found that the relayEvents method in Ext JS (2.x) is one of the most useful and code-saving techniques one can use.  The purpose of the method is to allow one object to listen to the custom events of another object.

I have found that the documentation is not that good, which can make somewhat RelayEvents hard to use.  Here is my shorthand to make is easy:


listener.relayEvents(broadcaster, ['custom event a', 'custom event b']);

Where:

  • listener: The object listening for events.  Register the array events in the listeners collection of the object
  • broadcaster: The object firing the events.  To fire the event use the fireEvent('custom event a') method within the broadcaster to fire the event

10 March 2011

Override setValue in Ext JS

I am working with Ext JS 2.x and have the need to format numeric values, such as percentages and comma delimited values.

The best way I know to format the numbers is to override the setValue function of the field. My original plan was to put the formatting in the 'change' event, but calling the setValue in the code does not call this event.

The way to override setValue method is easy, but not obvious. The directions are as follows:


[Namespace].form.[FieldName] = Ext.extend(Ext.form.Field {

    constructor: function (config) {

        /// constructor logic here
        [Namespace].form.[FieldName].superclass.constructor.apply(this, arguments);

    },

    setValue: function (val) {

        /// format logic here for val argument
        return [Namespace].form.[FieldName].superclass.SetValue.call(this, val);

    }

});

17 March 2010

ASP.Net Data meets Ext JS: Ext.net – Store and GroupingStore


Download the source code for Ext.net here.

Overview

Ext JS is my front-end platform of choice for all my ASP.Net applications.  The reasons are simple – Ext JS gives the developer more control, supports better coding practices, and takes better advantage of the IIS platform than native ASP development options.  But how could that be?

First, there is the question of control.  ASP controls are not open source.  It’s hard for the developer to understand what is going on under the covers without extensive study.  When will the page refresh?  When will the control talk to the server?  How can I give the control a different look?  Why is that Microsoft object emitting CSS?  Many of these questions are difficult for most people to understand and take valuable time to understand. 

Ext JS controls are open source and have a rich, well documented event model.  You can read the code directly if you need to.  Ext JS controls don’t make unexpected calls to the server or emit unexpected code  The developer controls how data is piped from the sever to the screen, which makes it easier to control events and identify performance bottlenecks. 

Simply put, the developer has complete control over everything that call that happens on the client.  There are not many mysteries. And aspects that annoy you can be fixed at programming time by looking at the source code.

Secondly, I have always been bothered by the mixed metaphor of ASP.Net development.  What’s on the browser?  What’s on the server?  Do I code this control with HTML or C#?  For all the remarkable work Microsoft did to make the process seem like coding a Visual Basic application (it is truly amazing), the actual results can be bizarre and fragmented.  .Net languages appear on the page with HTML, which then might have additional code capturing events somewhere else.  The page object model is complex, and ASP developers have to learn when and how to place each control on the page to

Ext JS controls are coded entirely in JavaScript and the separation between browser and server is clearly defined.  There is no half-HTML/half C# (or VB.Net) control that lives partially in code-behind and partially on the page.  There is no reason to carefully wedge control-code between page events to get everything working correctly.

This complete separation tends to drive business logic off the page and back onto the server where it belongs.  My personal preference is to keep the server code and UI code as separate as possible.  Ext JS enables the developer to keep the server-side code simple and clean.  Simply write your UI in JavaScript and expose the web services for the page.  This approach also simplifies testing because the developer can easily identify and test the logic used in each page.

Finally, Ext JS makes it possible to leverage the absolute strength of IIS, which is delivering web services.  It has always struck me as strange that ASP.Net controls do not explicitly consume services.  In an effort to make the communication seamless, Microsoft actually minimizes the strengths of exposing SOAP services.  This, in turn, leads to code-bloat, because the developer has to write custom code to deliver data to ASP.Net controls and then additional code to deliver data to other applications.

Despite all these advantages, communication between Ext JS and ASP web services can be tedious.  Ext JS was written by people who are clearly oriented towards JSON data delivery.  And why not?  It’s lightweight and native to JavaScript.  There is the XML reader, but the average .Net/Ext JS developer still has to write tedious (and needless) code to parse the data into stores.

But IIS (.Net) is an XML-oriented language.  It does not serve JSON without specialized server-side code and some hacking.  What if you work in a corporate environment that does not allow non-standard software to be installed on the server?  Shouldn’t the goal of the programmer be to stick to the standards and also leverage what each piece of software does best?

Ext.net.Store and Ext.net.GroupingStore

Ext JS.net started with simple questions.  Why should I write JavaScript code to describe my data structures, when an ASP.Net web services already delivers that data to my page?  Would my code be less coupled if I worried more about the UI and less about the structure of the data coming to my page? 
The result is Ext.net.Store and Ext.net.GroupingStore.  The goals of this project are as follows:
  • Reduce boilerplate code – on the server and the page
  • Increase web service reuse/simplify server-side code
  • Simplify data transport and consumption
Table names and data types have already been written and defined on the server – why write them again?

How does Ext.net work? 

The Ext.Net stores intercept the XML returned from a web-service call and build the data set before the store is completely initialized.  This means that the data definition that is defined on the server and delivered in the web service automatically becomes the data definition in the store. 
In order to take advantage of the store, the programmer simply exposes an ADO DataSet as the return data type.  Ext.Net stores consumes the meta-data, builds a table definition and then populates it with the service data.

On the server, create a standard data set.  The names of the tables do not matter.


IIS Server Side Code - C#

[WebMethod]
  public DataSet TableData()
  {
      DataSet ds = new DataSet("ds"); 
      string cnStr = ConfigurationManager.ConnectionStrings["local"].ToString();
      using (SqlConnection cn = new SqlConnection(cnStr))
      {
          string strSQL = "SELECT * FROM tblDataVals";
          using (SqlDataAdapter da = new SqlDataAdapter(strSQL, cn))
          {
              da.Fill(ds, "data");
          }
          strSQL = "SELECT COUNT(*) FROM tblDataVals";
          using (SqlDataAdapter da = new SqlDataAdapter(strSQL, cn))
          {
              da.Fill(ds, "count");
          }
          cn.Close();
      }
      return ds;
  }


The client-side JavaScript is just as simple.  In your HTML add a reference to Ext.net.Store.  Make sure the reference appears after the references to ExtJs code.

Declare a store by using Ext.net.Store or Ext.net.GroupingStore wherever you would declare a store.  All of the config parameters are the same, with very few differences. 

Ext.net.Store and Ext.net.GroupingStore will create a reader automatically, so you do not have to declare an XMLReader or any record definitions.  On large grids, this will save considerable code. 

There is one extra parameter to add to the grid – net. The net object has 3 fields:
  • dataTable (string): The name of the table that contains the data.  This will be translated into the store data.
  • dataTableId (string): The name of the field that contains the id of the data table.
  • totalRecords (string): The name of the table that contains the data count.  This parameter is optional.
Below is a sample store declaration.  Note that there is no record definition because it is created at run time. 
A big benefit to this is that the service can change and the grid will keep on working as it did before.  For large grids, you also save re-coding record definitions.


Sample Ext.net.Store declaration in JavaScript

var s = new Ext.net.Store({
net: {
     dataTable: 'data',
     dataTableId: 'id',
     totalRecords: 'count'
},
  remoteSort: true,
  sortInfo: { sort: 'fname', dir: 'ASC' },
  proxy: new Ext.data.HttpProxy({
     url: 'EmployeeServices.asmx/GetEmployees',
     method: 'GET'
  }),
  storeId: 'empStore'
});



The source code for Ext.net.Store and Ext.net.GroupingStore can be downloaded for free from http://extjsdata.codeplex.com/.  The code has been tested with Firefox 3.5+ and IE7+.  It was designed to be compatible with ExtJs Framework 2.2, but also works with 3.1.

02 February 2010

ExtJS Helper Functions - SelectionModel Modifications

One of the application patterns I implement in ExtJS is to have ViewPort containing a grid with records for a user to edit.  The user double-clicks a record on the grid, which opens a window to edit the information.  When complete, the user then closes the window and the grid refreshes.

The issue is that after the grid refreshes, the user loses her place on the grid as the selection goes back to the first record.

Additionally, the RowSelectionModel() only implements selection by index, which means that if there are concurrency checks, you cannot automatically go back to the index you were on or guarantee the new index will be correct.

These methods attempt to correct these shortcomings.  The first extension implements a selectById method for the RowSelectionModel object.

The second extension implements a SelectAfterLoad method on the GridPanel (and all of it's descending objects).  When closing the form, take the id from the record you are using and pass it into the selectAfterLoad method.  The method will kick off a single event to find the id in the current loaded record set.  If the id of the record is not found, the default 'selectFirstRow()' method is called.


// extend the RowSelectionModel
Ext.override(Ext.grid.RowSelectionModel, {

// enables the selection model to select by record id
selectById: function (id) {

var sm = this,               // hook to the selection model
      s = sm.grid.store,   // reference to the store
      f = false,                 // found (initialized as false)
      idx = 0;                   // record index

      // if store has no records, return control
      if (s.getCount() === 0) {
          return;
      }

     // iterate through each record, looking for the id
     s.each(function (r) {
          // if the record id matches the passed id
          if (r.id.toString() === id.toString()) {
               // found is true
               f = true;
               // select the row
               sm.selectRow(idx, false);
               // return false to exit
               return !f;
          }


          // iterate the index
          idx = idx + 1;
         // return true to continue iteration
         return !f;
      });
           // if not false, exit
            if (!f) {
                // select the first row
               sm.selectFirstRow();
          }
     }
});

// selects by record id after the grid reloads
Ext.override(Ext.grid.GridPanel, {

     // selects row by id after store loads
     selectAfterLoad: function (id) {

     // get the grid selection model
     var sm = this.getSelectionModel();

     // select record by passed id argument after store loads
     this.store.on({
               'load': {
                     fn: function (t, recs, opts) {
                          sm.selectById(id);
                      },
                      single: true
                 }
           });
      }
});

20 January 2010

ExtJS Helper Functions - GetValue / SetValue

This is my first (of several planned) functions to increase the functionality of the ExtJs functionality.

These methods extend the container object and make it easier to set and retrieve values from the controls within the container.  A great benefit is that the search will go into all the nested containers as well.


// Shortcut for adding methods to the prototype
Function.prototype.method = function (name, func) {
this.prototype[name] = func;
return this;
};

// Works on all containers (windows, formformpanels, etc.) and will
// even search subcontainers. The control must have an identifiable id
// and a setValue method.
// In this method c is the control id and v is the value to be set.
Ext.Container.method('setValue', function (c, v) {
this.findById(c).setValue(v);
});

// Works on all containers as above. The control must have an identifiable
// id  and a getValue method.
// In this method, c is the control id of the value to be retrieved.
Ext.Container.method('getValue', function (c) {
return this.findById(c).getValue();
});


Using these functions on the container saves a tremendous amount of code devoted to looking up and setting values. Just create a variable for the container and then use the getValue retrieve the value or setValue to set the value.

For instance, if you have a window object named 'win' and a textbox with an id of 'txtName', you can merely use:
win.setValue('txtName', 'Michael'); 
Doing so will set the TextBox value to Michael, even if it is deeply nested in a form panel and several columns.

Links:
http://extjs.com

06 February 2008

Ext JS - One Service Several Stores

One Service - One Store
The ExtJS framework makes loading data from an ASP.Net XML Service a snap. The pattern for retrieving data from the server is as follows:
  • Create a service (server side)
  • Define a record structure
  • Define a record reader
  • Define a server proxy (Http) to deliver data to the reader
  • Define a data store and load the data
Create the web service that serves up your data. Since I am using ASP.Net, the service returns a dataset as an XMLDocument. But the data can also be served back as JSON or put directly onto the page.

Create a Ext.Record definition for parsing the data. An example is listed below. The record is going to be displayed in a combo box.

// record object definition
var xmlRec = new xd.Record.create([
{name: 'entid', type: 'string'},
{name: 'entnm', type: 'string'}
]);


Create an Ext.Reader object. Ext JS provides XML and JSON readers. A sample XmlReader is listed below.

// xml reader for the entity dropdown
var xmlReader = new xd.XmlReader(
{
record: 'entity',
id: 'entid'
},
xmlRec
);


Create an Ext.HttpProxy object. For ASP.Net I have found that the URL and method attributes both have to be initialized.

Inside tip: When using ASP.Net 2.0 you will have to enable POST on your IIS server via the web.config or this won't work. See this Microsoft KB on how to enable POST on IIS.

// proxy for the entity connection
var proxyEntity = new xd.HttpProxy({
url: 'services.asmx/combInit',
method: 'POST'
});


Create an Ext.Store object for delivery to your consumer.
// create the store
var str = new xd.Store({
proxy: proxyEntity,
reader: xmlReader
});


One Service - Multiple Stores
.Net makes it easy to share connections using ADO.Net and then persist the data in a DataSet on the server for delivery to the client. Imagine if you could load all the 'static' data fields on your page from one service in one call. If you look at the abstraction pattern outlined above, the answer is not obvious - but Ext JS makes it easy.

The pattern for using one service for deliver to several stores is only slightly different.
  • Register a function on the 'load' event for the first store. This function will load the data into the other stores.
  • Deliver data to the first store as above. Make sure to invoke the load() method.
  • Create your new record and reader definitions.
  • Retain a variable that points to the original data. The example here is for XML.
  • Use a Memory Proxy to load the existing data into a new store(s).
Registration for events is relatively simple. In the example below, I create a new combo object and pass the XMLData into the constructor of the object. This xmlData contains all the data for all the combos on my form.

store.on('load',function(t, rec, opt){
var sct1Cb = new Sector1Combo(entCb.xmlReader.xmlData);
....(load other data)
});


Creating the record definition and XMLReader object was covered above so I will skip it here. The important thing is to replace the HttpProxy with a MemoryProxy, using the XML data in the constructor.
var str = new xd.Store({
proxy: new Ext.data.MemoryProxy(XmlDocument),
reader: xmlReader
});
str.load();


Using this second technique, you only have to make one web service to load your combo boxes. On the server side, that means you only have to connect one time to the database for your static data. It also cuts down considerably on the code you have to write and maintain.

24 January 2008

Remote ExtJS Grid Sorting in ASP.Net

Remote Grid sorting in ExtJS is relatively straightforward, but there is one "gotcha" to look out for.

Steps for Implementing Remote Sorting
The steps for implementing remote sorting are as follows:
  • Create your web service that returns a record set. Give it two parameters that define the field name and sort direction. The value passed back will be 'ASC' or 'DESC'. Just use that in your call to the database for implementing the order in your select statement.
  • In your store, add the 'remoteSort: true' to the constructor.
  • Call the setDefaultSort(field name, direction) on some time before the load.
The Gotcha
I have quoted the ExtJS code below from the Ext.data.Store documentation. Make sure that the actual parameters of the web service are 'sort' (for field name) and 'dir' (for ASC/DESC). If you do not name the parameters the same as what is listed below, the remote sorting will not work.


remoteSort : boolean
True if sorting is to be handled by requesting the Proxy to provide a refreshed version of the data object in sorted ...
True if sorting is to be handled by requesting the Proxy to provide a refreshed version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).

If remote sorting is specified, then clicking on a column header causes the current page to be requested from the server with the addition of the following two parameters:

  • sort : String

    The name (as specified in the Record's Field definition) of the field to sort on.

  • dir : String

    The direction of the sort, "ASC" or "DESC" (case-sensitive).


Overall, the grid is coming along nicely. Eventually, the code makes sense. But getting ASP.Net to work with ExtJS is proving to be a challenge.

18 January 2008

In the trenches with the ExtJS Grid and ASP.Net

Yesterday I successfully got ExtJS to retrieve data via an ASP.Net web service and wanted to outline the steps here for future reference.

Before getting started, I want to mention that my client runs ASP.Net 2.0 and have only consented to using the standard ASP.Net Ajax download from Microsoft on their servers. No other server software is allowed for this project.

Special thanks to amackay11 and his blog posting on how to consume XML. That posting is invaluable.

Server Side - C# / ASMX / ASP.net

The server side is relatively straightforward. There are a few requirements for coding the web services.

The ASMX code-behind service classes should have the WebService (added automatically by Visual Studio) and WebServiceBinding attributes,with the BasicProfile1_1 as the conforming WSI Profile.

[WebService(Namespace = http://tempuri.org/)]
[WebServiceBinding(ConformsTo=WsiProfiles.BasicProfile1_1)]

The ASMX methods need to be coded with the [WebMethod] attribute (again, this is standard service coding).

[WebMethod]
public XmlDocument getEmployees() {...}

One thing to notice is that the return value is an XmlDocument. .Net makes it easy to return fully formatted XmlDocuments. I recommend using DataSets for return data structures because it is easy to add tables and combine all the data calls into one message from the server to the client.

[WebMethod]
public XmlDocument getEmployees() {
// Create a new data set. The name of the dataset will be the
// opening and closing tag of the return document
DataSet ds = new DataSet("EmployeeSet");
string cmd = "SELECT * FROM tblEmployee";
SqlDataAdapter da = new SqlDataAdapter(cmd, cn());
// Fill the employee table
da.Fill(ds, "Employee");
//Total count from the table for paging purposes
DataTable count = new GetRecordCount("tblEmployee");
// Add the new table to the data set
ds.Tables.Add(count);
// Create and return the data set
XmlDocument doc = new XmlDocument();
doc.LoadXml(ds.GetXml());
return doc;
}

The previous sample code demonstrates how easy C# makes it to publish the XML for client consumption. An ADO.Net dataset is a nice flexible container and if your page has multiple data consumers on the page, the DataSet.Tables.Add() method makes it easy to throw one more structure into the mix before sending data to the client.

The previous code will then return an XML document.

<?xml version="1.0" encoding="utf-8"?>
<EmployeeSet>
<Employee>
<Id>1</Id>
<FirstName>Rob</FirstName>
<LastName>Livingston</LastName>
<Email>fred@yahoo.net</Email>
</Employee>
<Employee>
<Id>2</Id>
<FirstName>Chris</FirstName>
<LastName>Salad</LastName>
<Email>chris@salad.com</Email>
</Employee>
<Employee>
<Id>3</Id>
<FirstName>Adam</FirstName>
<LastName>Funk</LastName>
<Email>adam@funk.com</Email>
</Employee>
<Employee>
<Id>4</Id>
<FirstName>Steve</FirstName>
<LastName>Larsen</LastName>
<Email>larsenr@google.net</Email>
</Employee>
<records>
<count>4</count>
</records>
</EmployeeSet>

Notice the straightforward data structure and how the record count is appended neatly to the end of the XML document.

Client Side / JavaScript / HTML / Ext JS

The client side can be tricky to the uninitiated, especially the JavaScript. ExtJs requires two JavaScript includes and one CSS include in the header. You will also need to include your JavaScript file.

<head runat="server">
<title>Employee Edit Grid</title>
<script src="ext-2.0/adapter/ext/ext-base.js" type="text/javascript"></script>
<script src="ext-2.0/ext-all.js" type="text/javascript"></script>
<script src="JavaScript/Employee.js"></script>
<link rel="stylesheet" type="text/css" href="ext-2.0/resources/css/ext-all.css" />
</head>

One disadvantage of using XML is that verbosity of the server/client message. That being said, one advantage of not using JSON in an ASPX is that it requires 2 additional JavaScript includes (which are generated at run time), which makes the compiler complain (in Visual Studio 2005 at least). I mention that here because the includes can sometimes create headaches for the new developer.

The pattern for developing a grid in Ext JS is as follows:

  • Create a column model object which defines how the columns will be formatted and rendered in the grid
  • Create a record object which defines the data structure
  • Create an XMLReader object to consume the XML Web Service. The XML reader uses the record object to create the final record structure.
  • Create an HttpProxy object to connect to the data source.
  • Create the DataStore object that delivers the data to the data grid. The data store uses an HttpProxy (or some other connection) as well as an XMLReader (or some other DataReader) object as arguments.
  • Create the grid which takes a DataStore and ColumnModel as constructor arguments.

Although the steps are fairly complicated, I am amazed at how little JavaScript is actually required to get data to the page.

The biggest 'gotcha' of the entire process is configuring the HttpProxy object. The main question I had was, how do you consume the service?

Again, .Net makes this easy. Point the URL to the ASMX file / services. The proxy takes a parameters object if the service takes arguments.

I successfully configured a proxy object as listed in the example below.

var proxy = new Ext.data.HttpProxy({
url: 'Services.asmx/getEmployees',
method: 'POST'
});

10 January 2008

Struggling with ExtJS and ASP.Net

I am struggling with ExtJS and ASP.Net 2.0 working together. Today I spent the entire day trying to get a simple grid working. After working most of the day, I finally got it to work. Somehow the joy was gone...hoping to work more with this tool

Following is the methods I used to get a simple unformatted grid up and working.

XML/ASPX
Due to corporate constraints at my current employer, I am forced to use XML and cannot take advantage of the latest JSON technology. That meant that the grid data source has got to be XML.

Exposing XML in ASP.Net is not well documented and not well understood. In fact, I even came across a Jesse Liberty posting asking how to do something similar (I think). (Hat's off to Jesse Liberty - he writes great books - but I have no idea what he is talking about in that post.)

Creating a raw XML page from an ASPX file turns out to not be difficult. Write code to do the following in the Page_Load event:
  • Create a DataSet
  • Connect to the database and fill a table in the dataset via a DataAdapter
  • Create an XmlTextWriter and populate the constructor with the Response.OutputStream and Encoding.UTF8 arguments
  • Call the XmlTextWriter.WriteStartDocument() method
  • Use the data table.WriteXML method, using the XMLTextWriter as the single argument
  • Call the XmlTextWriter.WriteEndDocument() method
The markup also requires two tasks:
  • Clear the page of all markup except for the page directive at the top
  • Add the ContentType attribute to the directive, specifying "text/xml"
The above was done for testing purposes. I think the recommended method for exposing XML is via a Web Service. ExtJS's data reader will (theoretically) read almost XML source. I can definitely vouch that they use a complex XML example on their website for consuming XML.

ExtJS Sample code
The JavaScript code in the example leaves a lot to be desired. You want to look at the one here. The difference is that the second example uses the Ext.data.HttpProxy object. This turns out to be a non-trivial difference. Your code will not be able to read the data without it.

Finally, do yourself a favor and create a record object to pass the data when using the reader to read the data structure. I'm not sure what they are doing in the example - but hopefully I'll learn. Creating a record object will make your life easier.