Higher Order Blog


Extending Ext.data.Record to support inheritance for domain types

18 Mar 2008

As I've previously blogged about, the JavaScript framework ExtJS provides an excellent support for developing models in Controller-Model-View architectures in web-browser client applications. One of the tools Ext provides is the function Ext.data.Record.create: using this one can easily create constructor functions for domain concepts. For example, in our room-booking application, TriBook, we defined a Reservation type concisely like this:
com.trifork.tribook.model.Reservation = Ext.data.Record.create([
       {name: 'start_at', type:'date', dateFormat:'d/m/Y-H:i'},
       {name: 'end_at', type:'date', dateFormat:'d/m/Y-H:i'},
       {name: 'room'}
That is: a Reservation object has 'start_at' and 'end_at' Date properties as well as a 'room' property (which refers to a 'Room' domain object, defined of course using Ext.data.Record.create). One point made in a previous article is that Ext.data.Record.create returns a JavaScript constructor function for the defined domain concept. This means that we can add domain logic to our domain types by augmenting their prototypes, e.g.,
Ext.apply(com.trifork.tribook.model.Reservation.prototype, {
     isPreLunchReservation: function(){//just an example...
         var sh = this.get('start_at').getHours(),
             eh = this.get('end_at').getHours();
         return 6 < sh && eh < 11;//must end before noon...
This is all very useful, particularly because Ext.data.Record objects are supported by a bunch of other Ext functions, as discussed previously. However, there is no built-in support for inheritance in domain concepts. For example, suppose that we like to create a sub-type of our reservation domain type: a RecurringReservation, which one can use e.g., to reserve a room the same time each week. It would be nice to be able to write the following:
var m = com.trifork.tribook.model;
m.RecurringReservation = Ext.data.Record.extend(m.Reservation, [
      {name:'interval', type:'string'}//can be 'daily','weekly', 'monthly' or 'yearly'
var rr = new m.RecurringReservation({
           room:room_ref,//assuming room_ref refers to a m.Room object.
           interval: 'weekly'
Now, the object referred to by 'rr' should have all the specified state, and all the domain logic of Reservation should be inherited, e.g., 'isPreLunchReservation' also works for RecurringReservation objects. The following is an Ext extension that makes the above snipplet work:
Ext.data.Record.extend = function(sp,fields){
        var sb = Ext.extend(sp,{}),
            sb_f = sb.prototype.fields.clone(),
            Field = Ext.data.Field,

        for (i=0,N=fields.length; i<N; i++) {
                sb_f.add(new Field(fields[i]));
        sb.prototype.fields = sb_f;
        return sb;