Sencha Inc. | HTML5 Apps

Blog

Deft JS: Loosely Coupled MVC through Dependency Injection

May 14, 2012 | John Yanarella

Guest Blog Post: John Yanarella of Universal Mind

DeftJS

That application you just deployed? As experienced software developers, we all know it won’t be long before you’re going to need make to significant UI changes. Regardless of the amount of painstaking forethought, consensus gathering and planning backing it, no software design ever survives first contact with its users unscathed. To deliver truly effective software, we have to be prepared to adapt to an evolving understating of our users’ needs.

So… how do we architect our software, so we can rapidly implement UI changes without breaking the underlying business logic?

Model View Controller (MVC)

It starts by applying structure to our code, separating it into manageable units where each is responsible for a specific application concern. To this end, most software applications employ the Model View Controller architectural pattern. There are a wide variety of implementations of this pattern; software development pundit Martin Fowler has catalogued many of those variations here.

Typically, with an MVC architecture, the:

  • Model describes and manages application domain data behaviors and state, and responds to requests to retrieve or persist changes to that state.
  • View presents model data to the user, accepts user input, and announces high-level user gestures such as clicks or selection changes.
  • Controller mediates between the model and view, listening for user gestures to initiate actions on the Model, and instructing the View to reflect Model changes.

By separating the user interface components and layout (the View) from the logic that observes corresponding user gestures (the Controller) ands triggers business logic or changes to application domain data (the Model), your application is better positioned to adapt to inevitable changes.

Deft JS MVC

Deft JS enhances the Model View Controller (MVC) within Sencha Frameworks, where the:

  • Model is expressed using ‘faceless’ business logic components, such as Ext.data.Store and Ext.data.Model.
  • View is realized using any of the rich suite of Ext JS or Sencha Touch containers and components.
  • Controller is implemented by creating view-specific controllers that extend the Deft.mvc.ViewController class.

Deft JS View Controllers

Consider a view to be a composition of multiple components in a container. A View Controller is a lightweight controller responsible for managing the state of a specific view and its child components, listening for events dispatched by the view and its child components in response to user gestures, and delegating work to injected business models and services (such as Ext.data.Stores, Ext.data.Models, etc.).

With Deft JS, a view is typically a subclass of an Ext JS container class, populated with component items. The view is configured to use the Deft.mixin.Controllable mix-in, and annotated with the class name of the associated View Controller. For each view, you would create a corresponding View Controller class that extends Deft.mvc.ViewController. This view-specific view controller would be configured to reference relevant view components and register view controller methods to handle view component events.

The Deft JS View Controller and Controllable mix-in:

  • Provide class annotation driven association between a given view and its view controller
  • Clarify the role of controller classes – i.e. controlling a specific view
  • Support multiple independent instances of a given view, each with its own unique view controller instance
  • Reduce memory usage by automatically creating and destroying view controllers in tandem with their associated views
  • Offer concise configuration for referencing view components and registering event listeners with view controller methods
  • Integrate with the view destruction lifecycle to allow the view controller to potentially cancel removal and destruction
  • Simplify cleanup by automatically removing view and view component references and event listeners

Deft JS Dependency Injection

Most model, view and controller objects are not self-contained; they reference and delegate some of their work to other objects; these objects are referred to as dependencies. Typically, you might explicitly create instances of these dependencies or manually request them from a service locator.

To encourage loose coupling between application components, Deft JS includes a lightweight Inversion of Control (IoC) container for dependency injection. When applying the principal of Inversion of Control, you annotate your class with a list of its dependencies instead of manually creating or obtaining them. When your class is later instantiated, the IoC container is then responsible for resolving those dependencies with the correct object instances, injecting those values into your class at runtime.

With IoC, your class is no longer responsible for creating its dependencies or knowing where its dependencies are defined. Further, it is no longer bound to a specific implementation of a dependency. Provided it offers the expected API, you can configure the IoC container to inject a totally different implementation.

