EXT JS – My Learning Experience

I used Ext JS for browser side javascript programming, to build professional looking UI using the layout and widgets Ext has to offer, it’s been a good experience learning EXT.

Documentation : http://docs.sencha.com/extjs/5.0.0/cmd/intro_to_cmd.html

Kitchen Sink Examples : http://dev.sencha.com/extjs/5.0.0/examples/kitchensink/#grid-filtering

Project Structure Creation by Sencha CMD

  1. Follow here http://docs.sencha.com/extjs/5.0.0/getting_started/getting_started.html

    sencha generate app -ext MyApp ./app
    
  2. To start the default web server

    cd app
    sencha app watch
    
  3. To use your own sdk

    sencha -sdk /path/to/framework generate app MyApp ./app
    

That’s it. You’ve created an application and deployed a server. Now navigate to http://localhost:1841 or your native localhost.

The explaination of the appliation architecture is here http://docs.sencha.com/extjs/5.0.0/application_architecture/application_architecture.html

Main View

  1. open and edit : app/view/main/Main.js

  2. use it as viewport in app.js

    Ext.application({
        name: 'MyApp',
        extend: 'MyApp.Application',
        autoCreateViewport: 'MyApp.view.main.Main'
    });
    

autoCreateViewport is a new feature as of Ext JS 5. By designating a container class for autoCreateViewport, you can use any class as your Viewport. In the above example, we have determined MyApp.view.main.Main (a Container class) to be our Viewport.

The autoCreateViewport config instructs the application to create the designated view and attach the Viewport Plugin. This connects the view to the document body.

Class declaration and object creation

Ext JS 5 ships with more than 300 classes. The names of the classes map directly to the file paths in which they are stored. As a result, there must only be one class per file. For example:

  1. Ext.util.Observable is stored in path/to/src/Ext/util/Observable.js
  2. Ext.form.action.Submit is stored in path/to/src/Ext/form/action/Submit.js
  3. MyCompany.chart.axis.Numeric is stored in path/to/src/MyCompany/chart/axis/Numeric.js

path/to/src is the directory of your application’s classes. All classes should stay under this common root and should be properly namespaced for the best development, maintenance, and deployment experience.

The class declaration (Ext.define) and creation (Ext.create) example

Ext.define('My.sample.Person', {
  name: 'Unknown',

  constructor: function(name) {
      if (name) {
          this.name = name;
      }
  },

  eat: function(foodType) {
      alert(this.name + " is eating: " + foodType);
  }
});

var aaron = Ext.create('My.sample.Person', 'Aaron');

aaron.eat("Salad"); // alert("Aaron is eating: Salad");

Ext.Class pre-processors

Before a class is created, lot of things happens on the back scene by the Ext.Class pre-processor. For example, every item in the config property will be pre-processed like this:

  1. Getter and setter methods for every config property are automatically generated into the class prototype during class creation if methods are not already defined.
  2. An apply method is also generated for every config property. The auto-generated setter method calls the apply method internally before setting the value. You may override the apply method for a config property if you need to run custom logic before setting the value. If apply does not return a value, the setter will not set the value.

Dynamic Loading

See this discussion http://www.sencha.com/forum/showthread.php?279370-What-s-Dynamic-Loading-really-Mean-Only-app.js-loaded-amp-other-js-are-loaded-on-demad

In ExtJS, each class is defined in its own file, and the organization of the files matches the class names. What dynamic loading means is that when the app.js file included in the page is loaded, ExtJS will load the files for each class required by app.js (via AJAX). Then, as each class is loaded, its dependencies will be loaded dynamically, continuing recursively until the entire dependency tree is present.

Dynamic loading is a huge time-saver during development. It allows you to keep your code modularized without having to add a new JS file to your HTML every time you add a new ExtJS class. It allows you find dependency issues up-front during development, rather than at build time when you try to run Sencha Cmd. And finally, it makes for a much nicer debugging experience, since each class file is loaded independently rather than having a single ext-all-dev.js with many thousands of lines of code.

