It's been quiet here on Ye Olde Blogg lately. I've spent the last few months trying out various HTML component libraries and JavaScript frameworks, and have finally selected what I think is the most promising combination: ExtJS with DeftJS.

Anyone reading this is probably familiar with ExtJS, so I won't bore you with details on it. Suffice to say that its UI library rivals what is available in Flex, and indeed is better in many ways. (Data grids and trees, anyone?)

The main thing that initially bothered me about ExtJS was its MVC implementation. In my opinion it has a several flaws, one being the service locator approach. Another is that controllers use selectors that are relative to the application container to reference views, which isn't very flexible.

So I was pleased to see John Yanarella's contribution to the Sencha blog unveiling DeftJS. This is an extension to ExtJS which adds an inversion of control container and an improved controller tier through the use of ViewControllers.

I decided to try creating a DeftJS version of the car store example application that Sencha outlines in the documentation. What follows is a quick overview of the results.

Configuring the IoC portion of DeftJS is straightforward. Here, I'm specifying the two classes I want to add to the IoC container:

Ext.onReady( function () {
    Deft.Injector.configure({
        carChartJson: 'carStore.store.CarChartJson',
        carDataJson: 'carStore.store.CarDataJson'
    });
});
		

Next, I inject these into my view, and provide the ViewController class that I want to manage the view. This allows DeftJS to create the associated ViewController at the same time the view is created, and to destroy it when the view is destroyed.

Ext.define( 'carStore.view.CarListings', {
    extend: 'Ext.panel.Panel',
    mixins: [ 'Deft.mixin.Controllable', 'Deft.mixin.Injectable' ],
    inject: [ 'carChartJson', 'carDataJson' ],
    controller: 'carStore.controller.MyViewController',
...
		

Finally, my simple ViewController looks like this:

Ext.define( 'carStore.controller.MyViewController', {
    extend: 'Deft.mvc.ViewController',
    mixins: [ 'Deft.mixin.Injectable' ],
    inject: [ 'carChartJson', 'carDataJson' ],

    control: {
        carGrid: {
            selectionchange: 'onCarGridSelectionChange'
        },
        carDetail: true,
        carChartPanel: true
    },

    config: {
        carChartJson: null,
        carDataJson: null
    },

    onCarGridSelectionChange: function( selectionModel, selections ) {
        var carDataModel = selections[0];
        this.getCarDetail().update( carDataModel.getData() );
        this.getCarChartJson().loadData( carDataModel.getData().quality );
    }

});
		

I'm specifying the ID values (carGrid, carDetail, and carChartPanel) of the view elements I want to obtain references to. If necessary, a component query selector can also be used here. Note that unlike a standard ExtJS controller, these are relative to the view being managed rather than relative to the root application container. However, just like an ExtJS controller I can attach event listeners to the view instances. In this case, I'm handling the grid's selectionchange event to update the detail and chart views for their selected car. Essentially, this is an implementation of the Passive View design pattern.

That about covers the more interesting bits of this application. Since it's based on a very simple example, the rest of the code is pretty standard ExtJS. I've uploaded a running version of the app, and have pushed the source to GitHub for anyone who wants a deeper look.

DeftJS seems like a great extension to ExtJS. Not only that, but looking at the source also re-kindled my interest in Jasmine and CoffeeScript. The Jasmine specs for DeftJS are quite illuminating from a learning perspective, and the whole DeftJS framework is actually authored in CoffeeScript before being compiled out to JavaScript. I'll take a deeper look at both of these in upcoming blog entries.

Comments Comments (8) | del.ico.us del.icio.us | Digg It! Digg It! | Linking Blogs Linking Blogs | 14256 Views

Related Blog Entries

Comments

  • # Posted By ilan | 5/21/12 6:44 AM

    Hi,

    your example fail with DeftJs 0.6.5.

    It would be great if you could fix it.

    Thanks
    Ilan

  • # Posted By ilan | 5/21/12 7:23 AM

    The solution was to use Ext.require for the store

  • # Posted By Brian Kotek | 5/21/12 9:43 AM

    Hi ilan, I'll have to check but as you can see from the running example, the code I put up works as-is, so I'm not sure what issue you ran into?

  • # Posted By ilan | 5/21/12 10:24 AM

    Hi Brian,

    there seems to be some differences in how DeftJs work in the current version (0.6.5).

    adding the following lines above Ext.onReady did the trick. I did not investigate this yet.

    Ext.require([
       'carStore.store.CarChartJson',
       'carStore.store.CarDataJson'
       ]);

    your example was a great ramp up for me. thanks!

  • # Posted By claude gauthier | 7/16/12 11:18 AM

    I test the example with Deft.js 0.67 and it works like a charm. Now, I made a little change to app.js, and the app worked just as well.

    /************* CODE BEGIN
    Ext.Loader.setConfig({
    enabled: true,
    paths: {
       'carStore': 'app'
    }
    });

    Ext.require('carStore.view.Viewport');

    Ext.onReady( function () {
    Deft.Injector.configure({
    carChartJson: 'carStore.store.CarChartJson',
    carDataJson: 'carStore.store.CarDataJson'
    });
    Ext.create('carStore.view.Viewport');
    });
    /******************* CODE END

    This works correctly, no need for the Ext.application portion. At least for this example :)

  • # Posted By kgbroce | 7/27/12 8:39 PM

    I implemented your example and was able to get it working with DeftJS version 0.6.7. Thanks for putting this together - it was really helpful.

    In the original (non-DeftJs) Car Store example, I added a 'viewready' event handler that automatcally selects the first row in the grid. In your version, I did the same thing in MyViewController. However, it seems the Store is not loaded when this event fires, so the following code generates an error:

    onViewReady : function( table, options ) {
       table.getSelectionModel().select(0);   
    }

    I changed 'eager' to true when calling Deft.injector.configure, however that didn't help.

    Also, I noticed that the 'render' and 'afterrender' event handlers don't fire when I add them.

    control : {
       carGrid : {
          selectionchange : 'onGridpanelSelectionChange',
          viewready : 'onViewReady',
          render : 'onRender',
          afterrender : 'onAfterRender'
          },

    I appreciate any help you can provide. Thanks again.

  • # Posted By KJ | 12/13/13 6:31 AM

    Hi there, I also had the problem recently on my own project using Deft where the store was never being loaded despite being in the store :[], configuration object. I had to set the singleton property in the store to true and then it started to work. I have no idea why this is the case because in my application without Deft I didn't have to do this.

    Any ideas?

  • # Posted By Brian Kotek | 12/13/13 3:11 PM

    Sounds like you have something else going on, but I really have no idea what it might be. I've used Deft on many projects now, and I've never had to force any of my Ext JS classes to singletons.