EXTJS Calculator Example

In this example, we will show you step by step how to develop a simple calculator using ExtJS 6.

Ext JS is a popular JavaScript framework that provides rich UI for building web applications with cross-browser functionality. Ext JS is basically used for creating desktop applications.

Ext JS follows MVC/ MVVM architecture.

MVC − Model View Controller architecture (version 4)

MVVM − Model View Viewmodel (version 5)

This architecture is not mandatory for the program, however, it is a best practice to follow this structure to make your code highly maintainable and organized.

EXTJS Calculator Example

In this example, we use Cloudflare CDN for ExtJS 6. If the CDN doesn't work, you may need to update ExtJS lib URLs in index.html and point to the local ExtJS library path.

Let's create a EXTJS project structure as shown in below image:

index.html

Let's create an HTML page that includes the ExtJS library and app.js file:
<!DOCTYPE html>
<html>

<head>
    <title>Calculator!</title>
    <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/
                libs/extjs/6.0.0/classic/theme-crisp/resources/theme-crisp-all.css">
    <link rel="stylesheet" type="text/css" href="resources/css/app.css">

   <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/extjs/6.0.0/ext-all-debug.js">
   </script>
   <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/extjs/6.0.0/
                             classic/theme-crisp/theme-crisp-debug.js"></script>
   <script type="text/javascript" src="app.js"></script>
    
</head>

<body></body>

</html>

app.js

This is the main file from where the flow of the application will start, which should be included in the main HTML file using the <script> tag. The app calls the controller of the application for the rest of the functionality.
Ext.application({
    name: 'Calc',    
    launch: function () {
        Ext.create('Calc.view.main.Main').show();
        //Will create the calculator as a floating, movable window within the browser 
    }
});

Main.js

Create a file named app/view/main/Main.js and add the following code to it:
Ext.define('Calc.view.main.Main', {
    extend: 'Ext.window.Window',
    
    /* Marks these are required classes to be to loaded before loading this view */ 
    requires: [
        'Calc.view.main.MainController',
        'Calc.view.main.MainModel'
    ],
        
    xtype: 'app-main',
    controller: 'main',
    
      /* View model of the view */ 
    
    viewModel: {
        type: 'main'
    },  
    
    resizable: false,
    layout: {
        type: 'table',
        columns: 4
    },
    
    /* Defaults properties to be used for the child items. Any child can override it */

    defaultType: 'button',
    defaults: {
        width: 50,
        height: 50,
        cls: 'btn',
        handler: 'onClickNumber'
    },

    /* I’m using the header config of the Ext.window.Window to display the result in calculator. Using this header you can move the floating calculator around within the browser */ 
    header: {
        items: [
            {
                xtype: 'displayfield',
                colspan: 4,
                width: 200,
                cls: 'display',
                bind: { 
                    value: '{display}'
                },
                height: 60,
                padding: 0

            }]
    },
    items: [
        {
            text: 'C',
            colspan: 2,
            width: 100,
            cls: 'btn-green',
            handler: 'onClickClear'
        },
        {
            text: '+/-',
            cls: 'btn-green',
            handler: 'onClickChangeSign'
        },
        {
            text: '&divide;',
            cls: 'btn-orange',
            handler: 'onClickOp'
        },
        {
            text: '7'
        },
        {
            text: '8'
        },
        {
            text: '9'
        },
        {
            text: '&times;',
            cls: 'btn-orange',
            handler: 'onClickOp'
        },
        {
            text: '4'
        },
        {
            text: '5'
        },
        {
            text: '6'
        },
        {
            text: '-',
            cls: 'btn-orange',
            handler: 'onClickOp'
        },
        {
            text: '1'
        },
        {
            text: '2'
        },
        {
            text: '3'
        },
        {
            text: '+',
            cls: 'btn-orange',
            handler: 'onClickOp'
        },
        {
            text: '0',
            width: 100,
            colspan: 2
        },
        {
            text: '.',
            handler: 'onClickDot'
        },
        {
            text: '=',
            cls: 'btn-orange',
            handler: 'onClickOp'
        }
    ]
});

MainController.js

It is the controller file of Ext JS MVC architecture. This contains all the control of the application, the events listeners, and most of the functionality of the code. It has the path defined for all the other files used in that application such as store, view, model, require mixins.