Consequently, you can easily test your classes in isolation by configuring the IoC container with mock versions of any dependencies. You can also create multiple variants of your application, where the IoC container in each is configured to use different implementations of shared dependencies such as Stores or Proxies; one might be configured to use mock Stores and Proxies driven by static JSON files, and another configured to use Stores and Proxies that access production services via JSONP.

The Deft JS IoC Container and Injectable mix-in:

  • Provide class annotation driven dependency injection
  • Map dependencies by user-defined identifiers
  • Resolve dependencies by class instance, factory function or value
  • Support singleton and prototype resolution of class instance and factory function dependencies
  • Offer eager and lazy instantiation of dependencies
  • Inject dependencies into Ext JS class configurations and properties before the class constructor is executed

Example

Imagine a view within a Contact Manager application containing a grid of contacts:

Ext.define( 'ContactsApp.view.ContactGridView',
    extend: 'Ext.container.Container',
    mixins: [ 'Deft.mixin.Controllable', 'Deft.mixin.Injectable' ],
    inject: [ 'contactStore' ],
    controller: 'ContactsApp.controller.ContactGridViewController',
 
    config: {
        contactStore: null
    },
    ...
    initComponent: function() {
        this.items = [{
            itemId: 'contactsGrid',
            xtype: 'gridpanel',
            store: this.getContactStore(),
            ...,
            bbar: Ext.create( 'Ext.PagingToolbar', {
                store: this.getContactStore(),
                ...
            })
        },
        ...
        {
            xtype: 'container',
            ...
            items: [{
                itemId: 'editButton',
                xtype: 'button',
                text: 'Edit'
            }],
            ...
        }];
    }
);

This view class is configured to be injectable, using the Deft.mixin.Injectable mix-in, and its dependencies are described using the ‘inject’ class annotation.

When this view is instantiated via either Ext.create() or Ext.widget(), the IoC container will resolve the ‘contactStore’ dependency and inject the associated value into the ‘contactStore’ configuration. The generated getContactStore() accessor function will return that injected value.

Additionally, this view class is configured to be controllable, using the Deft.mixin.Controllable mix-in, and its controller is specified using the ‘controller’ class annotation.

When this view is instantiated, an instance of the specified view controller class will also be created and configured with a reference to the view. When the view is destroyed, the view controller will also be destroyed.

Ext.define( 'ContactsApp.controller.ContactGridViewController',
    extend: 'Deft.mvc.ViewController',
    mixins: [ 'Deft.mixin.Injectable' ],
    inject: [ 'contactStore' ],
 
    config: {
        contactStore: null
    },
 
    control: {
        contactsGrid: {
            click: 'onContactsGridClick'
        }
        editButton: {
            click: 'onEditButtonClick'
        }
    },
    ...
    destroy: function() {
       if (this.hasUnsavedChanges) {
           // cancel destruction
           return false;
       }
       // allow destruction
       return this.callParent( arguments );
    },
    ...
    onEditButtonClick: function () {
        this.getEditButton.setDisabled( false );
    },
 
    onContactsGridClick: function () {
        // add a ContactEditorView to the TabPanel for the selected item
        ...
    },
);

This view controller extends the Deft.mvc.ViewController abstract base class, which provides a ‘control’ configuration that simplifies the creation of view component accessors and registering view component event listeners.

In this example, the grid and button are referenced implicitly by their itemId (custom selectors are also supported) and their ‘click’ events are configured to be handled by corresponding view controller methods. Two accessor functions will automatically be created: getContactsGrid() and getEditButton(). When the view is destroyed, the view controller's destroy() method will be called, allowing it to cancel view destruction. If this method returns true, the view will be destroyed, and all references and event listeners created in the view controller using the ‘control’ configuration will automatically be removed.

The IoC container is typically configured in the main application JavaScript file, within Ext.onReady(), using the Deft.Injector.configure() method.

Ext.onReady( function () {
    Deft.Injector.configure({
        contactStore: 'ContactsApp.store.ContactStore'
        // contactStore: 'ContactsApp.store.MockContactStore'
    });
});

In this example, the Deft JS IoC container has been configured to fulfill all requests for ‘contactStore’ with a singleton instance of ContactsApp.store.ContactStore. The commented line shows how simple it would be to specify a mock class instead.

About Deft JS

Deft JS is an MIT-licensed open source framework that extends the Ext JS and Sencha Touch APIs to provide:

  • Loose-coupling and dependency injection via an Inversion of Control (IoC) container
  • Flexible component-oriented architecture through an alternative Model View Controller (MVC) implementation
  • Elegant asynchronous operation chaining and data processing using Promises and Deferreds

Created by a team of software architects working at the innovative digital solutions agency Universal Mind, Deft JS leverages best practices and proven patterns refined over years of delivering cutting edge solutions across a wide range of platforms and devices.

Written by John Yanarella
John Yanarella is a Principal Architect at Universal Mind, an innovative digital solutions agency that fuses the design capabilities of an interactive firm with the the technical expertise of a systems integrator. He is passionate about breaking complex problems down into simple reusable solutions; he created Deft JS and has been a principal author and contributor to several other commercial and open-source frameworks. Follow John on Twitter @johnyanarella.

Share this post:
Leave a reply

There are 37 responses. Add yours.

Grgur

3 years ago

Sweet! Can’t wait to get my hands dirty with it

K.

3 years ago

The view controller stuff was exactly was I was searching for.
When I split my app into modules, it would be nice to just put an xtype of a module-view into the main app and it gets loaded automagically with it’s needed controller.

Flexodus

3 years ago

For those who are just getting started in DI, it would be very helpful to show the equivalent code without DI so they can see the benefits.

Ben Hornedo

3 years ago

Very good stuff. Great work John!

Axel

3 years ago

boom! nice!

Ozzy

2 years ago

This looks like it might be a big help to build real applications with extjs.  Do you have a real world example that demonstrates this architecture in action?  It would be useful to see an example that puts it all together.

Andrei Ionescu

2 years ago

I subscribe to Ozzy’s request. Are there any real world examples that can be used?
A blog post is barely enough to base the entire architecture of an application upon.

Thnx.

H.W.

2 years ago

How does “Error Handling” fit into the scheme with DeftJS? I couldn’t find any working example for one of the followings:
- handling in the client of the serverside errors - e.g. SQL exceptions, other serverside exceptions that affect one of the ajax requests, or simply not acceptable delays.
- handling in the client of the transport/communication errors (and maybe too big delays - timeout just does not do it).
- general exceptions (catch/try/rethrow - but how and where).

Thanks in advance.

magdy a aboud

2 years ago

I want to buy the Ext JS 4.1 software to use it with vb.net asp.net
I need an example about how to use ext-4.1 => menu bare With vb.net2008 asp.net And write code to open deferent forms - from the vb.net default form after adding the java screpte file and the css file to the project

Best Regards

anon

2 years ago

Have you looked at AngularJS, it looks a lot more elegant than DeftJS, does far more with less, and has an underlying philosopy very similar to Flex…it almost makes HTML work like MXML

Tony Steele

2 years ago

To anon - is this appropriate , tons of mvc frameworks around, this unique as it enhances ExtJs.

Otherwise, try to quickly get it to work within my existing application , did not succeed, would help alot if you had a simple working example included in the code, a window with Hello World would help.

Tony Steele

2 years ago

Just spotted this:

http://www.briankotek.com/blog/index.cfm/2012/5/8/Exploring-ExtJS-with-DeftJS

Includes a downloadable application, will give it a try.

Rich02818

2 years ago

Is there a commercial license available so that this might be usable in a commercial product?

Babar

2 years ago

Looks good but its very hard to use it without any examples I am trying to load controllers dynamically but unable to do, I have no idea how can I use it.

Fredric

2 years ago

@Babar
Here is another approach:
https://github.com/Fredric/ExtJS-Multiple-MVC
Gives you the ability to specify a control array on any view.

Just clone the stuff right into the sencha example folder.

Troy Rose

2 years ago

What sort of safe guards have been put around the security of the framework, eg, SQL Injection and so forth.

Other than my concerns about that, I think it looks very promising and will have to give it a go!

Troy
http://www.osisecurity.com.au

carlacurtis218

2 years ago

This is a great information… Thanks for sharing!

Ozzy

2 years ago

is this project dead??  No responses from the owner(s) in a month.  Without a viable community there isn’t much point in pursuing this framework.

John Yanarella

2 years ago

Ozzy,

Deft JS is only a couple months old and currently in beta.  We’re actively using it ourselves to deliver work for clients, but I’m sure you can empathize with the fact that we have to keep a roof over our heads and those projects have deadlines.  Sadly, community support and evolution of the documentation for the framework itself is not our day job.  As an MIT licensed open-source project, Deft JS is a gift to the Ext JS development community that originates from what spare hours are available in our nights and weekends.

We have a vision for what Deft JS will be and are actively pursuing it.  We are very excited that Deft JS has already attracted as much interest as it has so early on in its life.  In its current form, it already pushes the envelope for the kinds of applications you can build and deliver with Ext JS and Sencha Touch.  We have more surprises in store.  You ain’t seen nothin’ yet.

But in the meantime… we are working to move the core framework out of beta into version 1.0.  This effort includes addressing key concerns that early users have reported, documenting and implementing tests for Deferreds and Promises (a feature of Deft JS not discussed here), improving documentation overall, developing meaningful examples, migrating to Sencha-style documentation (using JSDuck), and creating a revised project website (to replace the dressed-up README.md we have there currently).

No small order.  But we’re up to the task.  You just might have to wait a little while longer.

We are grateful that Sencha provided us this opportunity to announce the project to their community of developers via this blog.  The response has been extraordinary and overwhelmingly positive, and the feedback has been immensely useful.  We are excited that developers across the globe are already using this framework to build web and mobile applications.

We are even more excited that developers like Brian Kotek, Jacob Henry, Rowan Crawford, Josh Nesbit, Isaac Johnston and others have filed bug reports, offered suggestions and even contributed code to improve this project.  Deft JS is an open-source effort, and as such thrives by community contribution.  We’re excited that an active, contributing community is already emerging around this project.

Since this guest blog was posted here we have released multiple updates to the framework addressing issues filed on GitHub or discussed on our Google Groups forum.

You might be interested in the Deft JS Google Group:

  http://groups.google.com/group/deftjs

We manage our project on GitHub:

  https://github.com/deftjs

There you can find our latest source code and development branches, as well as file bug reports and track their progress.  We’ve closed several issues and have multiple enhancements scheduled for upcoming releases.

https://github.com/deftjs/DeftJS/issues

Brian Kotek was kind enough to create and share a small example application on his blog:

  http://www.briankotek.com/blog/index.cfm/2012/5/8/Exploring-ExtJS-with-DeftJS

While I wish we were able to provide you with a large-scale example application today, we are currently unable to do so.  If I gave you the code for the intranet applications I’m developing currently for my employer’s clients, I suspect I’d end up with a lot more time to develop Deft JS but a much tougher time paying my bills.  That said, we are aware that meaningful examples will be critical to ensure Deft JS’s long-term success and they are slated to be available as soon as we possibly can build them.

Best regards,

John

John Yanarella

2 years ago

I apologize that we have not been more responsive to questions posed in the comments on this blog.

A few of the questions here relate to Ext JS rather than Deft JS.

Rich02818:

Deft JS extends Ext JS with an IoC container for dependency injection, an ViewController-based MVC implementation and Promises/Deferreds.  It is open-source and licensed under the very permissive MIT license.  Feel free to contact me directly if you need alternative licensing terms. 

While you can freely use Deft JS within a commercial product under those terms, Ext JS itself is separately licensed.  You can refer to this page: http://www.sencha.com/products/extjs/license/ to learn more about their licensing terms.  Sencha Touch is offered under a different licensing model: http://www.sencha.com/products/touch/license/.

magdy a aboud:

Your questions relate to Ext JS rather than Deft JS.  You might try their support forums: http://www.sencha.com/forum/

John Yanarella

2 years ago

anon:

As a fellow Adobe Flex refugee, I’ve found both frameworks to be exciting alternatives in the HTML space.  I’ve used both Angular JS and Ext JS and my preference for a given project would vary based on the complexity of the UI and associated UI componentry required.  For single page applications with a desktop application style experience, with menus, trees, grids, etc. there is no question Ext JS is a clear winner.  I recently participated in the development of a proof-of-concept application of that type that took 6 weeks (each for two developers) to develop in Angular JS that I was able to rewrite in 3 days with Ext JS and Deft JS.  I love Angular’s MVVM implementation and transparent binding (its a beautiful implementation), however reinventing common UI component and adapting third-party components as directives is only viable when you only need a couple rich UI components that are outside the standard HTML suite of controls.  Ext JS provides a rich suite of components with consistent APIs, implemented in an OOP fashion for easy extensibility. Deft JS brings an Ext JS-style implementation of the few key Angular JS features that Sencha’s frameworks lacked, such as an IoC container for dependency injection, view-scoped controllers and Promises/Deferreds.

Mikhail Tatsky

2 years ago

Yes it is quite interesting.
DeftJS reminds me backbone.js

I also did my own js framework on Ext Core and some extentions from ExtJS.
It is here http://mtjs.org
It is ixtremely fast.

If I have sponsor that could supply my work during 8-16 month I would finish it up and get the world leading framework.
I would like implement UI like these
http://dribbble.com/shots/512508-Notifications
http://www.moreira.ch/
http://vectormill.com/

Moshe Flam

2 years ago

For internationalization - its usually not just the words being translated, but - in the case of BIDI languages like Hebrew, Arabic and Chinese, the controls are different for accepting text from right to left, spacers and layouts are different and there may even be expected differences in app behavior…

Would you recommend using this for internationalization?

John Yanarella

2 years ago

Moshe, It’s interesting that you ask that.  Someone on the Deft JS mailing list has been asking for some assistance in loosely coupling his view references (and his particular use case may well require a small enhancement to the framework to make it fully viable - we’re working through it).

You could potentially loosely couple your view references by configuring the IoC container to resolve alternative concrete view implementations for BIDI vs non-BIDI.  However, you’ll lose a lot of the elegant expressiveness of the alias-based JSON-esque component descriptors used throughout Ext JS (such as with the Container.add() method and `items` configuration).  That approach costs you quite a bit of convenience when it comes time to create the view instances.  Unless you need to create and show different localized versions of views and have them visible at the same time within an application, I’d take another route.

Instead, I’d consider creating alternative localized implementations of each of your views, packaging each set of localized views into locale-specific auxilliary JavaScript files (loaded separately from Ext JS and the rest of your app), but using the same aliases across locales.  Once you determine the user’s desired locale, you would load the file with the appropriate localized view implementations.  If the fields and underlying logic themselves are the same, you could potentially even use the same Deft JS ViewController across various localized view implementations.

Additional capabilities explicitly designed to aid internationalization are on the Deft JS roadmap, but they are not currently scheduled to be part of the 1.0 release.

Neil

2 years ago

In Sencha’s controllers, I have a reference to application. I have been using this to fire and listen to app-wide events.

How do I do this using Deft? Thanks!

sexy summer

2 years ago

But the station is yet to be resolved, JS, or chaos, and why. .
http://sexylingerietalk.blog.com/

Mauro Silva

2 years ago

Hi,
Sorry about my question, but I want to Know, if I can use (and make sense) Deftjs with RoutedApp (https://github.com/christocracy/RoutedApp)?
Thanks

Shay Katz

2 years ago

Hi,

I have a container(my view) that contains a form that contains some items.
It it possible to inject(using the control annotation) some of the items(e.g : the submit button) that reside inside the form?

Thanks,
Shay

Sebastien Tardif

2 years ago

I don’t see how having a view hardcoding the controller concrete class is an improvement. I think we are trying to solve problem that doesn’t exist. YAGNI.

Andrei I.

2 years ago

This all looks very nice and interesting, however from my point of view there are a few things I couldn’t figure out:
1.How is this simpler than the ExtJS MVC? That one is already overly complicated and many users don’t use it since it brings more problems than it tries to solve.
2.How to use it with Ext Designer or Sencha Architect? If the users generate(and update) allot of their code with those two Sencha products, how to integrate DeftJS in the scheme? The tools allow to edit code manually at some points, but those are restricted (to be able to update), so where does the DeftJS code fit in?
3. As other users already mentioned, what about exception handling? I found no really good example how to do it consistently in the entire application with or without DeftJS :(.

John Yanarella

2 years ago

Mauro,

I haven’t tried integrating with Ext.ux.RoutedApp, but I can’t think of any reason why it shouldn’t work.  You could potentially omit the controllers configuration and use Deft’s ViewControllers (or use both if you’d also like to use view-less application-level controller).  As with integrating with Ext.app.Application, I would recommend configuring your IoC container in Ext.onReady() rather than in RoutedApplication::launch() because any controllers, stores specified via the ‘stores’ or ‘controllers’ configs will be instantiated in the constructor before your launch method is called.  Otherwise, any dependencies those controllers or stores might have will not be fulfilled because the IoC container will not have been configured yet.

Mauro

2 years ago

Thanks John

Neil

2 years ago

@Andrei

Q: 1.How is this simpler than the ExtJS MVC? That one is already overly complicated and many users don’t use it since it brings more problems than it tries to solve.

A: Ext controllers are weird in that you have one controller but multiple views. This means you should never store a reference to the view, making the whole refs feature useless. The Deft controllers are one controller per view instance, meaning you can store state in the controller if you want. It’s much less work to create a getter for a view sub-object and to handle its events.

John Yanarella

2 years ago

Sebastien,

You might well not need it. We definitely do not advocate Deft JS as the one-size-fits-all solution to all web interactivity - in some cases it might be overkill. It is best suited for large scale single page applications where the UI is significantly dynamic. View Controllers allow a separation between the definition of the view, and the underlying logic for coordinating the state of subcomponents of that view and subsequent delegation of work to business logic components. They are not an invention of Deft JS, and similar implementations can be found in most modern application frameworks. For larger applications with dynamic user interfaces, this separation of responsibilities can be critical for developing a manageable and maintainable code base.

John Yanarella

2 years ago

Andrei,

1) Looks like Neil already pitched in with a great answer here.  Thanks, Neil!

2) Unfortunately, Sencha Architect does not currently support Deft JS.  I’m not sure Deft JS even existed at the time they began development of that tool.  Feel free to let Sencha know you’d be interested in seeing support for Deft JS and other third-party libraries in future releases of Sencha Architect.  We’d love to see this, too.

3) What kinds of exceptions are you interested in dealing with?  One of the other tentpole features of Deft JS (not discussed in this article) is Deferreds / Promises.  This feature allows developers to write methods that return a placeholder for a future value, and chain multiple asynchronous operations and transform their results into that resultant value using very natural syntax.  Included among those capabilities is the ability to handle and recover from an error that occurs within a chain of asynchronous operations. This portion of Deft JS is still in development, but you’ll be hearing a lot more about it soon.

John Yanarella

2 years ago

For those wondering, Neil’s question about injecting a reference to the application was answered here:

https://github.com/deftjs/DeftJS/issues/21

Vidon

2 years ago

Good Post, Good Job!

Comments are Gravatar enabled. Your email address will not be shown.

Commenting is not available in this channel entry.