View Model Data Binding – When store.load() gives you an ext-empty-store error

I’ve been starting a new enterprise application using Extjs5 and wanted to implement the MVVM pattern to include the new view Model, this is a list of the things I have learned so far and the obstacles that I have overcome.

Scenario: Create a store and load it with a parameter from the view Model’s data section

One of the things that I wanted to do was create a panel that would be created and added to a tab panel on a row click. The panel would show specific data for that row’s corresponding record. The new design pattern is perfect for this because the copy of the store can reside in the view Model and I can open as many new tabs as I want.

Obstacles:

I originally thought that I would just create the store in the view model and do a load on it when the panel was added to the parent container using Ext.getStore().load(), however, I kept getting the error “Cannot modify ext-empty-store” which was frustrating to say the least. It appears that to do the binding correctly the order in which objects are created means that the store may not exist for the few milliseconds in which you come along trying to reload it, what is there is a phantom store.

Solution:
In the view model I added a store like this:

stores: {

        myStore: {
    	    // Just holds the fields
            model   : 'myapp.model.MyStoreModel',
            proxy: {
                type : 'ajax',
                url  : '/someurl.php',
                extraParams: {
                    id: '{id}'
                },
                reader: {
                    type            : 'json',
                    rootProperty    : 'data',
                    totalProperty   : 'results'
                }
            },
            autoLoad:true
        }
}

Notice that there is an extraParams declaration with a key value pair named id. The value is in handlebars so it would be replaced by the id value in data. Since I do not know which record the user is going to click yet I can’t provide the data config to the view model yet.

In the panel itself I add the following code that will call a function called onFormAdd when the added event of the form is called.

listeners :{
scope : 'controller',
added : 'onFormAdd'
}

I also specify that the grid is going to bind to the store in the view model. The complete code for the child grid is:

{
                    xtype    : 'grid',
                    flex        : 1,
                    title       : 'My Grid',
                    bind :{
                        store : '{myStore}'
                    },
                    columns: [
                        {
                            text        : 'Column 1',
                            dataIndex   : 'cl_one'
                        }, {
                            text        : 'Column 2',
                            dataIndex   : 'cl_two',
                            flex        : 1
                        }
                    ]
                }

Now, for the glue that binds everything together, take a look at the added function below that adds the panel to the parent tab panel on the grid click.

onGridItemClick  : function( me, record, item, index, e, eOpts ){
        var tabPanel = me.up('app-main').down('tabpanel'),
            data     = record.data;

        tabPanel.add({
            bind:{
                title       : 'ID ({some_title}) '
            },
            data    : data,
            closable: true,
            reference   : 'mypanel-' + data.id,
            xtype   : 'mycoolpanel'
        });
    }

The next function is taken directly from the view model controller and is called when the added event is fired. This is where the data is bound and the store load is called with the proper id.

	onFormAdd: function(me, parent){
       		 me.getViewModel().setData(me.config.data);
               }

Real Simple Extjs NVD3js Charts in place of Extjs Charts

Download the latest code from GitHub 

A little bit about the charts …

If you are into data visualization and developing in JavaScript then you have probably heard of d3js which can be found at d3js.org, you may not have heard about NVD3 which is a nice open source group of reusable charts based on d3js created by developers for the financial industry. You can find NVD3 here http://nvd3.org/ . What these two chart packages do is allow you, the developer, to control every last pixel on the screen. You are also left with code that can be moved away from Extjs if that day comes. Just take a look at the examples page to realize how many possibilities there are when it comes to charting: https://github.com/mbostock/d3/wiki/Gallery. I needed to get that type of flexibility in my application and I liked the crisp sharp lines so I went ahead and threw together some NVD3 / D3 based widgets that you can use in your applications by simply adding them and referencing the xtype. I am assuming that you will be using extjs 5 so the instructions here are for installation in an extjs5 application – that said they should work with extjs4 as well.

I will keep adding charts and updating functionality over the next few months and hope to have a comprehensive set of plugins that you can use.

Getting Started:

Add d3 and nv.d3 to your build.

  • First download d3.min.js and nv.d3.min.js.
  • Create a folder named js under your resources folder
  • Place the files in the new js folder
  • Change the lines in your app.json file below to include the new js files into your build
    "js": [
        {
            "path": "app.js",
            "bundle": true
        },{
            "path": "resources/js/d3.min.js",
            "bundle": false
        },{
            "path": "resources/js/nv.d3.min.js",
            "bundle": false
        }
    ],

Add nv.d3.min.css to your application

  • Download the nvd3 css file
  • Create a folder named css under your resources folder
  • Place the file in the new css folder
  • Change the lines in your app.json file below to include the new css files into your build
    "css": [
        {
            "path": "bootstrap.css",
            "bootstrap": true
        },{
            "path": "resources/css/nv.d3.css",
            "bootstrap": false
        }
    ],

Create a widget folder at the same level as the app folder.

D3Donutpanel

Screen Shot 2014-09-18 at 9.28.09 PM

Config options

  • dataUrl                    : (string) – url of json data for the chart, json should be in the following format, label and value are required, any attached data points will get passed to the click event i.e. primary keys etc ..
    {'results': 1, 'data':[{'some_value': 'not required', 'label': 'Required', 'value': 17}]}
  • chartTitle              : (string) – chart title displayed above the chart
  • tooltipAppend   : (string) – text to append to the tooltip value
  • showTotal            : (boolean) – show total in the center of the chart
  • totalType              : ‘sum’ or ‘avg’ calculate the total values as the sum of all values that are shown or the average of all shown values.

Strange Sencha Command image slicing error after upgrading to Extjs 5.0.1

