Welcome to nooljs (Beta)
Full stack JavaScript framework built using famous open sources libraries Nodejs, Angularjs, expressjs, and socket-io.
- Easy to build complex data driven JavaScript applications with minimum coding.
- Support multiple data connections suck as Ms-sql, MySQL, PostgreSQL, and Mondodb.
- Real time framework build top of Express-js and Socket-io
- The client side is powered by the Angularjs. The layout can be build using the Angularjs tags and elements.
- Modularized layout to simplify the complex web pages.
- Can be mixed both Express-js and Socket-io
Quick Start
- Install nooljs with npm
$ npm install nooljs -g
- Create new nooljs project by running command
$ nooljs
It will ask project name. enter the project name( example testprj). It will create new folder for the project and sample application.
- Go the new project folder
$ cd testproj
- Update the npm dependency packages
npm update
- Run the application
node app.js
Documentation
Folder Structure
- config -- Configuration folder
- layout - Contains all the layout files
- public -- Public files ( js, image)
- server -- All the server side JavaScript files
- servermethod -- Put all the server methods here
Layout
The Layout is heart of the nooljs project. Each page/module of the application can be defined as layout. It should be keep inside the layout folder.
<nl-template id="store-edit-template" nl-permission="store-edit" nl-parent="main-content" > </nl-template> <nl-server-script> </nl-server-script> <nl-client-script>
The layout file contains three parts :
- nl-template - HTML template for this module.
- nl-server-script - Sever side JavaScript code for this module
- nl-client-script - Client side JavaScript code for this module
nl-template
<nl-template id="store-edit-template" nl-permission="store-edit" nl-parent="main-content" > ... your html code for this template here ..... </nl-template>
Template load event (nl-load)
This nl-load event will be fired after loading the template (nl-template). This is client side event. This will be useful to set any default values to the template after loading the template into the page.<nl-template id="store-edit-template" nl-load="loadData" nl-permission="store-edit" nl-parent="main-content" > ... your html code for this template here ..... </nl-template>
<nl-client-script>
{
loadData:function ($scope)
{
console.log(" enter assignDefaultAccount function ");
if($scope.accounts && $scope.accounts.length > 0)
{
console.log(" enter assignDefaultAccount function assigen Account "+ $scope.accounts[0]);
$scope.$root.account = $scope.accounts[0];
}
}
}
</nl-client-script>
Getting data from database ( nl-db-data )
Getting the data from database/server and injecting into HTML template can be easily done without writing code or with minimum code. Nooljs will do all the magic of executing database query, passing the parameter between client and server, getting the result from server, and binding to the HTML template. It is designed to support any type of database or file system.
<ion-list nl-db-data="exec Nodejs_GetUserAccountWithStore {{user.UserId}}" nl-db-model="accounts" nl-client-post-data="assignDefaultAccount" nl-websocket ="false" > <ion-item ng-repeat="x in accounts" menu-close > <span nl-click-redirect="{'url':'store-edit-template' , 'params':{'AccountKey':'account.AccountKey', 'StoreId':'x.StoreId'}}" > {{x.StoreName}} </span> <button class="button button-clear" nl-click-redirect="{'url':'store-times' , 'params':{'AccountKey':'account.AccountKey', 'StoreId':'x.StoreId'}}" >Store time </button> <ion-item> </ion-list>
- nl-db-data : This contains the executing data query. The parameters are getting from Angularjs tag or scope. The connection for the database is defined in the default connection at the config section.
- nl-db-model : The result of the executing query will be stored into this Angularjs model. The data can access in the client side using Ajularjs scope.
- nl-client-post-data : The name of the client side of function which will be executed after result received in the client. This is optional attribute.
<nl-client-script>
{
assignDefaultAccount:function ($scope)
{
console.log(" enter assignDefaultAccount function ");
if($scope.accounts && $scope.accounts.length > 0)
{
console.log(" enter assignDefaultAccount function assigen Account "+ $scope.accounts[0]);
$scope.$root.account = $scope.accounts[0];
}
}
}
</nl-client-script>
Getting data from server (nl-server-data )
nl-server-data is similar to the nl-db-data, but it is advanced and flexible method to injecting the server side data into HTML template.
<ion-list nl-db-data="validateLogin" nl-db-model="accounts" nl-client-post-data="assignDefaultAccount" nl-websocket ="false" > <ion-item ng-repeat="x in accounts" menu-close > <span nl-click-redirect="{'url':'store-edit-template' , 'params':{'AccountKey':'account.AccountKey', 'StoreId':'x.StoreId'}}" > {{x.StoreName}} </span> <button class="button button-clear" nl-click-redirect="{'url':'store-times' , 'params':{'AccountKey':'account.AccountKey', 'StoreId':'x.StoreId'}}" > Store time </button> <ion-item> </ion-list>
- nl-server-data : This contains name of the server side function and it should be inside the "nl-server-script" tag.
- nl-db-model :The result of the executing query will be stored into this Angularjs model. The data can access in the client side using Ajularjs scope.
- nl-client-post-data : The name of the client side of function which will be executed after result received in the client. This is optional attribute.
<nl-server-script>
{
validateLogin:
{
model:"item",
server:function($scope)
{
// $scope contains all the input values and add return values in to the scope variable
// place server side code here
// return true if you want to execute db and post functions
//return false if you want to skip execution of rest of functions
return true;
},
db:
{
query:"procedure=usp_LoginUser;userName=VarChar(255):{{login.username}},password=VarChar(255):{{login.password}} ,
applicationName=VarChar:'StoreAdmin',clientIp=VarChar:'',userAgentString=VarChar:'' ",
resultType:"single"
}
post:function($scope)
{
// place post server side code here
// $scope contains all the result from "server" and db functions.
// you can modify "server" and "db" results here.
},
}
}
</nl-server-script>
Execution flow : server() --> db() --> post() -->nl-client-post-data ( client side)
Executing click event in the server side ( nl-server-click )
The nl-server-click attribute uses for the firing the click event at server side.
<button id="category-edit-save" nl-server-click ="saveCategory"
nl-redirect="{'url':'category-template', 'cond':'categorySaveResult.Status == 0', 'params':{'AccountKey':'account.AccountKey'}}" >
save
</button>
- nl-server-click - This will fire click event at server side function "saveCategory"
- nl-redirect - (Optional) This will fire after executing server side function. This is used for redirecting to different template.
<nl-server-script>
{
saveCategory:
{
model:"categorySaveResult",
db:
{
query:"exec [usp_SaveCategory] {{AccountKey}} , {{category.CategoryId}}, 'null', {{category.CategoryName}} ,
{{category.Description}} ",
resultType:"single"
}
}
}
</nl-server-script>
Execution flow : server() --> db() --> post() -->nl-client-post-data ( client side) --> nl-redirect
Executing click event at Database ( nl-db-click )
The nl-db-click is similar to the nl-server-click but you can directly specify database query.
<button id="category-edit-save"
nl-db-click =""exec [usp_SaveCategory] {{AccountKey}} ,
{{category.CategoryId}}, 'null', {{category.CategoryName}} , {{category.Description}} "
nl-redirect="{'url':'category-template', 'cond':'categorySaveResult.Status == 0', 'params':{'AccountKey':'account.AccountKey'}}" >
save
</button>
Redirect Event (nl-click-redirect)
<button nl-click-redirect="{'url':'category-template', 'params':{'AccountKey':'account.AccountKey'}}">Items</button<
Login Process at server (nl-server-login)
The nl-server-login attribute is used for the login process. It is similar to the nl-server-click.
<button nl-server-login="validateLogin"
nl-redirect="{'url':'main-template'}" id="login-submit">
Login
</button>
The UserId field should be defined in cofig/config.json file. if userId value is grater than zero then login is successful and direct to the new template given in nl-redirect attribute.
<nl-server-script>
{
validateLogin:
{
server:function($scope)
{
if(!$scope || !$scope.login || !$scope.login.username || !$scope.login.password )
{
$scope.$root._error = {code:"INVALID_USER", message:"Invalid user information."};
return false;
}
return true;
},
db:
{
query:"procedure=usp_LoginUser;userName=VarChar(255):{{login.username}},password=VarChar(255):{{login.password}} ,
applicationName=VarChar:'StoreAdmin',clientIp=VarChar:'',userAgentString=VarChar:'' ",
resultType:"single"
}
post:function($scope){
// code for the post longin
//return false for the failure
return true;
}
}
}
</nl-server-script>
Login using Database (nl-db-login)
The nl-db-login is similar to the nl-server-login, but the database query can be specify directly without creating server side functions.
<button nl-db-login="procedure=usp_LoginUser;userName=VarChar(255):{{login.username}},
password=VarChar(255):{{login.password}} ,applicationName=VarChar:'StoreAdmin',clientIp=VarChar:'',
userAgentString=VarChar:'' "
nl-redirect="{'url':'main-template'}" id="login-submit">
Login
</button>
Permission (nl-permission)
The nooljs uses permission based authorization. The nl-permission attribute contains the name of the permission. It should be defined start of the template file with nl-template attribute. If given user does not have permission for given name then this template won't be loaded into the client. If nl-permission is empty then this template is public template.
<nl-template id="main-template" nl-permission="main" nl-parent="top-content">
All the permissions for this application can be load from file or database. The config/config.json defines the connection to load all the permissions for this application.
Sample config/config.json file
{ "userid" : "UserId",
"sessionTimeoutMinutes":60,
"logout":"login",
"defaultConnection": "sqlConn",
"permission": {
"connection":"jsonFile",
"query" : "config/permision.json",
"errorMessage": " You do not have permission to view this session."
}
}
Sample permission.json file
[ { "userKey":"RoleName",
"userValue" :"Admin",
"permission" :"*"
},
{ "userKey": "RoleName",
"userValue" :"StoreUser",
"permission" :["main", "item", "category", "store","store-edit",
"item-edit", "category-edit", "store-times" , "store-times-edit"]
},
{ "userKey": "RoleName",
"userValue" :"StoreManager",
"permission" :["item", "category","store", "item-edit", "category-edit", "store-edit"]
}
]
- userKey - The userkey should be member name of the user object which returns from nl-db-login or nl-server-login
- userValue - The userValue should be member value for given userKey in the user object which returns from nl-db-login or nl-server-login
- permission - Allowed permissions for the given userKey and userVaqlue. * - allowed all the permissions.
Default template (nl-default-template)
<ion-content id="main-content" nl-default-template="store-template">
Switching between Express and Socket-io
The switching between Express and Socket-io is really easy using nooljs framework. Even you can easily mix both frameworks within application.
client.js( inside public/js/client.js )
var app = angular.module('myApp', ['nooljs', 'ionic']);
app.run(['nlUtil', function (nlUtil) {
nlUtil.useWebsocket(true);
}]);
Turn off or turn on socket-io for the given data/layout injection
<ion-list nl-db-data="exec Nodejs_GetUserAccountWithStore {{user.UserId}}" nl-db-model="accounts"
nl-client-post-data="assignDefaultAccount" nl-websocket ="false" >
Server Method
Executing the server method inside the any client side JavaScript function is really easy.
index.html
<body ng-controller="myController">this is test
<div id = "top-content" nl-default-template="login" nl-websocket ="false">
</div>
<input type="button" ng-click="onclick()" value="call server method" />
<div>{{serverResult}}</div>
</body>
client.js ( client side JavaScript)
app.controller("myController",['nlServerMethods', '$scope', function(nlServerMethods, $scope)
{
$scope.serverResult= "my result";
$scope.onclick= function(){
nlServerMethods.exec( "myMethods.myServerMethod1", "First", "parameter")
.then(function(data){
$scope.serverResult = "data :" + data.data + " , error :" + data.error;
})
.catch(function (err)
{
$scope.serverResult = " error :" + err;
});
};
}]);
Server method should be inside /ServerMethod folder (/ServerMethod/myMethods.js)
{
myServerMethod1:
{
"permission":"myServerMethod1",
"method":function( name, value){
return "hello - from method 1 " + name + " " + value;
}
},
myServerMethod2:
{
"permission":"myServerMethod2",
"method":function( name){
return "hello -- from method 2 " + name ;
}
}
}
Data Connection
The development of complex data driven application can be done easily using the nooljs framework. Nooljs is design to support all kinds of database. It is currently support Ms-sql, Mysql, Mongodb, Postgresql, and Json file. Other data bases will be supported very soon.
All the connection strings are defined in the config/connection.json file. The default connection for the application is defined in the config/config.json file.
Ms-sql
Thanks to Seriate for creating wonderful Microsoft SQL Server cross platform node module.
Using stored procedure:
" procedure=[usp_SaveStoreTime];StoreId=VarChar(50):{{StoreId}} ,StoreOperationTimeId=VarChar(50):{{StoreTime.StoreOperationTimeId}},IsDate=VarChar(50):{{StoreTime.IsDate}},IsSunday=VarChar(50):{{StoreTime.IsSunday}},IsMonday=VarChar(50):{{StoreTime.IsMonday}},IsTuesday=VarChar(50):{{StoreTime.IsTuesday}},IsWednesday=VarChar(50):{{StoreTime.IsWednesday}},IsThursday=VarChar(50):{{StoreTime.IsThursday}},IsFriday=VarChar(50):{{StoreTime.IsFriday}},IsSaturday=VarChar(50):{{StoreTime.IsSaturday}},Date=VarChar(50):{{StoreTime.Date}},OpeningTime=VarChar(50):{{StoreTime.OpeningTime}},CloseTime=VarChar(50):{{StoreTime.CloseTime}}"
Using query string :
"select * from stores where storeid =@StoreId and StoreOperationTimeId=@StoreOperationTimeId;StoreId=VarChar(50):{{StoreId}} ,StoreOperationTimeId=VarChar(50):{{StoreTime.StoreOperationTimeId}}"
Mysql
Thanks to mysql for creating wonderful Mysql cross platform node module.
<nl-template id="mysql-template" nl-parent="mysql-content">
<h1>my sql data</h1>
<ion-list nl-server-data="getData" >
<ion-item class="item" ng-repeat="x in models">
{{x.rowidx}} - {{x.name}} - {{x.description}}
</ion-item>
</ion-list>
</nl-template>
<nl-server-script>
{
getData:
{
model:"models",
db:
{
query:"select rowidx, name, description, isactive from demo.test where isactive =?;[0]",
connection:"mysqlConnection"
}
}
}
</nl-server-script>
Mongodb
Thanks to mongodb for creating wonderful Mongodb cross platform node module.
<nl-template id="mongodb-template" nl-parent="mongodb-content">
<h1>mondodb sql data</h1>
<ion-list nl-server-data="getData" >
<ion-item class="item" ng-repeat="x in models">
{{x.id}} - {{x.name}}
</ion-item>
</ion-list>
</nl-template>
<nl-server-script>
{
getData:
{
model:"models",
db:
{
query:"cols=test;fun=find;params={\"active\":1}",
connection:"mongodbConnection"
}
}
}
</nl-server-script>
Postgresql
Thanks to pg for creating wonderful Postgresql cross platform node module.
<nl-template id="postgresql-template" nl-parent="postgresql-content">
<h1>postgre sql data</h1>
<ion-list nl-server-data="getData" >
<ion-item class="item" ng-repeat="x in models">
{{x.id}} - {{x.name}}
</ion-item>
</ion-list>
</nl-template>
<nl-server-script>
{
getData:
{
model:"models",
db:
{
query:"select name, active, id from tblname where active =$1;[0]",
connection:"postgresqlConnection"
}
}
}
</nl-server-script>
Support or Contact
If you need any help or bug fixing, please contract to cgkrish@hotmail.com