Ext JS 4 App with Express.js, Node.js and MongoDB on the backend

Ext JS 4 App with Express.js, Node.js and MongoDB on the backend

Hi, in this article I will show you how you can use JavaScript solutions from the title with your application. I would also like to show you how Ext JS 4 applications are flexible and how we can simply change the backend processes. In previous posts I used Zend Framework and Doctrine (MySQL) on the backend but for this example I will use only JavaScript solutions and I got Ext JS4 application code from this post:

Autocomplete combobox filter for Ext JS 4 Grid (CRUD functionality)

I only made small changes, I removed filter from the grid, I just show you simple CRUD functionality with the grid records.

1. Application structure

The app files look like the following list:

1-extjs4-nodejs-mongodb

I separated client side logic from server side logic in reusable way using MVC.

a) application directory contains server side logic: controllers, models and simple router which is responsible for setting proper controller and action

b) node_modules directory contains Node.js modules specified and installed from packages.json file

c) public directory is available for client side

- my Ext JS 4 application files are in the javascripts app directory

- I put Ext JS 4 core files in the lib directory

d) views directory contains simple jade template files

Dependencies:

{
  "name": "devjs-app",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "express": "3.4.0",
    "jade": "*",
    "mongoose": ">= 2.6.5"
  }
}

a) Express.js – it’s minimal and flexible web app framework for Node.js, it helped me build the interface of my Ext JS 4 App on client side

b) Jade template syntax – it’s a rich template engine for Node.js. I used simple layout and index to generate Ext JS 4 viewport

c) Mongoose - extends the native MongoDB drivers and also support serial and parallel requests in Node.js asynchronous environment. I mapped my Ext JS4 models on server side

2. Proxy for Model

To make it work I had to change store proxy settings. In this example I will show you how you can use Model proxy and Representational State Transfer (REST).

Ext JS4 supports REST connection types, so you can simply add to proxy object those lines:

public/javascripts/app/model/User.js

Ext.define('DevJS.model.User', {
    extend: 'Ext.data.Model',

    proxy: {
        type: 'rest',
        url : '/users',
        reader: {
            type: 'json',
            root: 'User'
        }
    },

    fields: [
        {
            name: 'login'
        },
        {
            name: 'firstName'
        },
        {
            name: 'lastName'
        },
        {
            name: 'email'
        },
        {
            name: '_id',
            defaultValue: null
        }
    ]
});

You set only one url and that’s it. Ext JS 4 Model will use automatically those REST operations:

a) get - Read

b) post - Create

c) put - Update

d) delete - Destroy

And you can fetch them on server side:

 //read
 app.get('/users', user.read);
 //create
 app.post('/users', user.add);
 //update
 app.put('/users', user.update);
 //remove
 app.delete('/users', user.destroy);

More info available at the end of this post.

3. Database

MongoDB is friendly to developers coming from SQL background (like me). In this example I used Mongoose which provides a straight-forward, schema-based solution to modelling your application data.

application/model/user.js

module.exports = function (mongoose) {

    var UserSchema = new mongoose.Schema({
        email: { type: String, unique: true },
        password: { type: String },
        firstName: {type: String},
        lastName: {type: String},
        login: {type: String, unique: true }
    });

    var User = mongoose.model('User', UserSchema);

    //put custom methods here

    return {
        User: User
    }
}

Just a few records:

2-extjs4-nodejs-mongodb

4. CRUD methods

Implementation of CRUD methods is located on server side:

application/controller/user.js

/**
 * This method read records
 *
 * @param req
 * @param res
 */
exports.read = function (req, res) {
    var params = req.body;

    exports.model.User.find({}, function (err, records) {
        res.send({success: true, User: records});
    });
};

/**
 * This method create records
 *
 * @param req
 * @param res
 */
exports.add = function (req, res) {
    var params = req.body,
        item;

    item = new exports.model.User(params);

    item.save(function(err) {
        if(!err) {
            res.send({success: true, User: item});
        }
        else {
            res.send({success: false, User: item});
        }
    });
};

