Tuesday, December 2, 2008

How to modify Ext tooltips dynamically

I have a requirement to dynamically change tool-tips as content gets refreshed and modified. There were a couple of suggestions in the forums, but the following works great for me:
var mydom = Ext.get('mydomelement');       // get element
var tip = Ext.getCmp(mydom.dom.id + '_tip'); //get element's tooltip

if ( tip ) {// tool tip already exists, so modify

tip.title = 'new title';
tip.html = 'new text';
}

else { // tip does not exist. Create it with unique id.

new Ext.ToolTip({
target: mydom.dom.id,
id: mydom.dom.id + '_tip',
title: 'title here', html: 'original text'
});
}
I am giving every tooltip a unique id, based on the id of the dom element it decorates.

Wednesday, November 26, 2008

Creating Charts and Graphs

Microsoft has released a chart control with .net framework 3.5. I believe it is licensed from Dundas and certainly has the Dundas look and feel. The functionality looks good but in my travels there are two graphing systems I have used, one for the client side and one for the server side.

On the server side I usually pre-generate graphs so that if there is lots of user traffic, database access is minimized. The client does not get one of those pesky 'loading data' messages. The server side graphic files are recreated on a periodic basis, with the web page referencing the image file (PNG, GIF etc). The package I have used is ZedGraph. It is open source however there doesn't seem to have been any project activity in over a year. It is easy to use and I had the samples up and running in about 5 minutes.

On the client side interactivity rules. There are a few open source packages around ( flot, plotkit ) but they are fairly basic. I paid the few dollars for Emprise Charts and have been very happy. The interactive features are great, especially the zoom and mouse-over features. I believe there is a free version that gives limited use and a watermark on graph backgrounds. I highly recommend Emprise Charts. I've combined Ext, .Net web services and Emprise in a complete solution that is quite slick. I basically loop through an Ext datastore and load up the graph points.

Deciding on whether to render on server or on client really depends on what your users will be looking at. If your db queries are expensive in terms of time to get the data, server side is best however if you can do it, client side rendering with Ajax will give your users a better interactive experience.

Wednesday, September 17, 2008

Using Intellisense with Visual Web Dev Express

I use Visual Web Developer Express - 2008 for all my development now, although most of my projects are still .NET 2.0.

Recently I discovered how to use javascript intellisense which helps a ton. You need to have SP1 of Visual Web Developer :
http://www.microsoft.com/downloads/details.aspx?FamilyId=7B0B0339-613A-46E6-AB4D-080D4D4A8C4E&displaylang=en

Once you have SP1, just add the following to the top of each JS file:

/// < reference path="lib/ext/adapter/ext/ext-base.js">
/// < reference path="lib/ext/ext-all-debug.js">
/// < reference path="myotherfile.js">


Not only do I get Ext intellisense, but also for objects from my own javascript files. Works great!

Tuesday, April 15, 2008

Minimizing server requests : multiple tables per request

The following example shows how to return multiple tables in one ajax request. Of course, minimizing server traffic allows for a snappy client experience. My requirement was to retrieve two data tables in a single server call. The Web service makes two distinct SQL calls, merges the datasets on the server and returns an XML document.

The client establishes a single data connection and then reads the results into two separate data stores using MemoryProxy data stores. The net effect is exactly the same result as making two (expensive) server requests.


Server Side

 [WebMethod]
public XmlDocument getPlannerDetail(String plannerid)
{
// SQL Query #1
String str = " select * from TblPlanners where plannerid = '" + plannerid + "'";
Filldt("plannerDetail", (int)Servers.nweb1, str);

DataSet localds = new DataSet();
localds.Merge(dt);

// SQL Query #2
str = "select plannerid_Owner, plannerid_Changer from TblPlanners_permission where plannerid_Owner = '" + plannerid + "'";
Filldt("Permits", (int)Servers.nweb1, str);

localds.Merge(dt);

XmlDocument doc = new XmlDocument();
xmlDoc.LoadXml(localds.GetXml());
return xmlDoc;

}

Client Side

var getdata = new Ext.data.Connection();

getdata.request({
url: "Service.asmx/getPlannerDetail",
params: {
plannerid: '123'
},
method: 'POST',
scope: this,

callback: function(options, success, response){

if (success) {
var xml = response.responseXML;

dsDetails = new Ext.data.Store({
proxy: new Ext.data.MemoryProxy(xml),
reader: new Ext.data.XmlReader({
record: 'plannerDetail',id: 'plannerid'
}, ['plannerid', 'centerid', 'LongName', 'DefaultViewRange'])
});

dsPermits = new Ext.data.Store({
proxy: new Ext.data.MemoryProxy(xml),
reader: new Ext.data.XmlReader({
record: 'Permits',
id: 'plannerid_Owner'
}, ['plannerid_Owner', 'plannerid_Changer'])
});

dsDetails.load();
dsPermits.load();
}
}
});

Friday, November 16, 2007

How To : Send Ext datastore to .Net dataset with XML

There are many examples of using the Ext xmlreader to get data xml data into a datastore on the client, however I wanted to do the reverse and allow my CRUD application to update the modified datastore back to the server, updated with user changes.

On the client I created a 'serialize' function to convert the datastore to XML, and then did an Ext.data.Connection to post the data to the server.

