Sunday, 30 March 2014

Using Template in Defining Beans

To understand templates in spring framework, consider a database connection class. This class requires certain parameters viz.

  • Database name, 
  • Server IP address, 
  • Username and 
  • Password.
As these properties must be present in all beans of database connection class, hence we can specify these properties with default values in a spring template as follows.

<bean id="sqlTemplate" abstract="true"> 
 <property name="database" value="Oracle"/>
 <property name="server" value="127.0.0.1"/> 
 <property name="username" value="scott"/> 
 <property name="password" value="tiger"/> 
</bean>

Note that in template we specify abstract="true" and do not provide a class. Now the beans of ORACLEDBConnection class can use this as template by specifying parent attribute value as the bean-id sqlTemplate.

<bean id="dbConnection" class="org.techmight.ORACLEDBConnection" parent="sqlTemplate"/>

Example

spring-config.xml
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

 <bean id="sqlTemplate" abstract="true"> 
  <property name="database" value="Oracle"/>
  <property name="server" value="127.0.0.1"/> 
  <property name="username" value="scott"/> 
  <property name="password" value="tiger"/> 
 </bean>
 
 <bean id="dbConnection" class="org.techmight.ORACLEDBConnection" parent="sqlTemplate"/>

 <bean id="dbConnection2" class="org.techmight.ORACLEDBConnection" parent="sqlTemplate">  
  <property name="server" value="112.36.12.100"/>
  <property name="username" value="techmight"/> 
  <property name="password" value="passwd@123"/>
 </bean>
</beans>

ORACLEDBConnection.java
package org.techmight;

public class ORACLEDBConnection {

 private String database;
 private String server;
 private String username;
 private String password;

 public String getDatabase() {
  return database;
 }

 public void setDatabase(String database) {
  this.database = database;
 }
 
 public String getServer() {
  return server;
 }

 public void setServer(String server) {
  this.server = server;
 }

 public String getUsername() {
  return username;
 }

 public void setUsername(String username) {
  this.username = username;
 }

 public String getPassword() {
  return password;
 }

 public void setPassword(String password) {
  this.password = password;
 }
}

MainApp.java
package org.techmight;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
 public static void main(String[] args) {
  AbstractApplicationContext context = new ClassPathXmlApplicationContext(
    "spring-config.xml");
  ORACLEDBConnection db = null;
  
  db = (ORACLEDBConnection) context.getBean("dbConnection");
  System.out.println("Default Database Connection params - ");
  System.out.println("Database name: " + db.getDatabase());
  System.out.println("Server IP : " + db.getServer());
  System.out.println("Username: " + db.getUsername());
  System.out.println("Password: " + db.getPassword());
  
  System.out.println("\nTechMight Database Connection params - ");
  db = (ORACLEDBConnection) context.getBean("dbConnection2");
  System.out.println("Database name: " + db.getDatabase());
  System.out.println("Server IP : " + db.getServer());
  System.out.println("Username: " + db.getUsername());
  System.out.println("Password: " + db.getPassword());
 }
}

Output
Default Database Connection params -
Database name: Oracle
Server IP : 127.0.0.1
Username: scott
Password: tiger

TechMight Database Connection params -
Database name: Oracle
Server IP : 112.36.12.100
Username: techmight
Password: passwd@123

Configuration Inheritance in Spring Beans

A bean definition can contain a lot of configuration information, including 
  • constructor arguments, 
  • property values, and 
  • container-specific information such as initialization method, static factory method name, and so on. 

A child bean definition inherits configuration data from a parent definition. The child definition can override some values, or add others, as needed.

Note that Spring Bean definition inheritance has nothing to do with Java class inheritance but inheritance concept is same.

Example

In our example, there is a World bean with two properties viz. message and language. Another bean India of which World is parent bean overrides message property and adds flag property. This is achieved by specifying the id of the parent bean in the child bean definition. The scenario is depicted with the help of following diagrams.
Spring Bean Configuration
Class Diagram
Note that there is no relationship between corresponding classes. 

The code is as follows.

spring-config.xml
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

 <bean id="world" class="org.techmight.World">
  <property name = "message" value ="Hello World"/>
  <property name = "language" value ="all"/>
 </bean>
 
 <bean id="india" class="org.techmight.India" parent="world">
  <property name = "message" value ="Namaste India"/>
  <property name = "flag" value ="Tiranga"/>  
 </bean>
 
</beans>

World.java
package org.techmight;

public class World {

 private String message;
 private String language;