I just downloaded extjs 5.0.1 and did the Sencha app upgrade command to bring the version from 5.0 to the latest and ended up with a lengthy list of warnings all regarding “Expected slices for widget … due to border radius …” and then finally the error:

Screen Shot 2014-09-18 at 5.16.20 PM

I took a look at the .sencha/app/slice-impl.xml  and noticed that it referenced some extjs 4.x legacy stuff around lines 239 – 244. I commented out the following since I am using just 5 and have no need for the older themes and all worked well.

Screen Shot 2014-09-18 at 5.16.29 PM

 

Show Extjs 5 action columns icons on row mouseover only – CSS solution – No JS

I recently upgraded an application to extjs 5 and noticed that the show / hide icons script that I had used in Extjs4 successfully was susceptible to errors if you used the mouse wheel to scroll through the rows quickly. The code that worked well in Extjs4 can be replaced with:

.x-grid-row:hover .x-hide-display{
    background-image: url(icon-info.png);
    background-repeat: no-repeat;
    width: 20px;
}

The corresponding JavaScript that needs to be in your action column to set the initial row icon to hidden is:

items: [
{
    iconCls : 'icon-info',
    tooltip : 'Some Tooltip',
    getClass: function() {
        return 'x-hide-display';  //Hide the action icon
    }
 }]

JQuery Events Calendar Plugin ala Metro.js Scheduler

Download Source Here from GitHub

Recently I stumbled across Sergey Pimenov’s Metro UI framework that makes the bootstrap framework look a lot like Windows 8 with the tiles and Microsoft color pallet and a few really nice looking UI elements that I believe mirror Microsoft components. I really liked how the schedule streamer presented event data in a linear fashion on tracks, but I spent a great deal of the last five years working with Sencha’s Extjs and Touch and I was looking for something that I could drop in and manipulate the actual contents via passing a JSON object, that way I could spare myself the tedious job of hand coding a ton of HTML and also pull data from the database a bit easier. I ended up gutting the original component and using a variety of other elements to get the desired functionality and true to the open source license I’m publishing the finished result below. The reason that the actual framework is not a dependency is due to the fact that the CSS was altered so that it did not require adding a class to the body tag; this allows you to just use the widget without interfering with your existing styles.

Ingredients:

Dependencies:

JQuery Waypointshttp://imakewebthings.com/jquery-waypoints/ this plugin is used to fire events tied to the scroll position. I used this to keep track of where you might be in the schedule so that if you went from scrolling to using the navigation button you would go to the last or next increment of time and not be sent back to the beginning and then forwarded one increment of time.

JQuery Mouse wheelhttps://github.com/brandonaaron/jquery-mousewheel this plugin is used to enable the horizontal scrolling on the events pane.

JQueryhttp://blog.jquery.com/ – I am using version 1.10.2 so this should be the minimum version that you use.

Bootstraphttp://getbootstrap.com/ I am also using Bootstrap 3.2.0 so this plays well with this framework. It’s not necessary but if you are using it this plugin will not interfere or vice versa.

JQuery Widget Factoryhttp://jqueryui.com/widget/  since this is actually a UI Widget; of course, you will need the widget UI file from JQuery.

 The Widget Files:

Json-event-streamer.js – This is the core JavaScript file that builds the html code and also adds the functionality to the buttons and timeline.

streamer.css – This is the CSS that adds all of the styles to the timeline and really makes it look awesome. This code is 99% Metro UI’s CSS code.

Setting Up Your Page

The code is going to look for a <div> tag in your page, you will need to give the tag a unique ID and then use that ID when initializing the streamer in your JavaScript. It’s important to note that the actual streamer is transparent so if you want to set it up in a container with a white background and some decent padding etc I would use the following code:

<div class=”center-block” style=”padding: 20px; border: 1px #eaeaea solid;width:1200px !important;background-color:#FFF;”   >

<div id=”json-events”></div>

</div>

The class center-block is a Bootstrap class above and I wanted to force the 1200 pixel width. Notice for the example my div ID  is equal to ‘json-events’. Next, you need to initialize the streamer using the following code that should be in the document ready function placed at the bottom of your page in script tags.

 

$( document ).ready(function() {
   $.custom.streamer({
    dataUrl  : ' events.json',
    containerId : 'json-events'
});
});

The example above assumes that the json file that will supply the events lives on the root of the drive, and the div id that will host the events streamer has an ID of ‘json-events’.

The JSON File Structure

The JSON file that contains the events must conform to the structure defined below, the example file is a great starting point.

Top level configuration:

eventHeader                        = The large title that is displayed above the streamer component. String

eventStartTime                  = Time in the following format 9:00, required to compute the number of blocks  that are in the streamer.

eventEndTime                     = Time in the following format 9:00, required to compute the number of blocks  that are in the streamer.

blockLengthMins              =  Number of minutes used to divide startTime – EndTime

keynotes                                 = Objects that contain the information for the presentations that span all of the tracks.

Tracks                                        = A track is an object that forms the rows in the streamer, each track contains a square with a color and corresponding events. Tracks must contain the following attributes as well as a ‘sessions’ object which is populated by event objects. Colors can be found in the streamer.css file

title                          : “Test”,

location                 : “Conference Room”,

blockColor           : “orange”,

 

Event Objects:

startTime                                =  Time in the following format 9:00, required to compute the number of blocks  this event will take up in the streamer.

endTime                                  =  Time in the following format 9:00, required to compute the number of blocks  this event will take up in the streamer.

title                                            = String value that will be the bold title in the event tile

description                            = Optional description leave an empty string if not needed,

presenter                               = Presenter name