Controller and Model Part
NodeAtlas is useful for more than simply generate template web page easily based on your variation files. NodeAtlas allow you to dynamicly interact with variations var and with the DOM with;
- parameters in query part of url (GET),
- parameters in request body (POST),
- connection with database or,
- management of sessions or,
- do AJAX or Websocket request/response and
- do more !
Lifecycle and Hooks
For that, you could hook to some point of life cycle of the page generation with common controller (commonController
) and with specific controller for each page (routes[<route>].controller
).
This is a webconfig.json
allows you to manipulate each part of life cycle of a page.
{
"controllersRelativePath": "controllers",
"commonController": "common.js",
"routes": {
"/": {
"template": "index.htm",
"variation": "index.json",
"controller": "index.json"
}
}
}
Note : If controllersRelativePath is not present in "webconfig.json", default controller folder is controllers. controllersRelativePath is useful only to change the name/path of directory.
and this is the detail of all hooks :
Start NodeAtlas
Init of Modules
- loadModules --> into
commonController
file (common.js
for example).Init of Sessions
- setSessions --> into
commonController
file (common.js
for example).Init of server configuration
- setConfigurations --> into
commonController
file (common.js
for example).Init of routes
- setRoutes --> à manipuler depuis le fichier
commonController
(common.js
dans l'exemple).Start Web Server
HTTP Request/Response of NodeAtlas
Client Request Processing
changeVariation --> into
commonController
file (common.js
for example).changeVariation --> into
routes[<route>].controller
file (index.js
for example).Templates and Variations Compilation => Complete DOM.
changeDom --> into
commonController
file (common.js
for example).changeDom --> into
routes[<route>].controller
file (index.js
for example).Sending of Response to Client
changeVariation
In order to intercept variations, you could use common controller for all the website page and/or also a specific controller per page.
This is an example using the two hooks, the common in first and after the specific:
{
"commonController": "common.js",
"commonVariation": "common.json",
"routes": {
"/": {
"template": "index.htm",
"variation": "index.json",
"controller": "index.js"
}
}
}
with this files :
├─ components/
│ ├─ head.htm
│ └─ foot.htm
├─ variations/
│ ├─ common.json
│ └─ index.json
├─ controllers/
│ ├─ common.js
│ └─ index.js
├─ templates/
│ └─ index.htm
└─ webconfig.json
Do a POST request on http://localhost/?title=Haeresis
with example=This+is+a+test
variable in body will use the following files:
variations/common.json
{
"titleWebsite": "Site Title"
}
variations/index.json
{
"titlePage": "Welcome",
"content": "<p>This is the Home Page.</p>"
}
templates/index.htm
<%- include('head.htm') %>
<div class="title"><%- common.titleWebsite %></div>
<div>
<h1><%- specific.titlePage %></h1>
<%- specific.content %>
</div>
<%- include('foot.htm') %>
controllers/common.js
// This code is executed before variation are injected into template engine.
// This code is executed for all HTTP request, for all pages.
exports.changeVariation = function (params, next) {
var variation = params.variation,
request = params.request,
response = params.response;
// Here we update variations variable.
console.log(variation.common.titleWebsite); // "Site Title"
console.log(variation.specific.titlePage); // "Welcome"
console.log(variation.specific.content); // "This is the Home Page."
if (request.query["title"]) {
variation.specific.titlePage = variation.specific.titlePage + " " + request.query.title;
}
if (request.body["example"]) {
variation.specific.content = request.body.example;
}
console.log(variation.common.titleWebsite); // "Site Title"
console.log(variation.specific.titlePage); // "Welcome Haeresis"
console.log(variation.specific.content); // "This is a test"
// We update modification here.
next(variation);
};
controllers/index.js
// This code is executed before variation are injected into template engine.
// This code is executed only for the « / » page .
exports.changeVariation = function (params, next) {
var variation = params.variation,
request = params.request,
response = params.response;
// Here we update variations variable.
console.log(variation.common.titleWebsite); // "Site Title"
console.log(variation.specific.titlePage); // "Welcome Haeresis"
console.log(variation.specific.content); // "This is a test"
variation.common.titleWebsite = "It's Home, no way.";
variation.specific.content = "It's Home, no way.";
console.log(variation.common.titleWebsite); // "It's Home, no way."
console.log(variation.specific.titlePage); // "Welcome Haeresis"
console.log(variation.specific.content); // "It's Home, no way."
// We update modification here.
next(variation);
};
en this produce the following output :
<!DOCTYPE html>
<html lang="fr-fr">
<head>
<meta charset="utf-8" />
<title>It's Home, no way.</title>
</head>
<body>
<div class="title">It's Home, no way.</div>
<div>
<h1>Welcome Haeresis</h1>
It's Home, no way.
</div>
</body>
</html>
If you delete the variation entry of specific page from webconfig:
{
"commonController": "common.js",
"commonVariation": "common.json",
"routes": {
"/": {
"template": "index.htm",
"variation": "index.json"
}
}
}
the output will be as following:
<!DOCTYPE html>
<html lang="fr-fr">
<head>
<meta charset="utf-8" />
<title>Site Title</title>
</head>
<body>
<div class="title">Site Title</div>
<div>
<h1>Welcome Haeresis</h1>
This is a test
</div>
</body>
</html>
changeDom
In order to intercept DOM before it was sent, you could use common controller for all the website page and/or also a specific controller per page.
This is an example using the two hooks, the common in first and after the specific:
{
"commonController": "common.js",
"commonVariation": "common.json",
"routes": {
"/": {
"template": "index.htm",
"variation": "index.json",
"controller": "index.js"
}
}
}
with this files :
├─ variations/
│ └─ index.json
├─ controllers/
│ ├─ common.js
│ └─ index.js
├─ templates/
│ └─ index.htm
└─ webconfig.json
Do a POST request on http://localhost/
will use the following files:
variations/common.json
{
"titleWebsite": "Site Title"
}
variations/index.json
{
"titlePage": "Welcome",
"content": "<p>This is Home Page.</p>"
}
templates/index.htm
<!DOCTYPE html>
<html lang="fr-fr">
<head>
<meta charset="utf-8" />
<title><%- common.titleWebsite %></title>
</head>
<body>
<div class="title"><%- common.titleWebsite %></div>
<div>
<h1><%- specific.titlePage %></h1>
<%- specific.content %>
</div>
</body>
</html>
controllers/common.js
// This code is executed before DOM was sent to Client.
// This code is executed for all HTTP request, for all pages.
exports.changeDom = function (params, next) {
var NA = this,
dom = params.dom,
request = params.request,
response = params.response,
cheerio = NA.modules.cheerio, // jsdom for manipulate DOM with jQuery.
$ = cheerio.load(dom, { decodeEntities: false }); // We load datas for manipulate it as a DOM.
// Just after eath h1 from HTML DOM...
$("h1").each(function () {
var $this = $(this);
// ...we create a div,
$this.after(
// ...we inject the content of h1 into the div,
$("<div>").html($this.html())
);
// ...and we delete the h1.
$this.remove();
});
// We create a new HTML output with updates.
dom = $.html();
// We update modification here.
next(dom);
};
controllers/index.js
// This code is executed before DOM was sent to Client.
// This code is executed only for the « / » page .
exports.changeDom = function (params, next) {
var NA = this,
dom = params.dom,
request = params.request,
response = params.response,
cheerio = NA.modules.cheerio, // jsdom for manipulate DOM with jQuery.
$ = cheerio.load(dom, { decodeEntities: false }); // We load datas for manipulate it as a DOM.
// We update nodes contents with `.title` class.
$(".title").text("Content Update");
// We create a new HTML output with updates.
dom = $.html();
// We update modification here.
next(dom);
};
the output will be as following:
<!DOCTYPE html>
<html lang="fr-fr">
<head>
<meta charset="utf-8">
<title>Site Title</title>
</head>
<body>
<div class="title">Content Update</div>
<div>
<div>Welcome</div>
<p>This is Home Page.</p>
</div>
</body>
</html>
loadModules
To load others modules which not include into NodeAtlas, you can use the common controller for all the website in order to load it once and use modules anywhere in all controllers.
This is an exemple using an external module of NodeAtlas:
{
"commonController": "common.js",
"routes": {
"/": {
"template": "index.htm",
"controller": "index.js"
}
}
}
with this set of files:
├─ controllers/
│ ├─ common.js
│ └─ index.js
├─ templates/
│ └─ index.htm
└─ webconfig.json
Do a POST request on http://localhost/
will use the following files:
templates/index.htm
<!DOCTYPE html>
<html lang="fr-fr">
<head>
<meta charset="utf-8" />
<title>Test Module</title>
</head>
<body>
<div class="title">Test Module</div>
<div>
<h1>Test Module</h1>
<%- example %>
</div>
</body>
</html>
controllers/common.js
// This code is executing during the modules loading phase.
// This code will be executed when NodeAtlas starting.
exports.loadModules = function () {
// Use the « NodeAtlas » instance from engine.
var NA = this;
// Associate each modules to allow us to use them anywhare.
NA.modules.marked = require('marked');
};
controllers/index.js
// This code is executed before variation are injected into template engine.
// This code is executed only for the « / » page .
exports.changeVariation = function (params, next) {
// Use the « NodeAtlas » instance from engine.
var NA = this,
variation = params.variation,
marked = NA.modules.marked;
variation.example = marked("I am using __markdown__.");
// We update modification here.
next(variation);
};
this will produce the following output:
<!DOCTYPE html>
<html lang="fr-fr">
<head>
<meta charset="utf-8" />
<title>Test Module</title>
</head>
<body>
<div class="title">Test Module</div>
<div>
<h1>Test Module</h1>
<p>I am using <strong>markdown</strong>.</p>
</div>
</body>
</html>
setConfigurations
To configure NodeAtlas web server others (ExpressJs), you can use the common controller for all the website in order to load it once and use modules anywhere in all controllers.
This is an exemple using a middleware for ExpressJs:
{
"commonController": "common.js",
"routes": {
"/": {
"template": "index.htm",
"controller": "index.js"
}
}
}
with this set of files:
├─ controllers/
│ └─ common.js
├─ templates/
│ └─ index.htm
└─ webconfig.json
Do a POST request on http://localhost/
will use the following files:
templates/index.htm
<%- content %>
controllers/common.js
// This code is executing before starting of the web server.
// This code will be executed when NodeAtlas starting.
exports.setConfigurations = function (next) {
// Use the « NodeAtlas » instance from engine.
var NA = this;
// Middleware utilisé lors de chaque requête.
NA.httpServer.use(function (request, response, next) {
response.setHeader("X-Frame-Options", "ALLOW-FROM https://www.lesieur.name/");
next();
});
// We update modification here.
next();
};
controllers/index.js
// This code is executing before starting of the web server.
// This code is executed only for the « / » page .
exports.changeVariation = function (params, next) {
var variation = params.variation;
// We prepare file for JSON displaying.
variation.currentRouteParameters.headers = {
"Content-Type": "application/json; charset=utf-8"
};
variation.content = JSON.stringify(variation, null, " ");
// We update modification here.
next(variation);
};
this will produce the following output:
{
"urlBasePathSlice": "http://localhost",
"urlBasePath": "http://localhost/",
"urlPath": "http://localhost/",
"pathname": /* ... */,
"filename": /* ... */,
"params": {},
"currentRouteParameters": { /* ... */ },
"currentRoute": "/",
"webconfig": { /* ... */ }
}
setSessions
To configure client-server Sessions of NodeAtlas, you can use the common controller for all the website in order to load it once and use modules anywhere in all controllers, this is an example with Redis sessions.
This is all files for example:
├─ controllers/
│ └─ common.js
├─ templates/
│ └─ index.htm
├─ variations/
│ ├─ common.json
│ └─ index.json
└─ webconfig.json
With the webconfig.json
:
{
"commonController": "common.js",
"commonVariation": "common.json",
"routes": {
"/": {
"template": "index.htm",
"variation": "index.json"
}
}
}
And "common.js" file containing e.g.:
// This code is executing during the modules loading phase.
// This code will be executed when NodeAtlas starting.
exports.loadModules = function () {
// Find instance of « NodeAtlas » engine.
var NA = this;
// Associations of each module to access it anywhere.
NA.modules.RedisStore = require('connect-redis');
};
// This code is executing while configuration of session.
// This code will be executed when NodeAtlas starting.
exports.setSessions = function (next) {
var NA = this,
session = NA.modules.session,
RedisStore = NA.modules.RedisStore(session);
// We replace the default session.
NA.sessionStore = new RedisStore();
// We update modification here.
next();
};
setRoutes
To configure routes of NodeAtlas by programmation, you can use the common controller for all the website in order to load it once and use modules anywhere in all controllers.
This is all files for example:
├─ controllers/
│ └─ common.js
├─ templates/
│ ├─ content.htm
│ └─ index.htm
├─ variations/
│ └─ common.json
└─ webconfig.json
With the webconfig.json
:
{
"commonController": "common.js",
"commonVariation": "common.json",
"routes": {
"/index.html": {
"template": "index.htm"
}
}
}
And "common.js" file containing e.g.:
// This code is executing while route are added.
// This code will be executed when NodeAtlas starting.
exports.setConfigurations = function (next) {
// We use instance of NodeAtlas.
var NA = this,
// And we keep routes from NodeAtlas webconfig...
route = NA.webconfig.routes;
// ...to add "/content.html" route amongs others routes.
route["/content.html"] = {
"template": "content.htm"
};
// We update modification here.
next();
};
Use Websocket instead of AJAX
To keep a link between Front and Back part of website, NodeAtlas can use Socket.IO (more details on official website).
Thanks to this, you could change in real time data on your page, but also change data from another tabs or browsers.
With this following files:
├─ assets/
│ └─ javascript/
│ ├─ common.js
│ └─ index.js
├─ components/
│ ├─ foot.htm
│ ├─ head.htm
│ └─ index.htm
├─ controllers/
│ ├─ common.js
│ └─ index.js
├─ variations/
│ ├─ common.json
│ └─ index.json
├─ templates/
│ └─ index.htm
└─ webconfig.json
With this webconfig.json
:
{
"commonController": "common.js",
"commonVariation": "common.json",
"routes": {
"/": {
"template": "index.htm",
"variation": "index.json",
"controller": "index.js"
}
}
}
and with this templates files:
components/head.htm
<!DOCTYPE html>
<html lang="<%= languageCode %>">
<head>
<meta charset="utf-8" />
<title><%- common.titleWebsite %></title>
</head>
<body data-hostname="<%= webconfig.urlWithoutFileName %>" data-subpath="<%= webconfig.urlRelativeSubPath.slice(1) %>" data-variation="<%= currentRouteParameters.variation.replace(/\.json/,'') %>">
Note : data-hostname
and data-subpath
will help us to set Socket.IO front configuration.
components/foot.htm
<script type="text/javascript" src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
<script src="javascript/common.js"></script>
</body>
</html>
Note : The Front file of Socket.IO is calling here.
components/index.htm
<div class="title"><%- common.titleWebsite %></div>
<div>
<h1><%- specific.titlePage %></h1>
<%- specific.content %>
<div><%- new Date() %></div>
</div>
<button>Update</button>
Note : Each click on button
will update content from components/index.htm
.
templates/index.htm
<%- include('head.htm') %>
<div class="layout">
<%- include('index.htm') %>
</div>
<script src="javascript/index.js"></script>
<%- include('foot.htm') %>
Note : We parse here the home page /
.
and the following variations files :
variations/common.json
{
"titleWebsite": "Socket.IO Example"
}
variations/index.json
{
"titlePage": "Date",
"content": "<p>Current date is:</p>"
}
All work fine here, but see what we will do with controller part on Server-side and on Client-side.
On server, we will use the following files:
controllers/common.js
var privates = {};
// Load modules for this site in the NodeAtlas object.
exports.loadModules = function () {
// Find instance of « NodeAtlas » engine.
var NA = this;
// Associations of each module to access it anywhere.
NA.modules.socketio = require('socket.io');
NA.modules.cookie = require('cookie');
};
// Example using Socket.IO.
privates.socketIoInitialisation = function (socketio, NA, next) {
var optionIo = (NA.webconfig.urlRelativeSubPath) ? { path: NA.webconfig.urlRelativeSubPath + '/socket.io', secure: ((NA.webconfig.httpSecure) ? true : false) } : undefined,
io = socketio(NA.server, optionIo),
cookie = NA.modules.cookie,
cookieParser = NA.modules.cookieParser;
// Synchronizing sessions with Socket.IO.
io.use(function(socket, next) {
var handshakeData = socket.request;
// Fallback if cookies are not supported.
if (!handshakeData.headers.cookie) {
return next(new Error('Session cookie required.'));
}
// Transformation of the cookie String to JSON object.
handshakeData.cookie = cookie.parse(handshakeData.headers.cookie);
// Verification of the signature of the cookie.
handshakeData.cookie = cookieParser.signedCookies(handshakeData.cookie, NA.webconfig.session.secret);
// Keep worn the Session ID.
handshakeData.sessionID = handshakeData.cookie[NA.webconfig.session.key];
// Accept the cookie.
NA.sessionStore.load(handshakeData.sessionID, function (error, session) {
if (error || !session) {
return next(new Error('No recovered session.'));
} else {
handshakeData.session = session;
next();
}
});
});
// Next.
next(io);
};
// Adding listener for a specific controller "index.js" (see example in the next file).
privates.socketIoEvents = function (io, NA) {
var params = {};
params.io = io;
// Event for the index page (see example in the next file).
require('./index').asynchrone.call(NA, params);
};
// Configuration of all modules.
exports.setConfigurations = function (next) {
var NA = this,
socketio = NA.modules.socketio;
// Initialize Socket IO.
privates.socketIoInitialisation(socketio, NA, function (io) {
// Socket IO listening.
privates.socketIoEvents(io, NA);
// Next steps of engine.
next();
});
};
Note : This is Socket.IO server global configuration.
controllers/index.js
// All Websocket action possible for this template.
// Used not by "NodeAtlas" but with "common.js" (see previous file).
exports.asynchrone = function (params) {
var NA = this,
io = params.io;
// Once we have a valid connection between the client and our back-end...
io.sockets.on('connection', function (socket) {
// ...stay tuned on the "create-item-button" demand...
socket.on("server-render", function (data) {
var sessionID = socket.request.sessionID,
session = socket.request.session,
variation = {};
// Specific variations in the good language.
variation = NA.addSpecificVariation("index.json", data.lang, variation);
// Common variations in the good language.
variation = NA.addCommonVariation(data.lang, variation);
// HTML part from `componentsRelativePath` directory and render with variations.
result = NA.newRender("index.htm", variation);
// And responds to all customers with a set of data in data.
io.sockets.emit('create-article-button', data);
});
});
};
And for client-side, we use the following files:
assets/javascript/common.js
window.website = window.website || {};
(function (publics) {
"use strict";
var privates = {},
optionsSocket,
body = document.getElementsByTagName("body")[0];
// We configure Socket.IO client-side.
optionsSocket = (body.getAttribute("data-subpath") !== "") ? { path: "/" + body.getAttribute("data-subpath") + ((body.getAttribute("data-subpath")) ? "/" : "") + "socket.io" } : undefined;
publics.socket = io.connect((body.getAttribute("data-subpath") !== "") ? body.getAttribute("data-hostname") : undefined, optionsSocket);
}(website));
// We execute specific JavaScript, here it's ["index"].
website[document.getElementsByTagName("body")[0].getAttribute("data-variation")].init();
Note : This is the global Socket.IO configuration client-side with data-subpath
and data-hostname
.
assets/javascript/index.js
window.website = window.website || {};
(function (publics) {
"use strict";
var html = document.getElementsByTagName("html")[0],
body = document.getElementsByTagName("body")[0],
layout = document.getElementsByClassName("layout")[0];
// We associate on the button the action to contact server.
function setServerRender() {
var button = document.getElementsByTagName("button")[0];
button.addEventListener("click", function () {
website.socket.emit("server-render", {
lang: html.getAttribute("lang"),
variation: body.getAttribute("data-variation")
});
});
}
// We create the code will be executed when page run.
publics.init = function () {
// We set action on button.
setServerRender();
// When server response come back...
website.socket.on("server-render", function (data) {
// ...we update data content...
layout.innerHTML = data.render;
// ...and we set again button action.
setServerRender();
});
};
}(website.index = {}));
Run your project and go on http://localhost/
across multiple tab and/or multiple browser. You will see when you click on « Update », the page (current date) will be updated on all tabs open.
Thanks to NA.addSpecificVariation
, NA.addCommonVariation
and NA.newRender
, it's possible to generate a new template and variation compilation.
If data.lang
in this example is type of undefined
, files will be search in rood directory. If currentVariation
is type of undefined
an empty object will be created.
Use MySQL Database (SQL)
We will see now how to use data from database. We will use the mysql
npm module. And first, install a MySQL server.
MySQL Database
First, we will create a database demo
on the server:
CREATE DATABASE demo;
and select it:
USE demo
and create a user
table:
CREATE TABLE user
(
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
lastname VARCHAR(100),
firstname VARCHAR(100),
email VARCHAR(255),
birthdate DATE,
gender TINYINT(1),
country VARCHAR(255),
town VARCHAR(255),
zipcode VARCHAR(5),
address VARCHAR(255)
);
and fill it with this set of data:
INSERT INTO user (
lastname,
firstname,
email,
birthdate,
gender,
country,
town,
zipcode,
address
) VALUES (
"Lesieur",
"Bruno",
"bruno.lesieur@gmail.com",
"1988/07/18",
true,
"France",
"Annecy",
74000,
"66 avenue de Genève"
);
NodeAtlas Files
With the following data set:
├─ assets/
│ └─ javascript/
│ └─ models/
│ └─ user.js
├─ controllers/
│ ├─ common.js
│ └─ index.js
├─ models/
│ └─ user.js
├─ templates/
│ └─ index.htm
├─ variations/
│ ├─ common.json
│ └─ index.json
└─ webconfig.json
We will use the following webconfig.json
with the custom _mysqlConfig
variable which contain all informations for database connection:
{
"commonController": "common.js",
"commonVariation": "common.json",
"routes": {
"/": {
"template": "index.htm",
"variation": "index.json",
"controller": "index.js"
}
},
"_mysqlConfig": {
"host": "localhost",
"user": "root",
"password": "root",
"database": "demo"
}
}
With following files to display page:
templates/index.htm
<!DOCTYPE html>
<html lang="<%- languageCode %>">
<head>
<meta charset="utf-8" />
<title><%- common.titleWebsite %></title>
</head>
<body>
<div class="title"><%- common.titleWebsite %></div>
<div>
<h1><%- specific.titlePage %></h1>
<%- specific.content %>
<ul>
<li>Id: <strong><%- id %></strong></li>
<li>Lastname: <strong><%- lastname %></strong></li>
<li>Firstname: <strong><%- firstname %></strong></li>
<li>Email: <strong><%- email %></strong></li>
<li>Birthdate: <strong><%- birthdate %></strong></li>
<li>Gender: <strong><%- gender %></strong></li>
<li>Country: <strong><%- country %></strong></li>
<li>Town: <strong><%- town %></strong></li>
<li>Zipcode: <strong><%- zipcode %></strong></li>
<li>Address: <strong><%- address %></strong></li>
</ul>
</div>
</body>
</html>
variations/common.json
{
"titleWebsite": "Example MySql",
"male": "Man",
"female": "Woman"
}
variations/index.json
{
"titlePage": "User Table",
"content": "<p>`bruno` entry details.</p>"
}
And last, we will be connect to the database with the common controller controllers/common.js
:
exports.loadModules = function () {
var NA = this;
NA.modules.mysql = require('mysql');
NA.models = {};
NA.models.User = require('../models/user.js');
};
exports.setConfigurations = function (next) {
var NA = this,
mysql = NA.modules.mysql;
NA.mySql = mysql.createPool(NA.webconfig._mysqlConfig);
next();
};
And display result via specific controller controllers/index.js
:
exports.changeVariation = function (params, next) {
var NA = this,
variation = params.variation,
User = NA.models.User,
bruno = User();
NA.mySql.getConnection(function(err, connection) {
if (err) {
console.log(err);
return false;
}
bruno
.setConnection(connection)
.firstname("bruno")
.readFirst(function () {
variation.id = bruno.id();
variation.lastname = bruno.lastname();
variation.firstname = bruno.firstname();
variation.email = bruno.email();
variation.birthdate = bruno.birthdate();
variation.gender = (bruno.gender()) ? variation.common.male : variation.common.female;
variation.country = bruno.country();
variation.town = bruno.town();
variation.zipcode = bruno.zipcode();
variation.address = bruno.address();
next(variation);
});
});
};
with the user
model via connect file to database models/user.js
:
/* jslint esversion: 6 */
var user = require('../assets/javascript/models/user.js');
function User(connection) {
var privates = {},
publics = this;
privates.connection = connection;
if (!(publics instanceof User)) {
return new User();
}
publics.setConnection = function (connection) {
privates.connection = connection;
return publics;
};
user.call(publics);
publics.readFirst = function (callback) {
var select = `SELECT
id,
lastname,
firstname,
email,
birthdate,
gender,
country,
town,
zipcode,
address
FROM user`,
where = "",
limit = " LIMIT 0,1 ",
addWhere = " WHERE ";
if (publics.id()) { where += addWhere + "`id` = '" + publics.id().replace(/'/g, "''") + "'"; addWhere = ' && '; }
if (publics.lastname()) { where += addWhere + "`lastname` = '" + publics.lastname().replace(/'/g, "''") + "'"; addWhere = ' && '; }
if (publics.firstname()) { where += addWhere + "`firstname` = '" + publics.firstname().replace(/'/g, "''") + "'"; addWhere = ' && '; }
if (publics.email()) { where += addWhere + "`email` = '" + publics.email().replace(/'/g, "''") + "'"; addWhere = ' && '; }
if (publics.birthdate()) { where += addWhere + "`birthdate` = '" + publics.birthdate().replace(/'/g, "''") + "'"; addWhere = ' && '; }
if (publics.gender()) { where += addWhere + "`gender` = '" + publics.gender().replace(/'/g, "''") + "'"; addWhere = ' && '; }
if (publics.country()) { where += addWhere + "`country` = '" + publics.country().replace(/'/g, "''") + "'"; addWhere = ' && '; }
if (publics.town()) { where += addWhere + "`town` = '" + publics.town().replace(/'/g, "''") + "'"; addWhere = ' && '; }
if (publics.zipcode()) { where += addWhere + "`zipcode` = '" + publics.zipcode().replace(/'/g, "''") + "'"; addWhere = ' && '; }
if (publics.address()) { where += addWhere + "`address` = '" + publics.address().replace(/'/g, "''") + "'"; addWhere = ' && '; }
privates.connection.query(select + where + limit, function(err, rows, fields) {
if (err) console.log(err);
if (rows[0]) {
publics.id(rows[0].id);
publics.lastname(rows[0].lastname);
publics.firstname(rows[0].firstname);
publics.email(rows[0].email);
publics.birthdate(rows[0].birthdate);
publics.gender((rows[0].gender) ? true : false);
publics.country(rows[0].country);
publics.town(rows[0].town);
publics.zipcode(rows[0].zipcode);
publics.address(rows[0].address);
}
callback();
});
};
}
User.prototype = Object.create(user.prototype);
User.prototype.constructor = User;
module.exports = User;
based on user
classe shared between Front and Back part assets/javascript/models/user.js
:
(function (expose, factory) {
if (typeof module !== 'undefined' && module.exports) {
module.exports = factory;
} else {
expose.User = factory;
}
}(this, function User() {
var privates = {},
publics = this;
if (!(publics instanceof User)) {
return new User();
}
publics.id = function (id) {
if (typeof id === 'undefined') {
return privates.id;
} else {
privates.id = id;
return publics;
}
};
publics.lastname = function (lastname) {
if (typeof lastname === 'undefined') {
return privates.lastname;
} else {
privates.lastname = lastname;
return publics;
}
};
publics.firstname = function (firstname) {
if (typeof firstname === 'undefined') {
return privates.firstname;
} else {
privates.firstname = firstname;
return publics;
}
};
publics.email = function (email) {
if (typeof email === 'undefined') {
return privates.email;
} else {
privates.email = email;
return publics;
}
};
publics.birthdate = function (birthdate) {
if (typeof birthdate === 'undefined') {
return privates.birthdate;
} else {
privates.birthdate = birthdate;
return publics;
}
};
publics.gender = function (gender) {
if (typeof gender === 'undefined') {
return privates.gender;
} else {
privates.gender = gender;
return publics;
}
};
publics.country = function (country) {
if (typeof country === 'undefined') {
return privates.country;
} else {
privates.country = country;
return publics;
}
};
publics.town = function (town) {
if (typeof town === 'undefined') {
return privates.town;
} else {
privates.town = town;
return publics;
}
};
publics.zipcode = function (zipcode) {
if (typeof zipcode === 'undefined') {
return privates.zipcode;
} else {
privates.zipcode = zipcode;
return publics;
}
};
publics.address = function (address) {
if (typeof address === 'undefined') {
return privates.address;
} else {
privates.address = address;
return publics;
}
};
}));
You will get the following output:
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8" />
<title>MySql Example</title>
</head>
<body>
<div class="title">MySql Example</div>
<div>
<h1>User Table</h1>
<p>`bruno` entry details.</p>
<ul>
<li>Id: <strong>1</strong></li>
<li>Lastname: <strong>Lesieur</strong></li>
<li>Firstname: <strong>Bruno</strong></li>
<li>Email: <strong>bruno.lesieur@gmail.com</strong></li>
<li>Birthdate: <strong>Mon Jul 18 1988 00:00:00 GMT+0200 (Paris, Madrid (heure d’été))</strong></li>
<li>Gender: <strong>Homme</strong></li>
<li>Country: <strong>France</strong></li>
<li>Town: <strong>Annecy</strong></li>
<li>Zipcode: <strong>74000</strong></li>
<li>Address: <strong>66 avenue de Genève</strong></li>
</ul>
</div>
</body>
</html>
Use MongoDB Database (NoSQL)
We will see now how to use data from nosql database. We will use the mongoose
npm module. And first, install a MongoDB server.
MongoDB Database
First, we will create a database demo
on the server and select it:
use demo
and create a user
collection:
db.createCollection("user")
and fill it with this document:
db.user.insert({
email: "bruno.lesieur@gmail.com",
identity: {
lastname: "Lesieur",
firstname: "Bruno",
gender: true,
birthdate : new Date("1988/07/18")
},
location: {
country: "France",
town: "Annecy",
zipcode: "74000",
address: "66 avenue de Genève"
}
})
NodeAtlas Files
With the following data set:
├─ assets/
│ └─ javascript/
│ └─ models/
│ └─ user.js
├─ controllers/
│ ├─ common.js
│ └─ index.js
├─ templates/
│ └─ index.htm
├─ variations/
│ ├─ common.json
│ └─ index.json
└─ webconfig.json
We will use the following webconfig.json
with the custom _mongodbConfig
variable which contain all informations for database connection:
{
"commonController": "common.js",
"commonVariation": "common.json",
"routes": {
"/": {
"template": "index.htm",
"variation": "index.json",
"controller": "index.js"
}
},
"_mongodbConfig": {
"host": "localhost",
"port": "27017",
"database": "demo"
}
}
With following files to display page:
templates/index.htm
<!DOCTYPE html>
<html lang="<%- languageCode %>">
<head>
<meta charset="utf-8" />
<title><%- common.titleWebsite %></title>
</head>
<body>
<div class="title"><%- common.titleWebsite %></div>
<div>
<h1><%- specific.titlePage %></h1>
<%- specific.content %>
<ul>
<li>Id: <strong><%- id %></strong></li>
<li>Lastname: <strong><%- lastname %></strong></li>
<li>Firstname: <strong><%- firstname %></strong></li>
<li>Email: <strong><%- email %></strong></li>
<li>Birthdate: <strong><%- birthdate %></strong></li>
<li>Gender: <strong><%- gender %></strong></li>
<li>Country: <strong><%- country %></strong></li>
<li>Town: <strong><%- town %></strong></li>
<li>Zipcode: <strong><%- zipcode %></strong></li>
<li>Address: <strong><%- address %></strong></li>
</ul>
</div>
</body>
</html>
variations/common.json
{
"titleWebsite": "Example MongoDB",
"male": "Man",
"female": "Woman"
}
variations/index.json
{
"titlePage": "User Collection",
"content": "<p>Document `{ \"identity.firstname\": \"Bruno\" }` details.</p>"
}
And last, we will be connect to the database with the common controller controllers/common.js
:
exports.loadModules = function () {
var NA = this,
path = NA.modules.path;
NA.modules.mongoose = require('mongoose');
NA.models = {};
NA.models.User = require('../assets/javascript/models/user.js');
};
exports.setConfigurations = function (next) {
var NA = this,
mongoose = NA.modules.mongoose,
config = NA.webconfig._mongodbConfig;
mongoose.Promise = global.Promise;
mongoose.model("user", NA.models.User, "user");
mongoose.connect("mongodb://" + config.host + ":" + config.port + "/" + config.database, function (error) {
next();
});
};
And display result via specific controller controllers/index.js
:
exports.changeVariation = function (params, next) {
var NA = this,
variation = params.variation,
mongoose = NA.modules.mongoose,
User = mongoose.model('user');
User
.findOne({ "identity.firstname": "Bruno" })
.exec(function (err, bruno) {
variation.id = bruno._id;
variation.lastname = bruno.identity.lastname;
variation.firstname = bruno.identity.firstname;
variation.birthdate = bruno.identity.birthdate;
variation.email = bruno.email;
variation.gender = (bruno.identity.gender) ? variation.common.male : variation.common.female;
variation.country = bruno.location.country;
variation.town = bruno.location.town;
variation.zipcode = bruno.location.zipcode;
variation.address = bruno.location.address;
next(variation);
});
};
based on user
classe shared between Front and Back part assets/javascript/models/user.js
:
var mongoose;
if (typeof module !== 'undefined' && module.exports) {
mongoose = require('mongoose');
}
(function (expose, factory) {
if (mongoose) {
module.exports = factory;
} else {
expose.User = factory;
}
}(this, new mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
email: { type : String, match: /^\S+@\S+$/ },
identity: {
lastname: String,
firstname: String,
gender: Boolean,
birthdate : { type : Date, default : Date.now }
},
location: {
country: String,
town: String,
zipcode: String,
address: String
}
})));
You will get the following output:
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8" />
<title>MongoDB Example</title>
</head>
<body>
<div class="title">MongoDB Example</div>
<div>
<h1>User Collection</h1>
<p>Collection `{ "identity.firstname": "Bruno" }` details.</p>
<ul>
<li>Id: <strong>1</strong></li>
<li>Lastname: <strong>Lesieur</strong></li>
<li>Firstname: <strong>Bruno</strong></li>
<li>Email: <strong>bruno.lesieur@gmail.com</strong></li>
<li>Birthdate: <strong>Mon Jul 18 1988 00:00:00 GMT+0200 (Paris, Madrid (heure d’été))</strong></li>
<li>Gender: <strong>Homme</strong></li>
<li>Country: <strong>France</strong></li>
<li>Town: <strong>Annecy</strong></li>
<li>Zipcode: <strong>74000</strong></li>
<li>Address: <strong>66 avenue de Genève</strong></li>
</ul>
</div>
</body>
</html>