Create a file app/view/main/MainController.js and add the following code to it:
Ext.define('Calc.view.main.MainController', {
    
    extend: 'Ext.app.ViewController',
    alias: 'controller.main',
    views: ['Calc.view.main.Main'],
    models: ['Main'],
    
    state: {
        operatorClicked: false,
        selectedOperator: null,
        dotClicked: false,
        op1: 0,
        numberClicked: false,
        sign: true,
        decimal: false
    },

    onClickClear: function () {
        
        var vm = this.getViewModel();
        vm.set('display','0');
        this.state.selectedOperator=null;
        this.state.op1=0;
        this.state.isPositive = true;
        this.state.decimal = false;
        this.state.sign = true;
    },

    onClickChangeSign: function (btn) {
        
        var vm = this.getViewModel();
        var cur = vm.get('display');
        if(cur!='0') {
            if(this.state.sign===true ) {
                vm.set('display', '-' + cur);
            }
            else {
                vm.set('display', cur.toString().substring(1));
            }
        }
        this.state.sign=!this.state.sign;  
    },

    onClickOp: function (btn) {
        
        if(this.state.selectedOperator!=null && this.state.numberClicked===true)
        {
            var vm = this.getViewModel();
            var op2 = parseFloat(vm.get('display'));
            var op1 = parseFloat(this.state.op1);
            var result = 0;
            
            switch(this.state.selectedOperator){
                    case '+':
                    result = op1 + op2;
                    break;
                    
                    case '-':
                    result = op1 - op2;
                    break;
                    
                    case '&times;':
                    result = op1 * op2;
                    break;
                    
                    case '&divide;':
                    result = op1 / op2;
                    break;
                    
                    
            }
            vm.set('display', Math.round(result * 100) / 100);
            this.state.selectedOperator=null;
        }
        if(btn.text!='=') {
            this.state.operatorClicked = true;  
        }
        this.state.selectedOperator = btn.text;
        this.state.numberClicked = false; 
    },

    onClickDot: function (btn) {
        if(this.state.decimal===false) {
            var vm = this.getViewModel();
            vm.set('display', vm.get('display') + '.');
        }
    },

    onClickNumber: function (btn) {
        
        this.state.numberClicked = true;
        if(this.state.selectedOperator ==='='){
            this.onClickClear();
        }
        
        var vm = this.getViewModel();
        if(this.state.operatorClicked===true) {
            this.state.op1= vm.get('display');
            vm.set('display', btn.text);
            this.state.operatorClicked=false;
        }
        else{
            var cur = vm.get('display');
            if(cur == '0') {
                cur = '';
            }
            vm.set('display', cur + btn.text);
        }

    }
});

MainModel.js

It contains the interface part of the application, which shows up to the user. Ext JS uses various UI-rich views, which can be extended and customized here according to the requirement.

Create a file app/view/main/MainModel.js and add the following code to it:


/**
 * This class is the view model for the Main view of the application.
 */
Ext.define('Calc.view.main.MainModel', {
    extend: 'Ext.app.ViewModel',

    alias: 'viewmodel.main',

    data: {
        display: 0.0
    }
});

app.css

Create a file resources/app.css and add the following code to it:
.btn:hover {
    background-color: #C7C7C7 !important;
}

.btn-orange:hover {
    background-color: #D07B32 !important;
}

.btn-green:hover {
    background-color: #A1C9AC !important;
}

.btn,
.btn.x-btn-focus.x-btn-default-small {
    background-color: #E0E0E0;
}

.btn-orange,
.btn-orange.x-btn-focus.x-btn-default-small {
    background-color: #F5923E;
}

.btn-green,
.btn-green.x-btn-focus.x-btn-default-small {
    background-color: #AFDCBB;
}

.x-btn-focus.x-btn-default-small,
.x-btn-focus.x-btn-over.x-btn-default-small {
    box-shadow: none;
}

.btn-orange span,
.display div {
    color: #FFFFFF !important;
}

.display {
    background-color: #69787F;
    padding: 0px !important;
}

.btn span,
.btn-orange span,
.btn-green span {
    font-size: 20px;
    line-height: 22px;
    color: #000000;
}

.btn-orange,
.btn,
.display,
.btn-green {
    border-radius: 0;
    border-color: #89898C;
    border-width: 0.5px;
}

.display div {
    font-size: 26px;
    line-height: 32px;
    text-align: right;
    padding-right: 5px;
    padding-top: 10px;
}

td div {
    margin-bottom: 0px !important;
}

.x-window-header-default-top {
    padding: 0px !important;
    top: 0px !important;
    left: 0px !important;
}

Run ExtJS App

Open the index.html file in the browser to access this application.


Comments