At production level, during the build process, Sencha Cmd computes the dependencies (by parsing the source code) and concatenates all the necessary files into the production build. In that case, all the needed classes are already included on the page and no dynamic loading is required. Also a single minified JS requires much less loading overhead then multiple small JS file connections.

Components

An Ext JS application’s UI is made up of one or many widgets called Components. All Components are subclasses of the Ext.Component class which allows them to participate in automated lifecycle management including instantiation, rendering, sizing and positioning, and destruction.

Ext components correspond to HTML DOM objects.

Alias and xtype

Every Component has a symbolic name called an xtype. For example Ext.panel.Panel has an xtype of ‘panel’. When you use Ext.Create to create a container component with child items, we want to have the advantage that the child item will only be created when needed, that’s to say, a container can be created before all of its children items are created already.

This is where xtypes come in handy by allowing a Container’s children to be configured up front, but not instantiated until the Container determines it is necessary. This is also called “lazy initialization”.

An alias is set on the class definition, using Ext.define, and is what is used for the xtype when creating instances.

Also see this discussion http://www.sencha.com/forum/showthread.php?146412-Alias-xtype-and-widget

Getter and Setter

We mentioned before that Ext.Class pre-processor can create getter and setters for config property. Actually when you define a class, you can give it properties such as : refs, models, stores, besides config.

All items of those properties will automatically have getter and setters generated for them. for example you have attribues like these

refs: [
    {
        ref: 'dataInfo',
        selector: 'datainfo'
    },
    {
        ref: 'datasetList',
        selector: 'datasetlist'
    },
    {
        ref: 'metadataPanel',
        selector: 'metadata'
    }
],

models: ['TreeData', 'Data', 'MetaData'],
stores: ['Dataset', 'Data', 'TreeData', 'MetaData'],


config: {
    hierarchyStatus: false,
    metaTree: {name: "meta", expanded: true, children: []},
    jsonData: {},
    selectedItems: [],
    storeRoot: '',
    columnsArr: {},
    modelFields:{},
    contentChange: false
},

Then you can access these attributes like this

var datasetList = this.getDatasetList();
var store = this.getDatasetStore();
this.setJsonData(json_data);

id vs. itemId

In general, it is a good idea to let Ext assign the ID instead of creating a ‘hard’ id. If you create another instance that has the same id, you will have problems as the DOM is confused.

With itemId, it is scoped to the class.

It is recommended that you use itemId and then query for the component.

Up and Down uses ComponentQuery, as argument here you can use any selector you want according to the ComponentQuery, so they can select classes, or itemId.

getCmp searches in ComponentManager’s hash map only by id, it’s fast, but as we said, id intends to have duplicate problem.

Component management

  1. ref and selector

    refs: [
       {
           ref: 'vizProperty',       //getter -- get Ext app view class
           selector: 'vizproperty'   //xtype -- select dom object
       }
    ],
    
    
    onVizMethodSelect: function(selModel, record) {
    
       var property = this.getVizProperty();
    }
    

Since refs uses xtype to identify an object, there is this confusion, because xtype is at class level, not object level, so what if multiple objects exist for that xtype ?

See this discussion http://www.sencha.com/forum/showthread.php?242595-Clarification-about-Controller-refs

As we understand it, the ‘refs’ feature is a handy shortcut that causes a controller to create a getter() method based on a ComponentQuery syntax.

Our confusion surrounds how the Controller decides which compnent to select where there may be more than one to choose from.

It use Ext.ComponentQuery.query(ref)[0] , as you can see, if the component query return more than one component, it return the first item in the array.

  1. the ‘control’ function

    init: function() {
    
        // Start listening for events on views
        this.control({
            'viztoolbar': {
                select: this.onVizMethodSelect,
                scope: this
            },
            'datasetlist': {
                selectionchange: this.onNewDataSelect,
                scope: this
            },
            'drawchart #chartarea': {
                click: this.onVizSelectionChange,
                scope: this
            },
            'vizproperty button[action=draw-chart]': {
                click: this.onApplyViz,
                scope: this
            },
            'vizconfig': {
                close: this.clearVizMethod,
                scope: this
            }
    
        });
    
  2. the up and down function

    this.getDataInfo().down('#rawdata').add(tree_panel);