 public String getMessage() {
  return message;
 }

 public void setMessage(String message) {
  this.message = message;
 }

 public String getLanguage() {
  return language;
 }

 public void setLanguage(String language) {
  this.language = language;
 }
}

India.java
package org.techmight;

public class India {

 private String message;
 private String language;
 private String flag;

 public String getMessage() {
  return message;
 }

 public void setMessage(String message) {
  this.message = message;
 }

 public String getLanguage() {
  return language;
 }

 public void setLanguage(String language) {
  this.language = language;
 }

 public String getFlag() {
  return flag;
 }

 public void setFlag(String flag) {
  this.flag = flag;
 }
}

MainApp.java
package org.techmight;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {

 public static void main(String[] args) {
  AbstractApplicationContext context = new ClassPathXmlApplicationContext(
    "spring-config.xml");

  World world = (World) context.getBean("world");
  India india = (India) context.getBean("india");
  System.out.println("From World class - ");
  System.out.println("Message: " + world.getMessage());
  System.out.println("Language: " + world.getLanguage());

  System.out.println();
  System.out.println("From India class - ");
  System.out.println("Message: " + india.getMessage());
  System.out.println("Language: " + india.getLanguage());
  System.out.println("Flag: " + india.getFlag());
 }
}

Output
From World class -
Message: Hello World
Language: all

From India class -
Message: Namaste India (This value has overridden world bean value)
Language: all (This value is coming from world bean)
Flag: Tiranga (New property added to india bean)

Life Cycle of Spring Bean (init & destroy)

When a bean is instantiated, it may be required to perform some initialization to get it into a usable state. Similarly, when the bean is no longer required and is removed from the container, some cleanup may be required.

To define setup and teardown for a bean, we simply declare the <bean> with init-method and/or destroy-method parameters. 
  • The init-method attribute specifies a method that is to be called on the bean immediately upon instantiation. 
  • Similarly, destroy-method specifies a method that is called just before a bean is removed from the container.

In the case of XML-based configuration metadata, you can use the init-method attribute to specify the name of the method that has a void no-argument signature. For example:

<bean id="exampleBean" class="examples.ExampleBean" init-method="init"/>

Example

spring-config.xml
<?xml version="1.0" encoding="UTF-8"?> 

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 
 <bean id="helloWorld" class="org.techmight.HelloWorld" scope="prototype"> 
  <property name="message" value="Hello World from TechMight Solutions!"/>
 </bean>
 
 <bean id="user" class="org.techmight.User" init-method="init" destroy-method="destroy"> 
  <property name="hello">
   <ref local="helloWorld"/>
  </property>
 </bean>
 
</beans>

HelloWorld.java
package org.techmight;

/**
 * @author TechMight Solutions
 */
public class HelloWorld {

 private String message;
 
 public String getMessage() {
  return ("Your Message: " + message);
 }

 public void setMessage(String message) {
  this.message = message;
 }
}

User.java
package org.techmight;

/**
 * @author TechMight Solutions
 */

public class User {

 HelloWorld hello;

 public HelloWorld getHello() {
  return hello;
 }

 public void setHello(HelloWorld hello) {
  this.hello = hello;
 }

 public void init() {
  System.out.println("User Bean is going through init.");
 }

 public void destroy() {
  System.out.println("User Bean will be destroyed now.");
 }

 public void execute() {
  String response = getHello().getMessage();
  System.out.println(response + " (From User class) ");
 }
}

MainApp.java
package org.techmight;

/**
 * @author TechMight Solutions
 */
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {

 public static void main(String[] args) {
  AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");

  User user = (User) context.getBean("user");
  user.execute();

  context.registerShutdownHook();
 }
}

If you are using Spring's IoC container in a non-web application environment; for example, in a rich client desktop environment; you register a shutdown hook with the JVM. Doing so ensures a graceful shutdown and calls the relevant destroy methods on your singleton beans so that all resources are released.

Note that here we have registered a shutdown hook registerShutdownHook() method declared on the AbstractApplicationContext class. This will ensures a graceful shutdown and calls the relevant destroy methods.

Output

User Bean is going through init.
Your Message : Hello World from TechMight Solutions! (From User class)
User Bean will be destroyed now.

Scope of Spring Beans (singleton & prototype)

What is a Bean?
  • The objects that form the backbone of your application and that are managed by the Spring IoC container are called as beans
  • A bean is an object that is instantiated, assembled, and managed by a Spring IoC container.
When defining a <bean> in Spring, you have the option of declaring a scope for that bean. For example, To force Spring to produce a new bean instance each time one is needed, you should declare the bean's scope attribute to be prototype. Similar way if you want Spring to return the same bean instance each time one is needed, you should declare the bean's scope attribute to be singleton.

The Spring Framework supports following five scopes, three of which are available only if you use a web-aware ApplicationContext.

ScopeDescription
singleton This scopes the bean definition to a single instance per Spring IoC container (default).
prototype This scopes a single bean definition to have any number of object instances.
request This scopes a bean definition to an HTTP request. Only valid in the context of a web-aware Spring ApplicationContext.
session This scopes a bean definition to an HTTP session. Only valid in the context of a web-aware Spring ApplicationContext.
global-session This scopes a bean definition to a global HTTP session. Only valid in the context of a web-aware Spring ApplicationContext.

In this post we will discuss about first two scopes viz. singleton and prototype with an example for each.

Specifying scope of a bean
<bean class="org.techmight.HelloWorld" id="helloWorld" scope="singleton">

The singleton scope

This is the default scope. If scope is set to singleton, the Spring IoC container creates exactly one instance of the object defined by that bean definition. This single instance is stored in a cache of such singleton beans, and all subsequent requests and references for that named bean return the cached object.

Example
This is in continuation of the previous introductory Hello World example in Spring. Click here to read that post.

spring-config.xml
<?xml version="1.0" encoding="UTF-8"?> 

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 
 <bean id="helloWorld" class="org.techmight.HelloWorld" scope="singleton"> 
  <property name="message" value="Hello World from TechMight Solutions!"/>
 </bean>
 
 <bean id="user" class="org.techmight.User"> 
  <property name="hello">
   <ref local="helloWorld"/>
  </property>
 </bean>
 
</beans>

In this example we are going to create a new User class and injected HelloWorld class as its dependency. by using ref. One way of injecting dependency is

<bean id="user" class="org.techmight.User"> 
 <property name="hello" ref="helloWorld"/>
</bean>

Actually, the ‘ref’ tag can access to a bean either in same or different XML files, however, for the project readability, you should use the ‘local’ attribute if you reference to a bean which declared in the same XML file and 'bean' attribute if you reference to a bean which is declared in a different XML file.

<bean id="user" class="org.techmight.User"> 
 <property name="hello">
  <ref bean="helloWorld"/>
 </property>
</bean>

User class will have getter and setter for the HelloWorld class object because HelloWorld is defined as property in spring-config file.

User.java
package org.techmight;

/**
 * @author TechMight Solutions
 */

public class User {

 HelloWorld hello;

 public HelloWorld getHello() {
  return hello;
 }

 public void setHello(HelloWorld hello) {
  this.hello = hello;
 }

 public void execute() {
  String response = getHello().getMessage();
  System.out.println(response + " (From User class) ");
 }
}

The HelloWorld class is modified as follows.

HelloWorld.java
package org.techmight;

/**
 * @author TechMight Solutions
 */
public class HelloWorld {

 private String message;
 private int count = 0;
 public String getMessage() {
  count++;
  return ("Your Message (" + count + ") : " + message);
 }

 public void setMessage(String message) {
  this.message = message;
 }
}

MainApp.java
package org.techmight;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {

 public static void main(String[] args) {
  ApplicationContext context = new ClassPathXmlApplicationContext(
    "spring-config.xml");

  HelloWorld obj = (HelloWorld) context.getBean("helloWorld");

  String response = obj.getMessage();
  System.out.println(response);
  // Output-> Your Message (1) : Hello World from TechMight Solutions!

  User user = (User) context.getBean("user");
  user.execute();
  // Output-> Your Message (2) : Hello World from TechMight Solutions!
  // (From User class)

  response = obj.getMessage();
  System.out.println(response);
  // Output-> Your Message (3) : Hello World from TechMight Solutions!
 }
}

Output
Your Message (1) : Hello World from TechMight Solutions!
Your Message (2) : Hello World from TechMight Solutions! (From User class) 
Your Message (3) : Hello World from TechMight Solutions!

Observation
The count variable was increased each time as getMessage() method is called from different locations.

The prototype scope
If scope is set to prototype, the Spring IoC container creates new bean instance of the object every time a request for that specific bean is made.

As a rule, use the prototype scope for all state-full beans and the singleton scope for stateless beans.

In spring-config.xml just change the scope of the helloWorld bean to prototype.
<bean id="helloWorld" class="org.techmight.HelloWorld" scope="prototype"> 

Now execute MainApp.java and see the output which will be as follows.

Output
Your Message (1) : Hello World from TechMight Solutions!
Your Message (1) : Hello World from TechMight Solutions! (From User class) 
Your Message (2) : Hello World from TechMight Solutions!

We are leaving it for our readers to determine what is the difference in the output and the reason behind !!

Saturday, 29 March 2014

Starting with Spring Framework (Hello World Example)

This article will talk about the rudimentary steps required to set up a simple Hello World application in Java using Spring Framework.

Download Links

Steps

1. Create a new Java Project in Eclipse

2. In Project Explorer,
right click on project name,
Build Path,
Configure,
Libraries Tab,
Add External Jars
Browse & add
All the executable Jar files from spring-framework-3.1.0.M2/dist directory.
antlr-runtime-4.2.1
commons-logging-1.1.3

3. In the src folder create package org.techmight

4. Add the following two classes in org.techmight package.

HelloWorld.java
package org.techmight;

/**
 * @author TechMight Solutions
 */

public class HelloWorld {

 private String message;

 public String getMessage() {
  return ("Your Message : " + message);
 }

 public void setMessage(String message) {
  this.message = message;
 }
}

MainApp.java (this class will have main method)
package org.techmight;

/**
 * @author TechMight Solutions
 */

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {

 public static void main(String[] args) {
  ApplicationContext context = new ClassPathXmlApplicationContext(
    "spring-config.xml");
  HelloWorld obj = (HelloWorld) context.getBean("helloWorld");

  String response = obj.getMessage();
  System.out.println(response);
 }
}

5. Create spring-config.xml in src folder with the following bean configuration.
<?xml version="1.0" encoding="UTF-8"?> 

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 
 <bean id="helloWorld" class="org.techmight.HelloWorld"> 
  <property name="message" value="Hello World from TechMight Solutions!"/>
 </bean>
 
</beans>

6. Finally right click on MainApp.java,
Run as
Java application

Output

Your Message : Hello World from TechMight Solutions!

Advantage

The default values of the member variables can be changed by making the changes in spring-config.xml file without changing any Java code.

Implementation

E.g. Consider a class which uses some configuration variables for database communication. If there is any change in any of these configurations, there is no need to make modifications in java code and then recompile it. Only setting the proper configuration in spring-config.xml file will do the work.

Tuesday, 18 March 2014

Testing Ext JS Controller using Jasmine Framework

The problem with Java Script development is debugging and testing. For debugging you have chrome debugger as a good tool. Once the application is debugged and it is working seamlessly, your work doesn't end there. There are certain tailoring and modifications which are always desired throughout the life cycle of an application. Making changes in one part of the Java Script code may introduce bugs and failures in other parts and can go undetected till someone encounters it. What is the way to avoid such unwanted and hidden failures.

The best way is to write certain test cases and re-run them after any change to the code to ensure that there is no break in the functioning of application. Jasmine framework is the one we are going to use. Google to know more, as we don't reinvent the wheel.
We have created a simple Stock Grid application (MVC) in the last post. You can go through it by clicking here. Now, I am going to write the a set of test cases for the controller.

Create folder app-test->lib->jasmine-1.3.1 and put the following three files into it.
  1. jasmine.css
  2. jasmine.js
  3. jasmine-html.js
Create folder app-test->specs and put the test file here which is as follows.

StockGridControllerSpec.js
describe("Stock Grid Controller", function() 
{
 var controller = null;   
 it('#1 -> Initialize controller : should be able to instantiate Stock Grid controller', function() 
 {
  controller = Application.getController('grid.StockGrid');
  // NB: We've created a controller outside of the lifecycle of the Application. We must manually initialise it.
  controller.init();
  // If we'd defined a launch method for controller, we'd need to call it here
  expect(controller).toBeTruthy();
 });
 
 it("#2 -> Testing refs : should have no valid references before making widgets", function() 
 { 
  expect(controller.getStockGrid()).toBeUndefined();
 });
 
 var store = null; 
 it("#3 -> Store Load : should be able to get no records loaded into store", function () 
 {
  store = controller.getStocksStore();
  expect(store.getCount()).toEqual(0);   
 });
 
 var widget = null
 it("#4 -> Creating Widget : should be able to create a widget, via the controller", function() 
 {
  widget = controller.getView('grid.StockGrid').create({ id: 'grid1' });    
  expect(widget).toBeTruthy();
 });
 
 it("#5 -> Firing event : should be able to fire events on the widget, and have them picked up by the controller using the xtype", function() 
 {
  spyOn(controller, 'loadStockStore');    
  widget.fireEvent('render');    
  expect(controller.loadStockStore).toHaveBeenCalled();  
 });
});

The code for StockGrid Controller is as follows.
Ext.define('Example.controller.grid.StockGrid',
{
 extend : 'Ext.app.Controller', 
 views : [ 'grid.StockGrid'], 
 models : ['Stock'], 
 stores : ['Stocks'], 
 refs :
 [
  { 
   ref: 'stockGrid', 
   selector: '#stock-grid' 
  },
 ],
 
 init : function()
 {
  var me = this;
  me.bindListeners();
  me.callParent(); 
 },
 
 bindListeners : function()
 {
  var me = this;
 
  this.control(
   {
    'stock-grid' :
    {     
     /* 
     render : me.loadStockStore
     WORKS, BUT IS NOT TESTABLE - 
     the spy will replace the implementation of loadStockStore, but won't change the listener     
     Therefore, 
     */ 
     render : Ext.Function.alias(me, 'loadStockStore')
    }
   }
  ); 
 },
  
 loadStockStore : function()
 {
  var me = this;
  me.getStocksStore().load();
 } 
});

Create app-test.js at same level as app.js
Ext.Loader.setConfig(
{
 enabled : true,  
 paths: 
 {
  /*
   In application we specify name as Example.store.Stock
   and as the name in Application in this file specifies Example,
   it searches Example folder.
   
   To replace Example with actual folder name app, following configuration 
   is added.
  */
  Example: 'app' 
 }
});

var Application = null;

Ext.onReady(function() 
{

 Application = Ext.create('Ext.app.Application', 
 {
  name: 'Example', //This name should be same as the application name

  controllers: ["grid.StockGrid"], //name of folder inside controllers and then controller file name

  launch: function() 
  {
   jasmine.getEnv().addReporter(new jasmine.HtmlReporter());
   jasmine.getEnv().execute();
  }
 });
});

Create tests.html at the same level as index.html
<html>
<head> 
 <title>Ex JS Grid Application (MVC) Test</title>
 <script src="ext-all.js"></script>
 <script src="app-test/lib/jasmine-1.3.1/jasmine.js" type="text/javascript"></script>
 <script src="app-test/lib/jasmine-1.3.1/jasmine-html.js" type="text/javascript"></script> 
 <link href="app-test/lib/jasmine-1.3.1/jasmine.css" rel="stylesheet" type="text/css"></link>
 <script src="app-test.js"></script>  
 <script src="app-test/specs/StockGridControllerSpec.js"></script>  
</head>
<body>
</body>
</html>

Finally just hit the test.html URL to verify that all the test results are positive.


When any changes are made anywhere in this application, you cans imply hit a URL and execute all the tests.Feel free to ask your doubts in comments to this post.

Saturday, 8 March 2014

Ext JS Grid Application using MVC architecture

What this post will teach you?
  • The structure of folders when following MVC pattern in Ext JS
  • How to create a view?
  • How to create a model with proxy and a custom field?
  • How to create a store and populate using JSON data?
  • How to bind a store to a grid?
Output of this tutorial

So let's start.
How to begin?
  • You need a notepad to write the code. 
  • You also need Ext JS libraries. Ask Google for help.
  • I am running this on Apache Tomcat using XAMPP
Folder Structure (Which file goes where?)

Starting with the html file which will have references to
  • Ext JS package
  • CSS and
  • app.js (the start point for our Ext JS applicatio)
Index.html
<!DOCTYPE html>
<html>
<head> 
 <title>Ex JS Grid Application (MVC)</title>
 <script src = "ext-all.js"></script>
 <script src = "app.js"></script>
 <link rel="stylesheet" type="text/css" href="ext-all.css">
</head>
<body>
</body>
</html>

Now we define app.js.
Ext.application(
{
 appFolder  : 'app', //default
 name  : 'Example', 
 controllers :
 [
  'Example.controller.grid.StockGrid'
 ], 
 autoCreateViewport : true
});
As autoCreateViewport is set to true, it will automatically go to view folder, look for Viewport.js and renders the application. What is a Viewport? Google, you will get it. I do not want to reinvent the same wheel.

This file first goes to controller and executes the controller and then comes to Viewport. We will see the Viewport code  next and then will have a look at the controller and files referred inside it.

Viewport.js
Ext.define('Example.view.Viewport',
{
 extend : 'Ext.container.Viewport',
 layout : 'border',
 
 requires :
 [
  'Example.view.grid.StockGrid'
 ],
 
 initComponent : function()
 {
  var me = this;
  me.items = me.getComponents();
  me.callParent();
 },
 
 getComponents : function()
 {
  return(
  [
   {
    xtype : 'stock-grid',
    region : 'center'
   } 
  ]);
 }
});

JSON Data -> stockdata.json
{
    "response": "success",
    "stocklist": [
        {
            "name": "Maruti Suzuki India Ltd.",
            "code": "maruti",
            "ltp": "1586.30",
            "high": "1864.00",
            "low": "1217.00"
        },
        {
            "name": "Reliance Industries Ltd.",
            "code": "reliance",
            "ltp": "799.25",
            "high": "927.90",
            "low": "765.00"
        },
        {
            "name": "Reliance Communications Ltd.",
            "code": "rcom",
            "ltp": "112.05",
            "high": "164.45",
            "low": "50.25"
        }
    ]
}

Model -> Stock.js
Ext.define('Example.model.Stock', {
    extend: 'Ext.data.Model',
    fields   : [
           {name : 'name',          type : 'string'},
           {name : 'code',    type : 'string', convert : function(value) {return value.toUpperCase();}},
           {name : 'ltp',   type : 'numeric'},
     {name : 'high',   type : 'numeric'},
     {name : 'low',   type : 'numeric'},
     {name : 'avg', type:  'numeric', convert : function(value, record) 
 {
  var high  = parseInt(record.get('high'));
  var ltp  = parseInt(record.get('ltp'));
  var low  = parseInt(record.get('low'));
  return ((high+low+ltp)/3);
 },  defaultValue : 'NA'}
    ],
 
 proxy: 
 {
        type: "ajax",
        url: "app/data/stockdata.json",  
        reader: {
            type    : 'json',
            root    : 'stocklist'
        }
    } 
});

Store -> Stocks.js
Ext.define('Example.store.Stocks',
{
 extend  : 'Ext.data.Store',
 requires : ['Example.model.Stock'], 
 model  : 'Example.model.Stock', 
 autoLoad : false
});

View -> StockGrid.js
Ext.define('Example.view.grid.StockGrid',
{
 extend : 'Ext.grid.Panel',
 alias : 'widget.stock-grid',
 title : 'BSE Stock List',
  
 requires:
  [
   'Example.store.Stocks'
  ],
  
 store : 'Stocks',
 columns : [
  {
   header  : 'Stock Name',
   dataIndex : 'name',
   flex  : 2
  },
  
  {
   header  : 'Stock Code',
   dataIndex : 'code',
   flex  : 1
  },
   
  {
   header  : 'Last Trade Price',
   dataIndex : 'ltp',
   flex  : 1,
   renderer: Ext.util.Format.numberRenderer('0.000')
  },
   
  {
   header  : '52 Week High',
   dataIndex : 'high',
   flex  : 1,
   renderer: Ext.util.Format.numberRenderer('0.000')
  },
    
  {
   header  : '52 Week Low',
   dataIndex : 'low',
   flex  : 1,
   renderer: Ext.util.Format.numberRenderer('0.000')
  },
    
  {
   header  : 'Average',
   dataIndex : 'avg',
   renderer: Ext.util.Format.numberRenderer('0.000')
  }
 ],
 
 initComponenet : function()
 {
  var me = this;  
  me.callParent();
 }
});

Controller -> StockGrid.js
Ext.define('Example.controller.grid.StockGrid',
{
 extend : 'Ext.app.Controller',
 
 views : [ 'grid.StockGrid'],
 
 models: ['Stock'],
 
 stores : ['Stocks'],
 
 init : function()
 {
  var me = this;
  me.bindListeners();
  me.callParent(); 
 },
 
 bindListeners : function()
 {
  var me = this;
 
  this.control(
   {
    'stock-grid' :
    {
     render : me.loadStockStore
    }
   }
  ); 
 },
  
 loadStockStore : function()
 {
  var me = this;
  me.getStocksStore().load();
 } 
});

Ensure that your application is supported by Internet Explorer.

Download Link
Click here to download this project.

What next?
We will connect this grid to a MySQL table using PHP and will populate data from there rather than populating from the static JSON data file.



Reference
If you want to know anything about Ext JS, hit the docs link.

If you are facing difficulty in understanding the code, you can comment to this post.

Do you like this article?