/**
 * This method update records
 *
 * @param req
 * @param res
 */
exports.update = function (req, res) {
    var params = req.body, id = params._id;

    //remove id from values to update
    delete params._id;

    exports.model.User.update({"_id": id},{ $set : params}, {upsert:false}, function (err) {
        if(!err) {
            res.send({success: true});
        }
        else {
            res.send({success: false});
        }
    });
};

/**
 * This method remove records
 *
 * @param req
 * @param res
 */
exports.destroy = function (req, res) {
    var params = req.body;

    exports.model.User.remove({"_id": params._id}, function (err) {
        if(!err) {
            res.send({success: true});
        }
        else {
            res.send({success: false});
        }
    });
};

5. How it works?

a) the main server file app.js

app.js

/**
 * Module dependencies.
 */

var express = require('express');
var router = require('./application/router');
var http = require('http');
var path = require('path');
var dbPath = 'mongodb://localhost/devjs';

// import the data layer
var mongoose = require('mongoose');
// import the models
var models = {
    User: require('./application/model/user')(mongoose)
};

var app = express();

// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));

//db connection
mongoose.connect(dbPath, function onMongooseError(err) {
    if (err) throw err;
});

//router
router.init(app, models);

app.listen(8080);
console.log('Listening on port 8080');

The app.js file initialize server, database connection and set view. At the end we can see router init function which I described in the next point.

b) the second main file router.js

application/router.js

/**
 * Its only static background,
 * in real world everything goes automatically
 *
 * @param app
 * @param models
 */
exports.init = function(app, models)
{
    var index = require('./controller');
    var user = require('./controller/user');

    /* set models */
    user.model = models.User;

    /* set controllers */
    app.get('/', index.index);

    //read
    app.get('/users', user.read);
    //create
    app.post('/users', user.add);
    //update
    app.put('/users', user.update);
    //remove
    app.delete('/users', user.destroy);
}

The router.js file sets models for controllers and actions to proper places.

c) layout

views/layout.jade

doctype 5
html
  head
    title= title
    link(rel='stylesheet', href='/stylesheets/bootstrap.css')
    link(rel='stylesheet', href='/stylesheets/css/ext.custom.css')
    script(type='text/javascript', src='/javascripts/lib/ext/ext-all-dev.js')
    script(type='text/javascript', src='/javascripts/bootstrap.js')
    script(type='text/javascript', src='/javascripts/app/app.js')
  body
    block content

The layout.jade sets scripts files for app and opens the index content.

d) index


extends layout

The index.jade generates Ext JS 4 viewport.

6. The final result

Users grid view:

4-extjs4-nodejs-mongodb

Server communication logs:

3-extjs4-nodejs-mongodb

As you can see the Ext JS4 Model REST proxy is working properly.

7. Conclusion

It’s just a simple example of implementation but client side logic is separated from server side logic in reusable way using MVC. In my opinion Ext JS4 is really awesome and I like write code using this framework and Node.js was designed around events and callbacks so it’s exiting to see them both in action. It gives me great fun. In the one of my next posts I will show you implementation of Ext.Direct with Node.js. I will be happy if you find something, even a small part which inspire you or help you to understand something. Have fun and see you soon.

Source code: github

Comments:
md2k
Reply
02/01/2014 at 5:48 PM

Hi, can you share sources which was used for this topic?

Łukasz Sudoł To reply on comment
Reply
04/01/2014 at 11:18 PM

Hi, I created a new git repository based on the code used for this topic. You can find a link to repository at the bottom of an article. Please feel free to contact me if you have any further questions or concerns.

pkellner
Reply
21/06/2014 at 2:22 AM

could you mention what a “custom method” in the user class might look like (in the user.js file)

stepa
Reply
30/08/2014 at 1:58 PM

thank you so much. Downloaded from github, everything works.

Leave a Reply

Please fill all required fields


Drag circle to the rectangle on the right!

Send