Ext.ux.Printer – printing for any ExtJS Component

After my recent foray into printing grids with ExtJS, I realised I needed to print some trees too. Seeing as some of the work was already done for the Grid example, it made sense to create a common API for printing any Ext.Component. And thus Ext.ux.Printer was born:

var grid = new Ext.grid.GridPanel({ // just a normal grid });
var tree = new Ext.tree.ColumnTree({ // just a normal column tree });

Ext.ux.Printer.print(grid);
Ext.ux.Printer.print(tree);

Each of the above opens a new window, renders some HTML (just a big table really), prints it and closes the window – all client side with no server side code required. Although trees and grids represent data quite differently internally, we can use the same API on Ext.ux.Printer to print them both.

Ext.ux.Printer uses Renderer classes to cope with a specific xtype, and adding Renderers for other components is easy. At the moment Ext.grid.GridPanel and Ext.tree.ColumnTree are supported out of the box, but let’s see how we’d add support for printing the contents of an Ext.Panel:

/**
 * Prints the contents of an Ext.Panel
 */
Ext.ux.Printer.PanelRenderer = Ext.extend(Ext.ux.Printer.BaseRenderer, {

 /**
  * Generates the HTML fragment that will be rendered inside the <html> element of the printing window
  */
 generateBody: function(panel) {
   return String.format("<div class='x-panel-print'>{0}</div>", panel.body.dom.innerHTML);
 }
});

Ext.ux.Printer.registerRenderer("panel", Ext.ux.Printer.PanelRenderer);

This is probably the simplest print renderer of all – we’re simply grabbing the HTML from inside a the panel’s body and returning it inside our own div. We subclassed Ext.ux.Printer.BaseRenderer, and in this case all we needed to do was provide an implementation for generateBody. Whatever this function returns is rendered inside the <body> tag of the newly-opened printing window.

Notice that we registered this renderer for all components with the xtype of ‘panel’. Internally, Ext.ux.Printer examines the xtype chain of the component you pass it to print, and uses the first renderer that matches. As many Ext components inherit from Ext.Panel this can function as a catch-all renderer.

Here’s how we’d use our new renderer:

var panel = new Ext.Panel({
  html: {
    tag: 'ul',
    chidren: [
      {tag: 'li', text: 'Item 1'},
      {tag: 'li', text: 'Item 2'},
      {tag: 'li', text: 'Item 3'}
    ]
  }
});

Ext.ux.Printer.print(panel);

Pretty straightforward. You can now print Ext.Panels the same way you’d print a Grid or a Tree. Take a look at the Grid Renderer and the ColumnTree Renderer for examples of rendering more advanced components.

As usual, all of the Ext.ux.Printer source is available on Github, and the README file there contains instructions for installation and usage.

Finally, when the printing window is opened it includes a stylesheet that it expects to find at “/stylesheets/print.css”. There is a default print.css stylesheet included with the extension to get you started, and you can specify where to find this stylesheet like this:

Ext.ux.Printer.BaseRenderer.prototype.stylesheetPath = '/path/to/print/stylesheet.css';

ExtJS grid page size – letting the user decide

Sometimes you’ll be using a Paging Toolbar on a grid and need to give the user the ability to change the number of records per page. One way of doing this is by adding a combobox to the toolbar:

var combo = new Ext.form.ComboBox({
  name : 'perpage',
  width: 40,
  store: new Ext.data.ArrayStore({
    fields: ['id'],
    data  : [
      ['15'], 
      ['25'],
      ['50']
    ]
  }),
  mode : 'local',
  value: '15',

  listWidth     : 40,
  triggerAction : 'all',
  displayField  : 'id',
  valueField    : 'id',
  editable      : false,
  forceSelection: true
});

We’ve set up a simple combo box which allows the user to choose between 15, 25 and 50 records per page. Now let’s set up a Paging Toolbar, and a listener to take action when the user changes the selection in the combo box:

var bbar = new Ext.PagingToolbar({
  store:       store, //the store you use in your grid
  displayInfo: true,
  items   :    [
    '-',
    'Per Page: ',
    combo
  ]
});

combo.on('select', function(combo, record) {
  bbar.pageSize = parseInt(record.get('id'), 10);
  bbar.doLoad(bbar.cursor);
}, this);

Finally we’ll roll it all together into a Grid:

var grid = new Ext.grid.GridPanel({
  //your grid setup here...

  bbar: bbar
});

If the user needs to be able to enter her own page size, replace the ComboBox with an Ext.form.NumberField, and attach the event listener to the field’s ‘keypress’ event.

Printing grids with Ext JS

Grids are one of the most widely used components in Ext JS, and often represent data that the user would like to print. As the grid is usually part of a wider application, simply printing the page isn’t often a good solution.

You could attach a stylesheet with media=”print”, which hides all of the other items on the page, though this is rather application-specific, and a pain to update. It would be far better to have a reusable way of printing the data from any grid.

The way I went about this was to open up a new window, build a table containing the grid data into the new window, then print it and close. It’s actually pretty simple, and with a bit of CSS we can even get the printable view looking like it does in the grid.

Here’s how you use it (this is a slightly modified version of the Array Grid Example):

var grid = new Ext.grid.GridPanel({
  store  : store,
  columns: [
      {header: &quot;Company&quot;,      width: 160, dataIndex: 'company'},
      {header: &quot;Price&quot;,        width: 75,  dataIndex: 'price', renderer: 'usMoney'},
      {header: &quot;Change&quot;,       width: 75,  dataIndex: 'change'},
      {header: &quot;% Change&quot;,     width: 75,  dataIndex: 'pctChange'}
      {header: &quot;Last Updated&quot;, width: 85,  dataIndex: 'lastChange', renderer: Ext.util.Format.dateRenderer('m/d/Y')}
  ],
  title:'Array Grid',
  tbar : [
    {
      text   : 'Print',
      iconCls: 'print',
      handler: function() {
        Ext.ux.GridPrinter.print(grid);
      }
    }
  ]
});

So we’ve just set up a simple grid with a print button in the top toolbar. The button just calls Ext.ux.GridPrinter.print, which does all the rest. The full source code that this example was based upon can be found at http://extjs.com/deploy/dev/examples/grid/array-grid.js.

The source for the extension itself is pretty simple (download it here):

If you look at the source above you’ll see it includes a ‘print.css’ stylesheet, which can be used to style the printable markup. The GridPrinter expects this stylesheet to be available at /stylesheets/print.css, but this is easy to change:

  //add this before you call Ext.ux.GridPrinter.print
  Ext.ux.GridPrinter.stylesheetPath = '/some/other/path/gridPrint.css';

Finally, here is some CSS I’ve used to achieve a grid-like display on the printable page:

html,body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,p,blockquote,th,td{margin:0;padding:0;}
img,body,html{border:0;}
address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}
ol,ul {list-style:none;}caption,th {text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;}q:before,q:after{content:'';}

table {
  width: 100%;
  text-align: left;
  font-size: 11px;
  font-family: arial;
  border-collapse: collapse;
}

table th {
  padding: 4px 3px 4px 5px;
  border: 1px solid #d0d0d0;
  border-left-color: #eee;
  background-color: #ededed;
}

table td {
  padding: 4px 3px 4px 5px;
  border-style: none solid solid;
  border-width: 1px;
  border-color: #ededed;
}

This technique could easily be adapted to print any component that uses a store – DataViews, ComboBoxes, Charts – whatever. It just requires changing the generated markup and stylesheet.

Ext.override – Monkey Patching Ext JS

Ext JS contains a function called Ext.override. Using this function allows you to add functionality to existing classes, as well as override properties of the class. For example, let’s say we want to override how Ext.Windows are hidden:

Ext.override(Ext.Window, {
  hide: function() {
    //the contents of this function are now called instead of the default window hide function
  }
});

Using Ext.override changes the prototype of the class you are overriding – all instances of Ext.Window will now use the new hide function in the example above.

Overriding other classes can be dangerous, especially when they are classes from a library not under your control. For example, if the Ext.Window class was refactored in a later version, your overrides may no longer work. In some situations you might choose to go down the safer route of augmenting the existing functionality without overriding it. Here’s one way we can achieve this using a closure:

(function() {
  var originalHide = Ext.Window.prototype.hide;

  Ext.override(Ext.Window, {
    hide: function() {
      //perform pre-processing
      alert(&quot;The window is about to close!&quot;);

      //call the original hide function
      originalHide.apply(this, arguments);

      //perform post-processing.
      alert(&quot;The window closed!!1&quot;);
    }
  });
})();

In the example above we set up a closure via an anonymous function which is executed immediately. This lets us keep a reference to the original hide function on Ext.Window. Underneath we perform the override itself, in which we provide our own logic.

The originalHide.apply(this, arguments) line is key to maintaining Ext.Window’s original functionality. By using the apply keyword with the Window’s usual scope (‘this’) and the function’s arguments ‘array’, we can wrap our functionality before or after the original method.

Augmenting in this way is safer than simply overwriting the function, or copy & pasting Ext.Window’s original hide function into your own, as you don’t have to worry about breaking what Ext JS itself does (you’re still responsible for making sure your own additions work after upgrading Ext though).

Be aware that this will affect all instances of Ext.Window (or whatever class you are overriding). If that isn’t what you want, use Ext.extend to create your own subclasses instead.

Finally, note that you can use Ext.override on any class, not just the built-in Ext ones – all it does internally is call Ext.apply on the constructor function’s prototype.

Ext JS iterator functions

Ext JS has a number of handy iterator functions. Some, like Ext.each, you probably already know about, but there are a few others lurking around which can be useful in saving yourself a few lines of code. First, let’s recap Ext.each:

Ext.each

Ext.each applies a function to each member of an array. It’s basically a more convenient form of a for loop:

var people = ['Bill', 'Saul', 'Gaius'];

//using each to detect Cylons:
Ext.each(people, function(person, index) {
  var cylon = (index + 1) % 2 == 0; //every second man is a toaster
  alert(person + (cylon ? ' is ' : ' is not ') + 'a fraking cylon');
});

//is the same as
for (var i=0; i &lt; people.length; i++) {
  var person = people[i];
  var cylon = (i + 1) % 2 == 0; //every second man is a toaster

  alert(person + (cylon ? ' is ' : ' is not ') + 'a frakin cylon');
};

Ext.iterate

Ext.iterate is like Ext.each for non-array objects. Use it wherever you would normally use a for .. in loop:

var ships  = {'Bill': 'Galactica', 'Laura': 'Colonial One'};

Ext.iterate(ships, function(key, value) {
  alert(key + &quot;'s ship is the &quot; + value);
});

//is the same as
for (key in ships) {
  var value = ships[key];
  alert(key + &quot;'s ship is the &quot; + value);
}

Using Ext.iterate with an array is the same as calling Ext.each. Each and Iterate both take an optional third parameter, which is the scope to run the function in. Another advantage over using the for construct is that you can easily reuse the same function:

var myFunction = function(item, index) {
  //does some clever thing
}

Ext.each(people, myFunction);
Ext.each(['another', 'array'], myFunction);

Ext.pluck

Ext.pluck grabs the specified property from an array of objects:

var animals = [
  {name: 'Ed', species: 'Unknown'},
  {name: 'Bumble', species: 'Cat'},
  {name: 'Triumph', species: 'Insult Dog'}
];

Ext.pluck(animals, 'species'); //returns ['Unknown', 'Cat', 'Insult Dog']
Ext.pluck(animals, 'name'); //returns ['Ed', 'Bumble', 'Triumph']

Ext.invoke

Invoke allows a function to be applied to all members of an array, and returns the results. Using our animals object from above:

var describeAnimal = function(animal) {
  return String.format(&quot;{0} is a {1}&quot;, animal.name, animal.species);
}

var describedAnimals = Ext.invoke(animals, describeAnimal);
console.log(describedAnimals); // ['Ed is a Unknown', 'Bumble is a Cat', 'Triumph is a Insult Dog'];

Ext.invoke performs a similar job to Ruby’s collect method in making it easy to transform arrays. Any additional arguments passed to the Ext.invoke call will be passed as arguments to your function, in this case the describeAnimal function. Obviously your functions will be much more grammatically accurate than mine.

Ext.partition

Ext.Partition splits an array into two sets based on a function you provide:

var trees = [
  {name: 'Oak',    height: 20},
  {name: 'Willow', height: 10},
  {name: 'Cactus', height: 5}
];

var isTall = function(tree) {return tree.height &gt; 15};

Ext.partition(trees, isTall);

//returns:
[
  [{name: 'Oak', height: 20}], 
  [{name: 'Willow', height: 10}, {name: 'Cactus', height: 5}]
]

The partition call above returns a 2-dimensional array with the first element containing all of the items for which the function returned true (tall trees in this case), and the second containing items for which the function return false.

Math functions

Finally, we have some simple math-related functions:

var numbers = [1, 2, 3, 4, 5];
Ext.min(numbers); //1
Ext.max(numbers); //5
Ext.sum(numbers); //15
Ext.mean(numbers); //3

While the built in functions don’t cater for all situations, they’re useful to have and to know about, and usually offer a more elegant approach than using the ‘for’ keyword.

The case for Ext.applyOnly

** Update: Ext 3.0RC1 has included something like this, but called Ext.copyTo. Obviously my name is better though **

We should have something like this:

Ext.applyOnly(this, config, ['width', 'height']);

You could use this every time you write a method or class that requires a config Object as one of it’s parameters. These methods ought to only apply those properties of the config object they actually need, but usually this will just be done with an Ext.apply(this, config). This means anything in your object could be overwritten by this config object. Sometimes that’s a good thing, but sometimes it’s definitely not.

Ext.applyOnly() applies only a whitelist of the properties in the config object. These are specified by an optional third argument, which is an array of property names. Here’s how you might write applyOnly:

/**
 * Applies only a pre-specified set of properties from one object to another
 * @param {Object} receiver The object to copy the properties to
 * @param {Object} sender The object to copy the properties from
 * @param {Array} whitelist The whitelist of properties to copy (e.g. ['width', 'height'])
 * @return {Object} The receiver object, with any of the whitelisted properties overwritten if they exist in sender
 */
Ext.applyOnly = function(receiver, sender, whitelist) {
  if (receiver &amp;&amp; sender) {
    Ext.each(whitelist || [], function(item) {
      if (typeof sender[item] != 'undefined') receiver[item] = sender[item];
    }, this);
  };
  
  return receiver;
};

While you can’t stop code maliciously overwriting properties this way, it would stop people from unknowingly overwriting your object’s properties. They could overwrite them manually, but they’ll do this knowing that this wasn’t an intended use for the class. Let’s have a look at an extension that would do a great job opening popups telling people they’ve won lots of money:

/**
 * Pops up windows telling lucky visitor she's won big money!!!!
 */
Ext.ux.WinnerEarnings = Ext.extend(Ext.util.Observable, {
  /**
   * @property accessibleProperties
   * @type Array
   * All properties intended to be mass-updatable
   */
  accessibleProperties: ['height', 'width'],
  
  /**
   * Message to show lucky winners!! You can't change this!!!!!
   */
  message: &quot;You're the 1000000000000th visitor!!!!!!!1 Click here to claim money. Now!!!&quot;,
  
  constructor: function(config) {
    //apply only the fields that are deemed writable
    Ext.applyOnly(this, config, this.accessibleProperties);
    
    Ext.ux.WinnerEarnings.superclass.constructor.apply(this, arguments);
    
    Ext.applyIf(this, {
      version: 2.9,
      coolFeature: Ext.util.TaskRunner({
        interval: 1000,
        scope:    this,
        run: function() {
          //version, coolFeature, updateDetails, closable and close won't be sent to Ext.Window
          new Ext.Window(Ext.applyOnly({}, this, ['height', 'weight', 'message'])).show();
        }
      }).start()
    }
  },
  
  /**
   * Updates this WinnerEarnings opportunity with options from the supplied object
   * @param {Object} updates An object containing updates to make to this precious opportunity
   * @return {Ext.ux.WinnerEarnings} The WinnerEarnings object
   */
  updateDetails: function(updates) {
    return Ext.applyOnly(this, updates, this.accessibleProperties)
  },
  
  //secret tricks to let the user stop the popups
  closable: false,
  close: function() {
    this.coolFeature.stop();
  }
})

How it works:

var myObj = new Ext.ux.WinnerEarnings({height: 200, width: 150});

myObj.updateDetails({width: 300, message: &quot;My Message&quot;})
myObj.width:   // =&gt; 300
myObj.message; // =&gt; &quot;You're the 1000000000000th visitor!!!!!!!1 Click here to claim money. Now!!!&quot;

//updating message didn't work, but we can still do it manually
myObj.message = &quot;My message&quot;;
myObj.message; // =&gt; &quot;My message&quot;

In my example class I’ve added the whitelist as an accessibleProperties property on the class, which makes it easy for others to see what they should and should not be updating.

In this example we’re also sanitizing output with applyOnly. WinnerEarnings lightly wraps around a series of Ext.Windows and we’d like to be able to pass our WinnerEarnings object as config. We want to make sure we’re not passing our ‘closable’ property, ‘close()’ function and others to the Ext.Window constructor, so we pass that in via a whitelist too, inside the run() function in our constructor.

Check out the unit tests
for the function to see a couple more use cases. Here’s one final example – sanitizing output from a function:

myFunction = function(input) {
  //do some stuff to make input useful
  
  //guarantee our returned object only has relevant properties
  return Ext.applyOnly({}, input, ['important-thing-1', 'important-thing-2']);
}

Force Ext.data.Store to use GET

Say you have a simple Ext store:

var myStore = new Ext.data.Store({
  url:    '/widgets.json',
  reader: someReader
});

Which you put in a grid, along with a paging toolbar:

var myGrid = new Ext.grid.GridPanel({
  store:   myStore,
  columns: [.....],
  bbar:    new Ext.PagingToolbar({
    store: myStore
  })
  ... etc ...
});

Your grid loads up and the store performs a GET request to /widgets.json, which returns your widgets along with a total (see an example).

Awesome, but now we click one of the paging buttons on the PagingToolbar and we have a problem – our request has turned into POST /widgets.json, with “start=20” and “limit=20” as POST params.

Now we don’t really want that – we’re not POSTing any data to the server after all, we’re just trying to GET some. If you’re using a nice RESTful API on your server side this may cause you a real problem, as POST /widgets will likely be taken as an attempt to create a new Widget.

Luckily, as with most things the solution is simple if you know how. An Ext.data.Store delegates loading its data off to an Ext.data.DataProxy subclass. By default your store will create an Ext.data.HttpProxy using the url: ‘/widgets.json’ you passed in your store config. To make sure your stores are always requesting data using GET, just provide a proxy like this:

var myStore = new Ext.data.Store({
  proxy: new Ext.data.HttpProxy({
    url:    '/widgets.json',
    method: 'GET'
  }),
  reader: someReader
});

Adding a loading mask to your ExtJS application

Adding a loading mask like the one on the ExtJS API application is a nice way of showing the user that something is happening while their browser downloads the source code. It’s also extremely easy to do.

First, place the following HTML above all of your javascript include tags, ideally just after the <body> tag:

&lt;div id=&quot;loading-mask&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;loading&quot;&gt;
  &lt;div class=&quot;loading-indicator&quot;&gt;
    Loading...
  &lt;/div&gt;
&lt;/div&gt;

If you are currently including javascript files inside the <head>, don’t – put them at the bottom.

With a bit of CSS (see below), this provides a white mask over all underlying content, and a loading message. When everything has loaded, remove the mask like this:

Ext.onReady(function() {
  setTimeout(function(){
    Ext.get('loading').remove();
    Ext.get('loading-mask').fadeOut({remove:true});
  }, 250);
});

The above simply fades out the HTML elements to reveal the now ready page. The setTimeout call gives your app a little time to render, which is useful if you’re doing something like pulling external content down from the server.

Finally, here’s the CSS I use to style up the loading mask. You’ll need to download a loading image and stick it in the appropriate directory.

#loading-mask {
  position: absolute;
  left:     0;
  top:      0;
  width:    100%;
  height:   100%;
  z-index:  20000;
  background-color: white;
}

#loading {
  position: absolute;
  left:     50%;
  top:      50%;
  padding:  2px;
  z-index:  20001;
  height:   auto;
  margin:   -35px 0 0 -30px;
}

#loading .loading-indicator {
  background: url(../images/loading.gif) no-repeat;
  color:      #555;
  font:       bold 13px tahoma,arial,helvetica;
  padding:    8px 42px;
  margin:     0;
  text-align: center;
  height:     auto;
}

Why you should be using History in your ExtJS applications

I’ve been making a few updates to the ExtJS API documents application recently. The actual updates include remembering which tabs you have open and using Ext.History to go between tabs (you can follow the forum post or see a beta version).

That’s not quite ready yet, but what has been made very clear to me is that any ExtJS application with more than one view should be using Ext.History. With History we get urls inside the application itself, we can parse them and dispatch accordingly. For example, I’m using a Rails-like Router, which lets you define an internal url map like this:

map.connect(&quot;:controllers/:action/:id&quot;);
map.connect(&quot;:controllers/:action&quot;);

The router knows how to decode urls based on the regular expression-like syntax above, and parse the matches into an object – for example:

#users/new    &lt;= becomes {controller: 'users', action: 'new'}
#users/edit/2 &lt;= becomes {controller: 'users', action: 'edit', id: 2}
#colours      &lt;= becomes {controller: 'colours'}

You can of course define any url matching scheme using the connect() function. I then use a simple Dispatcher, which looks at the decoded parameters. It finds the appropriate controller and calls that action on the controller, passing any other parameters as arguments. For example:

#users/new      &lt;= calls UsersController's &quot;new&quot; action
#colours/edit/2 &lt;= calls ColoursController's &quot;edit&quot; action, with {id: 2} as the argument

And so on. Each controller knows what to do for that action. It’s easy then to say to someone “go to http://myapp.com/admin#users/152/comments&#8221; – which will take them straight to the comments that user 152 has written. Compare that with saying: “go to http://myapp.com/admin, then click the List Users tab, then find the user called Joe Bloggs, then double click the bubble icon next to his name”. It’s obvious which approach is better.

You don’t even need to use something as elaborate as a router, just a simple switch statement or some regular expressions would be enough for many applications. Once you’ve got Ext.History setup, you could do something as simple as:

//decodes a url and decides how to dispatch it
dispatch = function(token) {
  switch (token) {
    case &quot;users&quot;    :   displayUsers();   break;
    case &quot;users/new&quot;:   displayNewUser(); break;
    case &quot;users/2/edit: editUser(2);      break;
    default:            displayDefault(); break;
  };
};
Ext.History.on('change', dispatch);

//Call dispatch on initial page load as Ext.History's change event is not fired here
Ext.History.init(function() {
  var token = document.location.hash.replace(&quot;#&quot;, &quot;&quot;);
  dispatch(token);
});

Obviously you don’t hard code user IDs like that but it’s easy to see how to roll your own. With just a few lines of code, you’ve decoded a url into a function to call, which can do anything you need it to. All your internal navigation needs to do is call Ext.History.add(“some/new/url”), which will now be picked up by your dispatch code.

It’s important to only route like this for idempotent actions (i.e. actions which display data rather than change it), so that data changing actions are not repeated. This is equivalent to using GET and POST correctly in normal web applications.

When the simplest implementation takes just a few lines of code, what reason could there be not to be using it?

ExtJS Solitaire

Update: We recently released the updated Touch Solitaire for Sencha Touch.


For a bit of fun over Christmas I thought I’d try my hand at writing Solitaire using the ExtJS library. The results of my efforts can be seen over at http://solitaire.edspencer.net.

It’s reasonably complete, with the familiar drag and drop moving of cards (and stacks of cards). Most of the interface is custom built, with classes representing Cards, Stacks, the Pack, etc. The main motivation for creating this is to give a real-world example of using Drag and Drop with Ext JS, as documentation for it can be hard to come by. The full source of the game can be found on github, and I encourage people to take a look at and/or improve the code if they wish.

A few stats: the game comes to 1300 lines of code, including generous comments and whitespace. It’s 15k minified, and uses a custom Ext build. It took roughly 25 hours to put together, which was mostly spent researching how to use Ext’s many D&D classes.

The reason I’m releasing it now is that I’m currently working on a much larger, more exciting open source ExtJS project which I want to concentrate on before releasing. If anyone wants to pick this up feel free to fork the code on Github or get in touch in the comments or in #extjs on IRC.

%d bloggers like this: