Some thoughts on Angular from an Extjs developers perspective

Up until now I have been blogging primarily on Extjs and maybe a few other tasks like Sql Server, SSIS, and Adobe forms. I’ve been using Extjs since the beginning of version 2 and have grown to really appreciate it for what it can do for a large project developed by a small Dev team. That said I’ve been cognizant of the fact that there are a lot of other frameworks taking off right now; but – and this is key – I am old enough to have seen a lot of ‘next big things’ start with a bang and slowly fade away. Would you believe that at one point the future of the internet was going to be Java applets? That said I could no longer ignore one of the more popular frameworks, Angular.js; and I have finished toying with the idea of rewriting one of the apps I work on using this framework and actually started the rewrite.

Full disclosure – I am only taking this path because the user interface is set to become more ‘dashboard / data display’ and less of what some would consider an ‘app’ – you know where people enter a lot of data and stuff like that. I don’t think you should try and recreate an Extjs app in angular unless you have to but that’s for another post. I also know it’s a fool’s errand to argue the merits of either as in the end they are mere tools so the focus here is to come at Angular with an Ext perspective and just point out the differences that I see and how I overcame them.

With that said here are the first things that I noticed when stepping into angular.

Setting up your application:

I am really used to using Sencha command and love the fact that it builds a standard application straw man if you will with just three short words (no not I love you) and a command line terminal. The closest thing I could find were the various ‘starter’ apps that exist on GitHub and a link in the Angular documentation so I took liberty with the ‘W’ in MVW (Model-View-Whatever) which angular tags itself as being and set up my structure to mirror what I would find in Extjs 5’s MVVM.

This has worked out well because our developers are used to seeing this structure. So I went with a partials folder and in this folder I placed subfolders that contained the view (.html file) the controller, and I created a factory named ‘DataFactory’ that handles the requests for the controller, if you are an Extjs 5 developer you could almost view this as the view model (https://docs.angularjs.org/guide/providers).

How can I achieve something like layout: border and a viewport?

One of the first things I did was look for something that would resemble a viewport with a west panel and a center panel – why? Simple, our users have been conditioned to the layouts found in Ext for over 6 years now so any drastic change would be met with resistance; I had to make small changes. I found what I was looking for with the ui-layout module which you can find here: https://github.com/angular-ui/ui-layout .

What about grids?

I love the Extjs grids and wanted to find something comparable in angular. The caveat here is that I rarely use all of the features like row locking, inline editing and so forth. I know all of that is possible but I just needed a paging grid with sortable columns, I would do a remote filter on the data but that is just a matter of connecting a function to a textbox above the grid. There are several to choose from but in the end I decided to use Lorenzo Fox’s Smart-Table module which can be found here: http://lorenzofox3.github.io/smart-table-website/

Right about now you should start seeing a pattern, mainly much of what you need to accomplish using angular requires third party plugins, or extensions if you will. That’s great for the flexibility – I love it. That’s not so great for standardization / documentation / and building something that will not become a nightmare to maintain. If you have a really keen eye you will have picked up something else, all of the plugins listed above assume that the user is building an application that will run on the latest browsers / there is often very little (read none) support for legacy browsers – so if you are in a large organization on a corporate site (read enterprise) then you probably want something like Extjs.

The next post in the list will take a look at how I handled a ‘store’ like function in Angular.js.

Getting data from Angular – how close is it to stores in extjs?

I like the two way data binding that Extjs brings to the table and the fact that I can declare stores in the view model so how would I access data in angular? Turns out Angular is also built on two way data binding so you could build a set of ‘stores’ rather easily. Here’s what I ended up doing. First, using Dan Whalen’s excellent blog post on restful services I built what I would call a DataFactory. My goal was to have this ‘Factory’ behave like a store proxy in extjs – so in short I wanted to create something that worked like the api{} below.

api : {
       read      : '/getSomething',
       update    : '/updateSomething',
       create    : '/createSomething',
       destroy   : '/destroySomething '
},

So, in angular I started my ‘store’ like this:


app.factory('DataFactory', function ($http, $q) {
  'use strict';
   return {

   };
});

The function above relies on two service providers, $http, and $q. The first service $http, is pretty self-explanatory, it’s what allows us to go out and asynchronously fetch data from the server and then bind it to a variable in the controller which in turn seamlessly updates the user interface. $q on the other hand is something that I did not encounter in Ext even though the singleton Ext.defer seems to allude to $q.defer(), they are very different. $q.defer() sets your promise up with three methods that will allow it to hang around and wait until something happens – or – you decide it’s not going to happen. Ext’s defer sets up a function to run after the clock decides that something should have already happened. I’ve seen a lot of errors based on miscalculation in the Ext.defer milliseconds parameter.

On to the get method:


app.factory('DataFactory', function ($http, $q) {
  'use strict';
  return {
     get : function (url, params) {
       var   deferred = $q.defer(),
             params = { params: params };

      $http.get( url, params )
     .success(function(response)  

    var data = angular.fromJson(response);

 // Expects {success:true, data:[ ....
        if(data.success){
         deferred.resolve( response );
        } else {
         deferred.reject( data.msg );
        }
    })
    // This is an http error
    .error(function(response) {
        deferred.reject( 'Http error status code ' + response.status );
 });
           return deferred.promise;
   }
};
});

A promise is a promise

Once we declare deferred above we are automatically creating a promise. In this instance we promise to get data so we go out to the server and try to fetch the data using the $http call which will ultimately lead to one of two outcomes. First, the data could come back from the server ok (we hope) and then we would have made good on our promise and we let the app know by calling the resolve method of deferred; passing the data as a parameter. Sadly, there are instances when promises are broken, it’s happened to all of us, so in that case we notify the app of the bad news using the reject method of our deferred instance; and if we have any manners we’ll pass the reason why we broke the promise in the parameter. That’s not all; there is a third thing that happens with promises. We have all had that friend or maybe we are that friend who promises to do something but just can’t get it done in time. What do we do, beg and plead for more time, right? In that case you want to notify the page that the promise might take a little longer than expected using the notify method of your deferred instance.

So how do we call the get method of our new data factory?

Now that we have the get method defined in the DataFactory we just need to call it and pass the two parameters that have been defined:

url     : (string) required – where do you want to get the data from

parameters       : (object) optional – the parameters that you may want to pass to the server

The block of code below shows the data call. Since the factory is returning the promise we can tap into the callbacks of the then method (about halfway down – https://docs.angularjs.org/api/ng/service/$q ) . Here we are just assigning the data returned to the data variable in scope or sending an error message to the console.

DataFactory.get('/someurl').then(
 // Success Function   function(data){
       $scope.data = data;
   },

// Failure Function
   function(msg){
      console.error(msg);
   });

Extjs 5 htmlEditor resize bug

I just finished including some html editors in windows that contained forms which were maximizable where the intent is to have the htmleditor field grow on resize and fill the blank space. I used the following code placed on the window to resize the editor:

listeners   : {
    resize : function(windowItself, width, height){
        // 250 is the height of all other form elements combined.
        this.down('htmleditor').setHeight(height - 250);
    }
}

However, although the box itself appears to have resized properly after running the code when doing some testing the actual textarea is placed in an iframe and this iframe did not resize with the outer div. The following CSS will correct this error in Extjs 5.x

.x-htmleditor-iframe{
    height: 100% !important;
}

Adding Midas commands (like strikethrough) to the Extjs 5.x HtmlEditor

Almost ten years ago Mozilla introduced a series of commands that could be invoked on an iframe inside a webpage that had an attribute named designMode with a value of ‘on’ in the main tag. The web may seem fast but the adoption of and creation of standards seems to move at a glacial pace sometimes so here we are 2014 and I can use Midas commands in production only because the customer set a high bar as far as browser compatibility. If you are in the same situation and want to add something like strikethrough to your htmleditor just use the following override.

Ext.define('overrides.HtmlEditor', {
   override               : 'Ext.form.field.HtmlEditor',
   enableStrikeThrough     : true,
   init                   : function () {
       var me = this;
       me.callParent(arguments);
   },

   /*
     * Called when the editor creates its toolbar. Override this method if you need to
     * add custom toolbar buttons.
     * @param {Ext.form.field.HtmlEditor} editor
     * @protected
     */

   createToolbar           : function(){
       var me = this;
       this.toolbar = Ext.widget(this.getToolbarCfg());
       if(this.enableStrikeThrough){
           /*

           https://developer.mozilla.org/en-US/docs/Midas

                 If there is no selection, the insertion point will set
                strikethrough for subsequently typed characters.
                 If there is a selection and all of the characters are
                 already struck, the strikethrough will be removed.
                 Otherwise, all selected characters
                will have a line drawn through them.
           */
           this.toolbar.add([{
               iconCls     : 'x-edit-strikethrough',
               enableToggle: true,
               handler     : function () {
                  this.relayCmd('strikethrough');
               },
               scope       : this,
               tooltip     : 'Strike Through Text'
           }]);
       }
       return this.toolbar;
   }
});

The CSS that you will need for the icon is below:


.x-edit-strikethrough {
   background: url(../images/text_strike.png) 0 0 no-repeat !important;

}

The icon itself is here : text_strike

You may now be wondering what relayCmd does and if there is some trick, I mean it can’t be this easy right? Well, what relayCmd does is takes the command s that can be found on the Mozilla website https://developer.mozilla.org/en-US/docs/Midas and their corresponding arguments and executes them. It’s that easy to add buttons and custom commands to the extjs htmleditor.

Turn your Extjs5 grid into an awesome Bar Chart with this column widget

Bar Chart column grid cell widget for Extjs 5

Ever wanted to represent a number in a grid column as a bar? Why not, doing so would have the effect of magically turning your grid into a stacked bar chart that is sortable and may contain ancillary information that is just hard to convey in a traditional grid.

Hurdles:

First, the widgets that are currently available for grid cells all try to display data that is unique to the row that it is displayed in, this makes it simpler to implement as the data is presented in the record and can be accessed much like the row data in a renderer. The problem with this widget is that it must take into account all row values (not just the current row) to be able to render the bar to the appropriate length given the range (rows).

Second, there is the issue of scaling the bars given the width of a column that is resizable.

Prerequisites:

To handle the linear scaling I relied on d3.js so you will have to add the following lines to your app.json file so that it looks like the following:

"js": [
       {
          "path": "app.js",
          "bundle": true
       },{
           "path": "resources/js/d3.min.js",
           "bundle": false
       }
   ]

Of course, this means that you went http://d3js.org/ and downloaded the minified version of d3.js to the resources/js folder in your application.

Adding your widget in Extjs5:

First create the folder structure. I like to add all my widgets in a folder called *surprise* ‘widget’ on the root of the app directory right where, say, resources would be located, so create a folder there and then go in and modify the app.json file again adding the new folder to the area where the comments indicate “Extra resources to be copied along when build”.

"resources": [       "${app.dir}/widget"   ]

Second, copy the D3GridColumnBar.js file from the D3 charts project on github (https://github.com/jmcdonald69124/ExtjsD3Charts ) The actual file is here : https://github.com/jmcdonald69124/ExtjsD3Charts/blob/master/widget/D3GridColumnBar.js

Using the new widget column in your grid:

The following section represents a grid’s columns definition incorporating the new bar widget.

columns: [
       {
           text      : 'User',
           dataIndex : 'user',
           width     : 400,
           editor: {
               xtype: 'textfield',
               allowBlank: false
           }
       },{
           text      : 'Widgets',
           dataIndex : 'total',
           sortable  : true,
           width     : 400,
           xtype     : 'widgetcolumn',
           disableTooltips: true,
           widget    : {
               xtype   : 'D3GridColumnBar'
           }
       }
   ]

The model should correctly give the type for the dataindex total in the example above as int.

Config Options:

chartBarColor : ‘hex code’ // Is the base bar color

disableTooltips: Boolean // Will remove tooltips from the bars otherwise they default to the column header text and value.