SaveDStoServer :function(ds) {

var prog = Ext.MessageBox.wait("Saving data to server");

var ds_serialized= myscope.SerializeDS(ds);

var serv= new Ext.data.Connection();
serv.request({
url: "Service.asmx/Savedata",
params: {myID: 123, datastore:ds_serialized},
method: 'POST',
scope: this,
callback: function(options, success, response){
prog.hide();
if (success){
var xml = response.responseXML;
}
else {
if( response.status == -1 )
Ext.MessageBox.alert('Error on save','Server timeout')
else
Ext.MessageBox.alert('Error on save',response.responseText)
}
}
});
},



SerializeDS : function (ds) {

var columns = ds.fields.keys; // get columns from data store
var retdata ="&ltNewDataSet>";

ds.each ( function (rec) {
retdata +="&lt/datarow>";
for (var i=0; i< columns.length; ++ i)
retdata += "<" + columns[i] + ">" + rec.data[columns[i]]
+ "&lt/" + columns[i] + ">"
retdata += "&lt/datarow>";
});

retdata += "&lt/NewDataSet>";

return ""+retdata;
},
},


On the server side web service method, I create an XML document, create a reader and then read into the dataset. I tried using 'XMLdatadocument' but if did not seem able to create a schema and had an empty dataset. This may not be the most efficient way but it seems to work well. As always, be aware of web service parameter verification to prevent SQL injection.

[WebMethod]
public String Savedata (String SchID, String datastore)
{

DataSet ds = new DataSet();
XmlDocument doc = new XmlDocument();

// Load the xml into an XmlDocument
doc.LoadXml(datastore);
StringReader sreader = new StringReader(doc.DocumentElement.OuterXml);

ds.ReadXml(sreader);

foreach (DataRow row in dsCraft.Tables[0].Rows)
{
System.Diagnostics.Debug.WriteLine(row[0] + " " + row[1]);
}

return "success";
}

Monday, September 3, 2007

.Net Web Service with Ext data store

After using Ajaxpro with a couple of applications, I thought I should look into a more standardized approach for Ext/.Net integration. Specifically, how to bind SQL data on the server to a Ext data store. Ajaxpro's future seems uncertain.

First the Web Service:

[WebMethod]
public XmlDocument getSites(String Site, String Type, String Disc, String Manu, String query, String limit, String start, String callback)
{

XmlDocument xmlDoc = new XmlDocument();
DataSet ds = new DataSet();
String sql = " Select SITE as col1 from mytable where site = " + Site;

// create a connection
SqlDataAdapter oda = new SqlDataAdapter(sql, connStringSQL);
oda.Fill(ds);
xmlDoc.LoadXml(ds.GetXml());
return xmlDoc;
}
And the Ext code, with the .Net xml doc having 'Table' as record:

// parameters that get passed
var inparms ={query: '', start: '', limit: '', callback: '', Site: '', Type: '', Disc: '', Manu: ''};

var xmlread = new Ext.data.XmlReader({ record: 'Table' }, [
// set up the fields mapping into the xml doc
{name: 'col1'} ]);

// create the Data Store
var dsSites = new Ext.data.Store({
// load using HTTP
proxy: new Ext.data.HttpProxy({method:'POST',url: 'Service.asmx/getSites'}),
reader: xmlread, params: inparms });
.
.
.
dsSites.load( { params : inparms});
or
dsSites.load( {params : {query: '', start: '', limit: '', callback: '', Site: 'London', Type: '', Disc: '', Manu: ''});

Tuesday, August 14, 2007

Ext Combobox example... the very basics

I created a fairly sophisticated Ext application with editable grids and layouts several months ago. I now have a requirement for a new application. I thought I would start anew, resisting the temptation to just copy my old code and start modifying. I wanted to start with a clean slate but I was surprised how difficult it was to get started.

After some frustration with documentation and examples trying to get a simple combobox created, I distilled one of the examples down to the essentials. You should be able to install Ext, copy/paste the code below and you should be good to go. There are just two files you are creating, a HTML and ext_main.js...

HTML:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>my combo</title>
<link rel="stylesheet" type="text/css" href="lib/ext/resources/css/ext-all.css" />

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

<script type="text/javascript" src="ext_main.js"></script>

</head>
<body>
<h1>Simple Combo</h1>

<input type="text" id="local-states" size="20"/>

</body>
</html>

Code in ext_main.js:

/*
* Ext JS Library 1.1
* Copyright(c) 2006-2007, Ext JS, LLC.
* licensing@extjs.com
*
* http://www.extjs.com/license
*/

// some data used in the examples
Ext.namespace('Ext.exampledata');

Ext.exampledata.states = [
['AL', 'Alabama'],
['AK', 'Alaska'],
['AZ', 'Arizona'],
['AR', 'Arkansas'],
['CA', 'California'],
['CO', 'Colorado'],
['CN', 'Connecticut'],
['DE', 'Delaware'],
['DC', 'District of Columbia'] ];

var combos = {
init : function(){


// simple array store
var store = new Ext.data.SimpleStore({
fields: ['abbr', 'state'],
data : Ext.exampledata.states
});
var cbsite = new Ext.form.ComboBox({
store: store,
displayField:'state',
typeAhead: true,
mode: 'local',
triggerAction: 'all',
emptyText:'Select a state...',
selectOnFocus:true
});

cbsite.applyTo('local-states');

}};
Ext.onReady(combos.init, combos);